iOS15下Xamarin.Forms应用DidRangeBeacons后台/被杀状态无法持续触发问题
问题核心原因
iOS 15对后台Beacon测距机制做了严格限制:默认状态下,应用被区域进入事件唤醒后,仅能获得最多10秒的后台运行时间,时间到后系统会自动挂起应用,测距回调也就停止了。再加上你现有代码存在生命周期管理漏洞,才会出现熄屏/解锁后回调停止的问题。
修复步骤
- 第一步:修复BTManager生命周期问题
你在AppDelegate的FinishedLaunching中将BTManager声明为局部变量,会很快被GC回收,导致Delegate回调中断,需要改为全局属性:
public class AppDelegate : UIResponder, IUIApplicationDelegate { [Export("window")] public UIWindow Window { get; set; } // 改为全局属性避免被回收 public BTManager BtInstance { get; set; } [Export("application:didFinishLaunchingWithOptions:")] public bool FinishedLaunching(UIApplication application, NSDictionary launchOptions) { BtInstance = new BTManager(); // 新增:判断是否由位置事件唤醒应用 if (launchOptions != null && launchOptions.ContainsKey(UIApplication.LaunchOptionsLocationKey)) { BtInstance.RestartMonitoring(); } return true; } // 其余原有代码保留不变 }
第二步:添加必要的权限与后台模式配置
在Info.plist中添加以下配置:- 权限声明:
NSLocationAlwaysAndWhenInUseUsageDescription:需要始终访问位置以扫描BeaconNSLocationWhenInUseUsageDescription:使用应用期间需要访问位置以扫描Beacon- 新增
NSLocationTemporaryUsageDescriptionDictionary节点配置精确位置权限(iOS 14+强制要求)
- 后台模式:添加
UIBackgroundModes字段,值包含location(启用后台位置更新能力)
第三步:调整CLLocationManager配置
在BTManager的构造方法中新增以下配置,提升后台存活优先级:
public BTManager() { // 原有权限申请、通知配置代码保留不变 locationmanager = new CLLocationManager(); locationmanager.Delegate = this; // 新增配置 locationmanager.AllowsBackgroundLocationUpdates = true; // 允许后台位置更新 locationmanager.PausesLocationUpdatesAutomatically = false; // 禁止系统自动暂停位置更新 locationmanager.ShowsBackgroundLocationIndicator = true; // iOS 14+显示后台位置使用指示器,提升后台存活优先级 locationmanager.RequestAlwaysAuthorization(); // 注意原有代码此处构造方法多了一个逗号,会编译错误,需删除 region = new CLBeaconRegion(new NSUuid("3ABFAA22-5624-11EA-8E2D-0242AC130003"), 0, 109, "Region 1"); region.NotifyOnEntry = true; region.NotifyOnExit = true; region.NotifyEntryStateOnDisplay = true; }
- 第四步:优化区域事件回调逻辑,延长后台运行时间
当应用被杀后被区域进入事件唤醒时,原有的测距任务已停止,需要在进入区域时重新启动测距,同时申请额外的后台运行时间:
public class BTManager : CLLocationManagerDelegate { // 原有属性保留不变 private nint _bgTaskId = 0; // 新增重启监测的公共方法 public void RestartMonitoring() { if (locationmanager.MonitoredRegions.Contains(region)) { locationmanager.StopMonitoring(region); locationmanager.StopRangingBeacons(region); } locationmanager.StartMonitoring(region); locationmanager.StartRangingBeacons(region); } public override void RegionEntered(CLLocationManager manager, CLRegion region) { var reg = region as CLBeaconRegion; if (reg != null) { notifcationmanager.Send("Entered Region", "...", "111"); // 重启测距 locationmanager.StopRangingBeacons(reg); locationmanager.StartRangingBeacons(reg); // 申请最长30秒后台运行时间 _bgTaskId = UIApplication.SharedApplication.BeginBackgroundTask(() => { UIApplication.SharedApplication.EndBackgroundTask(_bgTaskId); _bgTaskId = 0; }); } } public override void RegionLeft(CLLocationManager manager, CLRegion region) { var reg = region as CLBeaconRegion; if (reg != null) { notifcationmanager.Send("Left Region", "...", "111"); // 离开区域停止测距释放资源 locationmanager.StopRangingBeacons(reg); if (_bgTaskId != 0) { UIApplication.SharedApplication.EndBackgroundTask(_bgTaskId); _bgTaskId = 0; } } } // 其余原有回调代码保留不变 }
如果需要超过30秒的持续后台测距,iOS15+下可配合实时活动(Live Activity)或者运动传感器权限延长后台存活时间,但会相应增加电量消耗。
内容的提问来源于stack exchange,提问作者Jason Roy
相关产品推荐
相关产品推荐

