iOS应用进入后台或终止状态时发送OneSignal标签失败咨询
可行解决方案
核心方案:申请系统默认后台执行时长
iOS系统默认允许APP进入后台时申请最多30秒的额外运行时间,完全覆盖你7-9秒的OneSignal标签上传需求,不需要额外申请特殊后台权限,也不会影响App Store审核。
核心逻辑如下:
- 进入后台时先判断购物车是否符合上报条件
- 调用系统API申请后台任务,拿到最长30秒的执行窗口
- 使用带完成回调的OneSignal标签上传方法,请求完成后主动结束后台任务
- 后台时间即将耗尽时做兜底存储,下次启动补发
// AppDelegate 全局变量 var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid func applicationDidEnterBackground(_ application: UIApplication) { // 不符合上报条件直接返回 guard AbondenCart.isAbondened else { return } // 申请后台任务 backgroundTaskID = application.beginBackgroundTask(withName: "SendOneSignalCartTag") { // 后台时间即将耗尽的兜底回调,存储未发送数据 self.saveUnsentTagToLocal() // 结束后台任务 if self.backgroundTaskID != .invalid { application.endBackgroundTask(self.backgroundTaskID) self.backgroundTaskID = .invalid } } // 构造上报数据 let abondenTime = Int(Date().timeIntervalSince1970) let tagDict: [String: String] = [ "cart_update": "\(AbondenCart.isAbondened)", "product_name": AbondenCart.productName, "product_image": AbondenCart.productImage, "update_time": "\(abondenTime)" ] // 使用带回调的上传方法,确保上传完成后收尾 OneSignal.sendTags(tagDict) { uploadSuccess in if uploadSuccess { self.clearUnsentLocalTag() } else { self.saveUnsentTagToLocal() } // 主动结束后台任务释放资源 if self.backgroundTaskID != .invalid { application.endBackgroundTask(self.backgroundTaskID) self.backgroundTaskID = .invalid } } } // 本地持久化工具方法 func saveUnsentTagToLocal() { let abondenTime = Int(Date().timeIntervalSince1970) let tagDict: [String: String] = [ "cart_update": "\(AbondenCart.isAbondened)", "product_name": AbondenCart.productName, "product_image": AbondenCart.productImage, "update_time": "\(abondenTime)" ] UserDefaults.standard.set(tagDict, forKey: "UnsentOneSignalCartTag") } func clearUnsentLocalTag() { UserDefaults.standard.removeObject(forKey: "UnsentOneSignalCartTag") } // 启动时补发逻辑,加在didFinishLaunchingWithOptions中 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // OneSignal初始化等原有逻辑 OneSignal.initWithLaunchOptions(launchOptions) // 检查本地是否有未发送的标签,有则补发 if let unsentTag = UserDefaults.standard.dictionary(forKey: "UnsentOneSignalCartTag") as? [String: String] { OneSignal.sendTags(unsentTag) { success in if success { self.clearUnsentLocalTag() } } } return true }
如果你的项目使用了iOS13+的Scene生命周期,将申请后台任务的逻辑放到
SceneDelegate的sceneDidEnterBackground方法中即可,逻辑完全一致。
原有方案失效原因说明
- background fetch由系统按策略定时触发,并非进入后台立即执行,无法满足即时上报需求
- applicationWillTerminate仅预留最多5秒执行时间,优先级极低,大多数场景下不会执行自定义逻辑
- BGTask属于延迟调度任务,系统会在设备空闲、低功耗时段才触发,无法实现进入后台即时执行
内容的提问来源于stack exchange,提问作者Husain Nahar
相关产品推荐
相关产品推荐

