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

Xamarin.iOS开发:如何获取iBeacon的GUID、高低位字及信号强度?

Xamarin.iOS iBeacon扫描器开发疑问

我正在使用Xamarin.iOS开发一款基于iBeacon协议的BLE扫描器,需要获取设备的GUID、关联的两个16位字(Major/Minor)以及信号强度,以此计算手机与BLE信标间的距离。我们无需与信标建立连接,仅依靠其每250ms发送的广播数据即可满足需求,这两个16位字段用于触发靠近信标时的操作,信标已通过厂商软件配置完成。

目前我的伪代码如下:

if (scanner == null)
{
    scanner = new CBCentralManager();
}

if (scanner != null)
{
    // FIXME Should I pass null to the first parameter of ScanForPeripherals?
    scanner.DiscoveredPeripheral += Scanner_DiscoveredPeripheral;
    scanner.ScanForPeripherals(null, new PeripheralScanningOptions { AllowDuplicatesKey = true });
}

private void Scanner_DiscoveredPeripheral(object sender, CBDiscoveredPeripheralEventArgs e)
{
    lock (this.visibleBeacons)
    {
        // FIXME : How do I get the 2 word values and the signal strength?
        BeaconInfo discoveredPeripheral = new BeaconInfo(e.Peripheral.Identifier.ToString(), word1, word2, signalStrength);
        ...
    }
}

现有两个疑问:

  1. ScanForPeripherals的第一个参数是否应传入null?
  2. 如何在回调中获取那两个16位字的值和信号强度?

解答

1. ScanForPeripherals第一个参数的取值

传null是可行的,但会扫描所有BLE设备,效率较低。更优的做法是指定iBeacon专属的服务UUID(0000FEAA-0000-1000-8000-00805F9B34FB),这样只会扫描符合iBeacon协议的设备,减少不必要的回调:

var iBeaconServiceUuid = CBUUID.FromString("0000FEAA-0000-1000-8000-00805F9B34FB");
scanner.ScanForPeripherals(new[] { iBeaconServiceUuid }, new PeripheralScanningOptions { AllowDuplicatesKey = true });

如果你的信标配置了自定义的UUID,也可以直接指定该UUID来缩小扫描范围,进一步提升效率。

2. 获取信号强度与两个16位字(Major/Minor)

信号强度

直接从CBDiscoveredPeripheralEventArgs的RSSI属性获取:

var signalStrength = e.RSSI;

解析Major/Minor与GUID

iBeacon的核心数据(UUID、Major、Minor)封装在广播数据的厂商特定字段中,需要解析e.AdvertisementData[CBAdvertisementData.ManufacturerDataKey]对应的NSData:

首先添加解析方法:

private bool TryParseIBeaconData(NSData manufacturerData, out Guid uuid, out ushort major, out ushort minor)
{
    uuid = Guid.Empty;
    major = 0;
    minor = 0;

    // iBeacon厂商数据格式:苹果公司ID(2字节) + 类型(1字节) + 长度(1字节) + UUID(16字节) + Major(2字节) + Minor(2字节) + 校准信号强度(1字节)
    if (manufacturerData.Length < 25)
        return false;

    var bytes = manufacturerData.ToArray();
    // 验证苹果厂商ID(0x4C00)
    if (bytes[0] != 0x00 || bytes[1] != 0x4C)
        return false;
    // 验证iBeacon类型(0x02)和长度(0x15)
    if (bytes[2] != 0x02 || bytes[3] != 0x15)
        return false;

    // 提取UUID(字节4-19)并调整字节序
    var uuidBytes = bytes.Skip(4).Take(16).ToArray();
    Array.Reverse(uuidBytes, 0, 4);
    Array.Reverse(uuidBytes, 4, 2);
    Array.Reverse(uuidBytes, 6, 2);
    uuid = new Guid(uuidBytes);

    // 提取Major(字节20-21),大端转小端
    major = BitConverter.ToUInt16(bytes.Skip(20).Take(2).Reverse().ToArray(), 0);
    // 提取Minor(字节22-23),大端转小端
    minor = BitConverter.ToUInt16(bytes.Skip(22).Take(2).Reverse().ToArray(), 0);

    return true;
}

然后在回调中调用解析:

private void Scanner_DiscoveredPeripheral(object sender, CBDiscoveredPeripheralEventArgs e)
{
    lock (this.visibleBeacons)
    {
        var signalStrength = e.RSSI;
        
        if (e.AdvertisementData.TryGetValue(CBAdvertisementData.ManufacturerDataKey, out NSObject manufacturerObj) && 
            manufacturerObj is NSData manufacturerData)
        {
            if (TryParseIBeaconData(manufacturerData, out Guid beaconUuid, out ushort major, out ushort minor))
            {
                BeaconInfo discoveredPeripheral = new BeaconInfo(beaconUuid.ToString(), major, minor, signalStrength);
                // 后续逻辑处理
            }
        }
    }
}

注意:解析时要处理字节序问题,因为iBeacon的Major/Minor和UUID使用大端字节序,而C#的BitConverter默认使用小端,所以需要反转字节数组。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 13:45:01