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

无需配对跨iOS与Android获取周边蓝牙设备唯一标识方案咨询

跨平台无需配对获取蓝牙设备唯一标识方案

核心思路

由于iOS和Android在未配对状态下都无法直接获取蓝牙设备的MAC地址或GUID,可行的方案依赖BLE设备广播包中的公开数据,以下是两种跨平台兼容的思路:

  • 解析广播包中的厂商特定数据:绝大多数BLE设备会在广播时携带厂商自定义数据,你可以要求设备厂商将设备唯一标识(如序列号哈希、自定义ID)嵌入这部分数据中,无需配对即可读取,且跨平台支持稳定。
  • 提取广播名称中的唯一标识:如果设备的广播名称(Local Name)包含唯一标识(如Device-XXXXXX格式),可以直接解析名称字符串获取,但需注意广播名称可能被修改,稳定性略差。

iOS 代码示例(Swift)

import CoreBluetooth

class BLEScanHandler: NSObject, CBCentralManagerDelegate {
    private var centralManager: CBCentralManager!

    override init() {
        super.init()
        centralManager = CBCentralManager(delegate: self, queue: DispatchQueue.main)
    }

    // 蓝牙状态更新回调
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        guard central.state == .poweredOn else { return }
        // 开始扫描所有BLE设备,禁止重复扫描同一设备
        central.scanForPeripherals(withServices: nil, options: [CBCentralManagerScanOptionAllowDuplicatesKey: false])
    }

    // 发现设备回调
    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
        // 1. 解析广播名称中的唯一标识
        if let localName = advertisementData[CBAdvertisementDataLocalNameKey] as? String {
            print("设备名称: \(localName)")
            // 假设名称格式为"Device-123456",提取后缀作为ID
            localName.components(separatedBy: "-").last.map { print("唯一标识: \($0)") }
        }

        // 2. 解析厂商特定数据中的唯一标识
        if let manufacturerData = advertisementData[CBAdvertisementDataManufacturerDataKey] as? Data {
            // 前2字节为厂商ID,后续为自定义数据(需和设备厂商约定格式)
            guard manufacturerData.count > 2 else { return }
            let deviceIdData = manufacturerData.subdata(in: 2..<manufacturerData.count)
            String(data: deviceIdData, encoding: .utf8).map { print("厂商数据标识: \($0)") }
        }
    }
}

Android 代码示例(Kotlin)

import android.bluetooth.BluetoothAdapter
import android.bluetooth.le.BluetoothLeScanner
import android.bluetooth.le.ScanCallback
import android.bluetooth.le.ScanResult
import android.content.Context
import android.os.Build

class BLEScanHandler(private val context: Context) {
    private var scanner: BluetoothLeScanner? = null

    fun startScan() {
        val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
        if (bluetoothAdapter?.isEnabled != true) return

        scanner = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            bluetoothAdapter.bluetoothLeScanner
        } else {
            @Suppress("DEPRECATION")
            bluetoothAdapter
        }

        val scanCallback = object : ScanCallback() {
            override fun onScanResult(callbackType: Int, result: ScanResult?) {
                result ?: return
                // 1. 解析广播名称中的唯一标识
                result.device.name?.let { name ->
                    println("设备名称: $name")
                    name.split("-").lastOrNull().map { println("唯一标识: $it") }
                }

                // 2. 解析厂商特定数据中的唯一标识
                result.scanRecord?.manufacturerSpecificData?.forEach { (_, data) ->
                    String(data, Charsets.UTF_8).map { println("厂商数据标识: $it") }
                }
            }
        }

        scanner?.startScan(scanCallback)
    }

    fun stopScan() {
        scanner?.stopScan(object : ScanCallback() {})
    }
}

关键注意事项

  • 设备端支持:上述方案的前提是BLE设备的广播包中包含可识别的唯一标识,若为自定义设备,需在固件中配置广播数据格式。
  • 权限配置:
    • iOS:需在Info.plist中添加NSBluetoothAlwaysUsageDescription(iOS 13+)或NSBluetoothPeripheralUsageDescription(iOS 12及以下)权限说明。
    • Android:需申请BLUETOOTH_SCAN、BLUETOOTH_ADMIN权限,Android 12+额外需要ACCESS_FINE_LOCATION权限才能扫描非连接设备。
  • 稳定性优先:优先选择厂商特定数据作为唯一标识来源,避免广播名称被修改导致的标识失效问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 10:15:35