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

AndroidTV开机自启BLE前台服务无法返回扫描结果问题

Android 10 AndroidTV 开机自启BLE扫描无结果问题

问题概述

搭载Android 10的AndroidTV设备上,应用的前台服务用于持续扫描指定MAC地址的BLE设备。从启动器启动应用时扫描正常,但设备重启后通过BOOT_COMPLETED广播启动服务时,即便BLE设备在范围内,扫描结果始终为空;后续打开应用重启扫描器后恢复正常。

相关代码

BLE扫描实现

import no.nordicsemi.android.support.v18.scanner.BluetoothLeScannerCompat
import no.nordicsemi.android.support.v18.scanner.ScanCallback
import no.nordicsemi.android.support.v18.scanner.ScanFilter
import no.nordicsemi.android.support.v18.scanner.ScanResult
import no.nordicsemi.android.support.v18.scanner.ScanSettings

fun scan() {
    BluetoothLeScannerCompat.getScanner()
        .startScan(
            /* MAC地址过滤规则 */ filters, 
            ScanSettings.Builder()
                .setLegacy(false)
                .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
                .setUseHardwareBatchingIfSupported(false)
                .setReportDelay(5000)
                .build(), 
            /* 扫描回调 */ callback
        )
}

启动器启动服务(MainActivity)

override fun onCreate(savedInstanceState: Bundle?) {
    // ... UI逻辑 ...

    startForegroundService(Intent(this, BleService::class.java))
}

开机广播接收器

class BootCompletedReceiver: BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        if (intent?.action == Intent.ACTION_BOOT_COMPLETED) {
            context?.startForegroundService(Intent(context, BleService::class.java))
        }
    }
}

日志信息

BluetoothAdapter        D  isLeEnabled(): ON
BluetoothLeScanner      D  onScannerRegistered() - status=0 scannerId=5 mScannerId=0
BluetoothScanJob        I  Start Scan
BluetoothS...b$callback I  [onBatchScanResults]: Results=[]

已确认事项

  • 两种启动方式下,服务均能正常初始化并启动扫描器,无报错
  • LogCat稳定输出onScannerRegistered()确认信息
  • BOOT_COMPLETED广播触发正常,无延迟或丢失
  • 服务启动与扫描初始化之间添加20秒延迟无效果
  • 是否设置reportDelay不影响扫描结果
  • 已配置所有必要的清单权限及运行时权限

清单文件内容

<manifest <!-- 省略其他配置 --> >

    <!-- 省略其他权限 -->

    <!-- SDK 30及以下蓝牙权限 -->
    <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" />

    <!-- SDK 30以上蓝牙权限 -->
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN"
        android:usesPermissionFlags="neverForLocation"
        tools:targetApi="31" />

    <!-- 前台服务权限 -->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE"/>

    <!-- 开机自启权限 -->
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    <!-- 强制要求BLE硬件支持 -->
    <uses-feature
        android:name="android.hardware.bluetooth_le"
        android:required="true"/>

    <application <!-- 省略其他配置 --> >

        <receiver
            android:name=".service.BootCompletedReceiver"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>

        <service
            android:name=".service.BleService"
            android:label="@string/service_name"
            android:description="@string/service_description"
            android:exported="false"
            android:foregroundServiceType="connectedDevice"/>

        <activity
            android:name=".ui.main.MainActivity"
            android:exported="true">

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <provider
            android:name="androidx.startup.InitializationProvider"
            android:authorities="${applicationId}.androidx-startup"
            tools:node="remove">
        </provider>

    </application>

</manifest>

解决方案尝试

1. 强制重置BLE适配器

Android 10 TV设备开机后,BLE可能处于“已启用”但底层未就绪状态。尝试重置BLE后再启动扫描:

val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
if (bluetoothAdapter.isLeEnabled) {
    bluetoothAdapter.disableLe()
    Handler(Looper.getMainLooper()).postDelayed({
        bluetoothAdapter.enableLe()
        Handler(Looper.getMainLooper()).postDelayed({
            scan()
        }, 2000)
    }, 1000)
} else {
    bluetoothAdapter.enableLe()
    Handler(Looper.getMainLooper()).postDelayed({
        scan()
    }, 2000)
}

2. 调整扫描模式

SCAN_MODE_LOW_LATENCY在开机初期系统资源紧张时可能无法正常工作,切换为平衡模式:

ScanSettings.Builder()
    .setLegacy(false)
    .setScanMode(ScanSettings.SCAN_MODE_BALANCED) // 修改扫描模式
    .setUseHardwareBatchingIfSupported(false)
    .setReportDelay(5000)
    .build()

3. 临时移除MAC过滤

开机后蓝牙底层可能无法正确处理MAC地址过滤规则,先扫描所有设备确认能获取结果后再添加过滤:

BluetoothLeScannerCompat.getScanner()
    .startScan(
        null, // 临时移除过滤规则
        scanSettings,
        callback
    )

4. 确保前台服务通知正确创建

Android 10要求前台服务必须在启动后5秒内显示通知,否则会被系统限制。在BleService的onStartCommand中确保调用startForeground():

private val CHANNEL_ID = "ble_scan_channel"
private val NOTIFICATION_ID = 1001

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    // 创建通知渠道(Android O及以上要求)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val channel = NotificationChannel(CHANNEL_ID, "BLE扫描服务", NotificationManager.IMPORTANCE_LOW)
        val notificationManager = getSystemService(NotificationManager::class.java)
        notificationManager.createNotificationChannel(channel)
    }
    // 构建前台通知
    val notification = NotificationCompat.Builder(this, CHANNEL_ID)
        .setContentTitle(getString(R.string.service_name))
        .setContentText(getString(R.string.service_description))
        .setSmallIcon(R.drawable.ic_notification)
        .build()
    // 启动前台服务
    startForeground(NOTIFICATION_ID, notification)
    // 初始化扫描
    scan()
    return START_STICKY
}

5. 监听蓝牙完全就绪状态

注册蓝牙状态广播,确保在蓝牙完全进入STATE_ON状态后再启动扫描:

class BleService : Service() {
    private val bluetoothStateReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            val state = intent?.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)
            if (state == BluetoothAdapter.STATE_ON) {
                // 蓝牙完全就绪,启动扫描
                scan()
                // 取消注册广播避免重复触发
                unregisterReceiver(this)
            }
        }
    }

    override fun onCreate() {
        super.onCreate()
        // 注册蓝牙状态监听广播
        val filter = IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)
        registerReceiver(bluetoothStateReceiver, filter)
    }

    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(bluetoothStateReceiver)
    }
}

内容的提问来源于stack exchange,提问作者Thijs

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 09:35:55