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

Xamarin.Android持续扫描iBeacon出现数据包间隔中断问题

Android端Xamarin BLE iBeacon扫描间歇性中断问题排查与解决

问题描述

我正在开发一款iOS/Android跨平台Xamarin应用,核心功能是扫描iBeacon设备并评估与手机的距离。iOS端使用原生iBeacon API运行正常,但Android端因为无原生iBeacon支持,结合自研代码与UniversalBeacon库实现扫描时,长时间扫描(测距)稳定性极差:BLE数据包会随机持续接收一段时间后完全停止,间隔随机时长后又恢复,循环往复。

已尝试以下方案但均未解决问题:

  • 调整ScanMode为LowPower/Balanced模式
  • 设置特定Beacon过滤规则
  • 定时重启扫描任务
  • 更换为Shiny.Beacons库

同时已通过其他设备同步扫描验证,排除了Beacon设备本身广告发送异常的可能。

初始化扫描代码

_ScanCallback.OnAdvertisementPacketReceived += ScanCallback_OnAdvertisementPacketReceived;

var settings = new ScanSettings.Builder()
    .SetScanMode(ScanMode.LowLatency)
    .Build();

_Adapter.BluetoothLeScanner.StartScan(null, settings, _ScanCallback);

回调实现代码

internal class BLEScanCallback : ScanCallback
{
    public event EventHandler<BLEAdvertisementPacketArgs> OnAdvertisementPacketReceived;

    public override void OnScanFailed([GeneratedEnum] ScanFailure errorCode)
    {
        base.OnScanFailed(errorCode);
    }

    public override void OnScanResult([GeneratedEnum] ScanCallbackType callbackType, ScanResult result)
    {
        base.OnScanResult(callbackType, result);

        switch (result.Device.Type)
        {
            case BluetoothDeviceType.Le:
            case BluetoothDeviceType.Unknown:
                try
                {
                    var p = new BLEAdvertisementPacket
                    {
                        BluetoothAddress = result.Device.Address.ToNumericAddress(),
                        RawSignalStrengthInDBm = (short)result.Rssi,

                        Timestamp = DateTimeOffset.FromUnixTimeMilliseconds(result.TimestampNanos / 1000000),

                        AdvertisementType = (BLEAdvertisementType)result.ScanRecord.AdvertiseFlags,
                        Advertisement = new BLEAdvertisement
                        {
                            LocalName = result.ScanRecord.DeviceName
                        }
                    };

                    if (result.ScanRecord.ServiceUuids != null)
                    {
                        foreach (var svc in result.ScanRecord.ServiceUuids)
                        {
                            var guid = new Guid(svc.Uuid.ToString());
                            var data = result.ScanRecord.GetServiceData(svc);

                            p.Advertisement.ServiceUuids.Add(guid);
                        }
                    }

                    var recordData = result.ScanRecord.GetBytes();
                    var rec = RecordParser.Parse(recordData);

                    foreach (var curRec in rec)
                    {
                        if (curRec is BLEManufacturerData md)
                        {
                            p.Advertisement.ManufacturerData.Add(md);
                        }
                        if (curRec is BLEAdvertisementDataSection sd)
                        {
                            p.Advertisement.DataSections.Add(sd);
                        }
                    }
                    OnAdvertisementPacketReceived?.Invoke(this, new BLEAdvertisementPacketArgs(p));
                }
                catch (Exception ex)
                {
                    Debugger.Break();
                }
                break;
            default:
                break;
        }
    }
}

可能成因

  1. Android系统BLE扫描限制:Android 8.0及以上版本对后台BLE扫描有严格频率限制,部分厂商定制系统(小米、华为等)会在后台或长时间扫描后自动降低扫描频率甚至暂停扫描以节省电量。
  2. 扫描回调阻塞:OnScanResult回调中包含大量数据解析逻辑,若执行时间过长会阻塞扫描队列,触发系统停止扫描避免主线程过载。
  3. 蓝牙适配器资源泄漏:未正确处理扫描停止逻辑,或多次启动扫描未释放旧回调实例,导致蓝牙资源耗尽引发扫描中断。
  4. 权限问题:Android 12+需BLUETOOTH_SCAN等权限,后台扫描还需ACCESS_FINE_LOCATION,权限缺失或状态变化(如用户关闭定位)会导致扫描中断。

解决方法

1. 优化扫描回调性能

  • 将数据解析逻辑转移到后台线程,避免阻塞扫描回调:
    public override void OnScanResult([GeneratedEnum] ScanCallbackType callbackType, ScanResult result)
    {
        base.OnScanResult(callbackType, result);
        Task.Run(() => ProcessScanResult(result)); // 后台线程处理解析逻辑
    }
    
    private void ProcessScanResult(ScanResult result)
    {
        // 原有的数据解析、事件触发逻辑
    }
    
  • 简化解析逻辑,只过滤处理iBeacon相关数据包(如Apple厂商ID0x004C的数据包),减少不必要计算。

2. 适配Android系统扫描限制

  • 前台扫描优化:应用处于前台时使用ScanMode.LowLatency,同时启动前台服务(Foreground Service),避免被系统判定为后台限制扫描。
  • 后台扫描策略:Android 8.0+用JobScheduler或WorkManager定时启动扫描,单次扫描不超30秒,间隔至少1分钟;Android 12+申请BLUETOOTH_SCAN权限并声明android:usesPermissionFlags="neverForLocation"(无需定位时)。
  • 厂商适配:引导用户关闭应用省电模式,将应用加入后台保护白名单。

3. 修复资源泄漏问题

  • 停止扫描时务必释放资源:
    public void StopScan()
    {
        if (_ScanCallback != null && _Adapter != null && _Adapter.IsEnabled)
        {
            _Adapter.BluetoothLeScanner.StopScan(_ScanCallback);
            _ScanCallback.OnAdvertisementPacketReceived -= ScanCallback_OnAdvertisementPacketReceived;
            _ScanCallback = null;
        }
    }
    
  • 启动扫描前检查状态,避免重复启动。

4. 完善权限处理

  • 在AndroidManifest.xml添加必要权限:
    <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    
  • 运行时动态申请权限,监听权限变化,权限收回时及时停止扫描并提示用户。

5. 替换为成熟iBeacon库

尝试使用AltBeacon Android Beacon Library的Xamarin绑定版本,该库针对Android系统BLE扫描限制做了大量适配,能自动处理扫描中断、权限管理和厂商兼容性问题,稳定性优于现有库。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 16:21:11