You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 05:25:54