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,提问作者김태윤
相关产品推荐
相关产品推荐

