Python蓝牙应用需实现后台/关闭/重启后持续运行的技术求助
要实现蓝牙接收在后台、应用关闭甚至开机自启的需求,你需要用Android的前台服务(Foreground Service)配合开机广播接收器,结合Buildozer的正确配置。以下是具体步骤:
一、Buildozer 配置修改(
buildozer.spec) 需要添加权限、声明服务和开机自启相关配置:
- 权限部分(覆盖安卓全版本蓝牙需求):
android.permissions = BLUETOOTH, BLUETOOTH_ADMIN, ACCESS_FINE_LOCATION, FOREGROUND_SERVICE, RECEIVE_BOOT_COMPLETED, BLUETOOTH_SCAN, BLUETOOTH_CONNECT
注:BLUETOOTH_SCAN和BLUETOOTH_CONNECT是安卓12及以上版本强制要求的蓝牙拆分权限。
- 声明后台服务:
android.services = src/bluetooth_service.py:BluetoothReceiverService
这里src/bluetooth_service.py是你的服务代码文件路径,BluetoothReceiverService是自定义的服务类名。
- 开机自启相关配置:
android.add_activiti_flags = android.intent.FLAG_ACTIVITY_NEW_TASK android.add_java = src/BootReceiver.java
二、Python 后台服务代码实现
创建src/bluetooth_service.py,编写独立的蓝牙接收服务逻辑(核心运行在后台,不受主应用生命周期影响):
from android import service from android.permissions import request_permissions, Permission from jnius import autoclass, PythonJavaClass, java_method # 初始化安卓系统类 Intent = autoclass('android.content.Intent') PendingIntent = autoclass('android.app.PendingIntent') NotificationChannel = autoclass('android.app.NotificationChannel') NotificationCompat = autoclass('androidx.core.app.NotificationCompat') Context = autoclass('android.content.Context') class BluetoothReceiverService(service.Service): def __init__(self): super().__init__() self.running = False self.bluetooth_socket = None # 替换为你的蓝牙连接实例 def onStartCommand(self, intent, flags, startId): # 请求蓝牙相关权限 request_permissions([ Permission.BLUETOOTH, Permission.BLUETOOTH_ADMIN, Permission.ACCESS_FINE_LOCATION, Permission.BLUETOOTH_SCAN, Permission.BLUETOOTH_CONNECT ]) # 创建前台通知(安卓8+强制要求,否则服务会被系统立即杀死) self.create_notification_channel() notification = self.build_notification() self.startForeground(1, notification) # 启动蓝牙接收循环 self.running = True self.start_bluetooth_listen() # 返回START_STICKY,确保服务被系统回收后自动重启 return service.START_STICKY def create_notification_channel(self): nm = self.getSystemService(Context.NOTIFICATION_SERVICE) channel = NotificationChannel("bluetooth_service", "蓝牙接收服务", 3) # 3代表高优先级通知 nm.createNotificationChannel(channel) def build_notification(self): # 点击通知可打开主应用 intent = Intent(self, autoclass('org.kivy.android.PythonActivity')) pending_intent = PendingIntent.getActivity(self, 0, intent, 0x10000000) # FLAG_IMMUTABLE builder = NotificationCompat.Builder(self, "bluetooth_service") builder.setContentTitle("蓝牙接收服务") builder.setContentText("正在后台接收数据") builder.setSmallIcon(autoclass('org.kivy.android.R$drawable').icon) builder.setContentIntent(pending_intent) return builder.build() def start_bluetooth_listen(self): # 替换为你的实际蓝牙接收逻辑 # 示例伪代码: # self.bluetooth_socket = 你的蓝牙连接初始化代码 # while self.running: # data = self.bluetooth_socket.recv(1024) # if data: # 处理数据(如写入本地存储、发送广播通知主应用等) pass def onDestroy(self): self.running = False if self.bluetooth_socket: self.bluetooth_socket.close() super().onDestroy() # 开机自启广播接收器(Python实现) class BootReceiver(PythonJavaClass): __javainterfaces__ = ['android/content/BroadcastReceiver'] @java_method('(Landroid/content/Context;Landroid/content/Intent;)V') def onReceive(self, context, intent): if intent.getAction() == "android.intent.action.BOOT_COMPLETED": service_intent = Intent(context, BluetoothReceiverService) context.startForegroundService(service_intent)
三、主应用代码调整
主应用仅负责启动服务,无需再处理蓝牙接收逻辑:
from kivy.app import App from kivy.uix.label import Label from jnius import autoclass class MainApp(App): def build(self): self.start_bluetooth_service() return Label(text="蓝牙服务已启动") def start_bluetooth_service(self): Intent = autoclass('android.content.Intent') service_intent = Intent(self.android_activity, autoclass('your.package.name.BluetoothReceiverService')) # 安卓8+必须用startForegroundService启动前台服务 self.android_activity.startForegroundService(service_intent) def on_pause(self): # 主应用退后台时无需保留,服务独立运行 return True def on_stop(self): # 主应用关闭后,服务继续运行 return True if __name__ == '__main__': MainApp().run()
四、开机自启补充(Java接收器,可选)
如果Python广播接收器在部分ROM上不稳定,可创建src/BootReceiver.java:
package your.package.name; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; public class BootReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { Intent serviceIntent = new Intent(context, BluetoothReceiverService.class); context.startForegroundService(serviceIntent); } } }
同时在buildozer.spec添加:
android.add_manifest_receiver = true
关键注意事项
- 安卓8+后台服务必须以前台服务运行,必须显示通知,否则系统会强制停止服务。
START_STICKY返回值能让服务被系统杀死后自动重启,但资源紧张时仍可能被回收,可根据需求替换为START_REDELIVER_INTENT。- 部分国产ROM(小米、华为等)需要手动在应用设置中开启「自启动权限」,否则开机广播接收器不会触发。
- 蓝牙权限在安卓12+需要动态申请,且
BLUETOOTH_SCAN可添加neverForLocation标记(如果不需要位置关联)。
内容的提问来源于stack exchange,提问作者tahami
相关产品推荐
相关产品推荐

