求Android 8.0+可用NFC蓝牙切换示例及API21-27开发方案
解决API21-27下NFC触发蓝牙连接的方案
兄弟,我之前在做类似需求的时候踩过不少坑,尤其是API21-27这个跨度里蓝牙权限和NFC交互的兼容问题,给你几个实际能用的方案,避开MAC地址无法获取的限制:
1. 用NFC传递蓝牙设备的自定义识别信息
既然MAC地址在高版本API里拿不到,咱们换个思路:通过NFC交换设备名称+自定义GATT服务UUID,让两台设备靠这两个信息完成识别和连接。
- 发送端(触碰时主动推送信息的设备):
在NFC触发的回调里,构造包含设备名称和自定义UUID的NdefRecord,比如格式写成BT_PAIR:MyDeviceX:123e4567-e89b-12d3-a456-426614174000,然后封装成NdefMessage通过Android Beam推送。 - 接收端:
在onNewIntent里解析收到的NdefMessage,拆分出设备名称和UUID,然后启动蓝牙扫描,过滤出对应名称的设备,再根据UUID连接指定的GATT服务。
2. 基于Android Beam的双向信息交换
API21-27都支持Android Beam,刚好可以用来做两台设备的蓝牙参数互传:
- 给两台设备都注册
NdefPushCallback,在onCreateNdefMessage方法里生成包含自身蓝牙服务信息的NdefMessage。 - 当两台设备触碰时,双方都会收到对方的蓝牙信息,之后各自启动蓝牙连接逻辑——比如A收到B的信息后发起连接,B收到A的信息后做好接收准备,这样就能实现触碰即触发连接的效果。
3. 避开MAC的蓝牙连接实现
彻底放弃依赖MAC地址,改用蓝牙名称+服务UUID来识别设备:
- 扫描阶段:用
BluetoothLeScanner添加ScanFilter,过滤包含目标UUID的设备,这样不用遍历所有扫描结果,效率更高。代码示例:BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (bluetoothAdapter != null && bluetoothAdapter.isEnabled()) { BluetoothLeScanner scanner = bluetoothAdapter.getBluetoothLeScanner(); List<ScanFilter> filters = new ArrayList<>(); ParcelUuid targetUuid = ParcelUuid.fromString("你的自定义服务UUID"); ScanFilter filter = new ScanFilter.Builder().setServiceUuid(targetUuid).build(); filters.add(filter); ScanSettings settings = new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) .build(); scanner.startScan(filters, settings, mScanCallback); } - 连接阶段:扫描到匹配的设备后,直接调用
connectGatt()建立连接,不需要MAC地址。
4. 权限兼容注意事项
这个区间的API权限差异要特别注意:
- API21-22:只需要在Manifest里声明
BLUETOOTH和BLUETOOTH_ADMIN权限,不需要位置权限。 - API23-27:除了蓝牙权限,还需要动态申请
ACCESS_COARSE_LOCATION或ACCESS_FINE_LOCATION权限,因为蓝牙扫描需要位置权限才能正常工作。
另外你提到的NFC Forum的SSBP文档确实已经过时了,因为高版本Android限制了MAC地址的获取,所以完全不用纠结那个方案,上面的思路都是针对当前权限规则调整后的可行方案。
内容的提问来源于stack exchange,提问作者HumanBean
相关产品推荐
相关产品推荐

