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

Android蓝牙服务无法检测004C厂商ID的iOS设备问题咨询

问题描述

在Android应用中执行蓝牙扫描操作时,无法检测到厂商ID为004C的iOS设备。当将蓝牙设备的厂商ID设置为0000时可正常检测,但改为004C后则无法被发现。经测试,使用nrfConnect应用的无过滤选项能够检测到该厂商ID为004C的设备。

问题原因

iOS设备(尤其是iBeacon)的BLE广播属于厂商特定数据广播(苹果厂商ID为0x004C),Android默认的BLE扫描设置会因为匹配模式、回调类型等参数限制,无法捕获这类广播包;同时原代码未处理厂商特定数据的检测,也未将扫描到的设备存入scannedDevices集合,导致后续无法通过地址获取设备。

修改方案

需要调整扫描参数以确保捕获所有类型的BLE广播,同时添加厂商特定数据的检测逻辑,并完善设备存储:

1. 优化扫描参数配置

修改startScan()方法中的ScanSettings,启用全量回调、积极匹配模式,确保不遗漏广播包:

fun startScan() {
    if (ActivityCompat.checkSelfPermission(
            this,
            Manifest.permission.BLUETOOTH_SCAN
        ) != PackageManager.PERMISSION_GRANTED
    ) {
        Log.e("BluetoothService", "Bluetooth scan permission not granted")
        return
    }

    val scanSettings = ScanSettings.Builder()
        .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
        // 接收所有匹配的扫描结果,包括重复广播
        .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
        // 积极匹配模式,降低扫描过滤门槛
        .setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
        // 允许报告最大数量的广播包
        .setNumOfMatches(ScanSettings.MATCH_NUM_MAX_ADVERTISEMENT)
        // 实时返回扫描结果(无延迟)
        .setReportDelay(0)
        .build()

    // 无过滤扫描所有BLE设备
    bluetoothLeScanner?.startScan(null, scanSettings, leScanCallback)

    Log.d("BluetoothService", "Bluetooth scanning started")
}

2. 完善扫描结果处理逻辑

在leScanCallback的onScanResult中,添加厂商特定数据检测,并将设备存入scannedDevices集合:

private val leScanCallback = object : ScanCallback() {
    override fun onScanResult(callbackType: Int, result: ScanResult) {
        if (ActivityCompat.checkSelfPermission(
                applicationContext,
                Manifest.permission.BLUETOOTH_CONNECT
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            Log.e("BluetoothService", "Bluetooth connect permission not granted")
            return
        }

        super.onScanResult(callbackType, result)
        val device = result.device
        val rssi = result.rssi

        // 将扫描到的设备存入集合,避免重复
        scannedDevices[device.address] = device

        // 检测苹果厂商ID(0x004C)的设备
        result.scanRecord?.let { scanRecord ->
            val manufacturerData = scanRecord.manufacturerSpecificData
            if (manufacturerData.containsKey(0x004C)) {
                Log.d("BluetoothService", "Apple device detected: ${device.name ?: "Unknown"} - ${device.address}, RSSI: $rssi")
            }
        }

        // 通用设备日志与回调
        Log.d("BluetoothService", "Device found: ${device.name ?: "Unknown"} - ${device.address}, RSSI: $rssi")
        deviceCallback?.onDeviceFound(device, rssi)
    }

    override fun onScanFailed(errorCode: Int) {
        super.onScanFailed(errorCode)
        Log.e("BluetoothService", "Bluetooth scan failed with error code: $errorCode")
    }
}
修改后的完整代码
interface BluetoothDeviceCallback {
    fun onDeviceFound(device: BluetoothDevice, rssi: Int)
}
interface BluetoothConnectionCallback {
    fun onConnectionStateChanged(connected: Boolean)
}

class BluetoothService : Service() {

    private val binder = BluetoothBinder()
    private lateinit var bluetoothAdapter: BluetoothAdapter
    private val scannedDevices = mutableMapOf<String, BluetoothDevice>()
    private var bluetoothLeScanner: BluetoothLeScanner? = null
    private var bluetoothGatt: BluetoothGatt? = null
    private var deviceCallback: BluetoothDeviceCallback? = null
    private var connectionCallback: BluetoothConnectionCallback? = null

    fun getBluetoothDeviceByAddress(address: String): BluetoothDevice? {
        return scannedDevices[address]
    }

    override fun onCreate() {
        super.onCreate()
        val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
        bluetoothAdapter = bluetoothManager.adapter
        bluetoothLeScanner = bluetoothAdapter.bluetoothLeScanner

        startForegroundService()
    }

    fun setDeviceCallback(callback: BluetoothDeviceCallback) {
        this.deviceCallback = callback
    }

    fun setConnectionCallback(callback: BluetoothConnectionCallback) {
        this.connectionCallback = callback
    }

    private fun startForegroundService() {
        val channelId = "BluetoothServiceChannel"
        val channelName = "Bluetooth Service"
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT)
            val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            manager.createNotificationChannel(channel)
        }

        val notificationIntent = Intent(this, MainActivity::class.java)
        val pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE)

        val notification: Notification = NotificationCompat.Builder(this, channelId)
            .setContentTitle("Bluetooth Service")
            .setContentText("Bluetooth connection is active")
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            .setContentIntent(pendingIntent)
            .build()

        startForeground(1, notification)
    }

    fun startScan() {
        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.BLUETOOTH_SCAN
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            Log.e("BluetoothService", "Bluetooth scan permission not granted")
            return
        }

        val scanSettings = ScanSettings.Builder()
            .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
            .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
            .setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
            .setNumOfMatches(ScanSettings.MATCH_NUM_MAX_ADVERTISEMENT)
            .setReportDelay(0)
            .build()

        bluetoothLeScanner?.startScan(null, scanSettings, leScanCallback)

        Log.d("BluetoothService", "Bluetooth scanning started")
    }

    fun stopScan() {
        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.BLUETOOTH_SCAN
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            Log.e("BluetoothService", "Bluetooth scan permission not granted")
            return
        }

        bluetoothLeScanner?.stopScan(leScanCallback)
        Log.d("BluetoothService", "Bluetooth scanning stopped")
    }

    private val leScanCallback = object : ScanCallback() {
        override fun onScanResult(callbackType: Int, result: ScanResult) {
            if (ActivityCompat.checkSelfPermission(
                    applicationContext,
                    Manifest.permission.BLUETOOTH_CONNECT
                ) != PackageManager.PERMISSION_GRANTED
            ) {
                Log.e("BluetoothService", "Bluetooth connect permission not granted")
                return
            }

            super.onScanResult(callbackType, result)
            val device = result.device
            val rssi = result.rssi

            scannedDevices[device.address] = device

            result.scanRecord?.let { scanRecord ->
                val manufacturerData = scanRecord.manufacturerSpecificData
                if (manufacturerData.containsKey(0x004C)) {
                    Log.d("BluetoothService", "Apple device detected: ${device.name ?: "Unknown"} - ${device.address}, RSSI: $rssi")
                }
            }

            Log.d("BluetoothService", "Device found: ${device.name ?: "Unknown"} - ${device.address}, RSSI: $rssi")
            deviceCallback?.onDeviceFound(device, rssi)
        }

        override fun onScanFailed(errorCode: Int) {
            super.onScanFailed(errorCode)
            Log.e("BluetoothService", "Bluetooth scan failed with error code: $errorCode")
        }
    }

    fun connectToDevice(device: BluetoothDevice) {
        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.BLUETOOTH_CONNECT
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            Log.e("BluetoothService", "Bluetooth connect permission not granted")
            return
        }
        bluetoothGatt = device.connectGatt(this, false, gattCallback)
    }

    private val gattCallback = object : BluetoothGattCallback() {
        override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {
            super.onConnectionStateChange(gatt, status, newState)
            if (newState == BluetoothGatt.STATE_CONNECTED) {
                Log.d("BluetoothService", "Connected to GATT server.")
                if (ActivityCompat.checkSelfPermission(
                        applicationContext,
                        Manifest.permission.BLUETOOTH_CONNECT
                    ) != PackageManager.PERMISSION_GRANTED
                ) {
                    Log.e("BluetoothService", "Bluetooth connect permission not granted")
                    return
                }
                bluetoothGatt?.discoverServices()
                connectionCallback?.onConnectionStateChanged(true)
            } else if (newState == BluetoothGatt.STATE_DISCONNECTED) {
                Log.d("BluetoothService", "Disconnected from GATT server.")
                connectionCallback?.onConnectionStateChanged(false)
            }
        }

        // Other callback methods such as onServicesDiscovered, onCharacteristicRead, etc.
    }

    override fun onBind(intent: Intent?): IBinder {
        return binder
    }

    override fun onDestroy() {
        super.onDestroy()
        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.BLUETOOTH_CONNECT
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            Log.e("BluetoothService", "Bluetooth connect permission not granted")
            return
        }
        bluetoothGatt?.close()
    }

    inner class BluetoothBinder : Binder() {
        fun getService(): BluetoothService = this@BluetoothService
    }
}

内容的提问来源于stack exchange,提问作者김태윤

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 21:22:02