禁用地理位置权限后本地重要通知无法送达的原因排查
问题
我的应用已获取展示重要通知(远程及本地)的权限,配置了后台按固定间隔展示本地重要通知的逻辑,核心代码如下:
通知调度调用代码
Log.i(">noti #\(i) next \(i * self.preEpisodeInterval)s") self.scheduleLocalNoti( title: LanguageHelper.getTranslationByKey(LanguageKey.ALARM) ?? "", body: data.preEpisodeWarnMessage ?? "", isCritical: true, timeInterval: TimeInterval(i * self.preEpisodeInterval), soundName: self.preAlarmModel?.data?.preEpisodeTone ?? "melodie.wav", userInfo: [MotionTrackingManager.LOCAL_NOTI_PREALARM_USERINFO: ""] )
本地通知调度实现
private func scheduleLocalNoti(title: String, body: String, isCritical: Bool = false, timeInterval: TimeInterval = 0, soundName: String? = nil, userInfo: [AnyHashable: Any]? = nil) { let content = UNMutableNotificationContent() content.title = title content.body = body if isCritical { if soundName != nil { let notiSound = UNNotificationSoundName(rawValue: soundName!) content.sound = UNNotificationSound.criticalSoundNamed(notiSound, withAudioVolume: 1.0) } else { content.sound = UNNotificationSound.defaultCriticalSound(withAudioVolume: 1.0) } } else { if soundName != nil { let notiSound = UNNotificationSoundName(rawValue: soundName!) content.sound = UNNotificationSound(named: notiSound) } else { content.sound = UNNotificationSound.default } } if userInfo != nil { content.userInfo = userInfo! } // 创建触发器 let trigger = UNTimeIntervalNotificationTrigger(timeInterval: timeInterval + 1, repeats: false) let uuidString = UUID().uuidString Log.i("Schedule local noti for: \(timeInterval + 1) with uuid: \(uuidString)") // 创建通知请求 let request = UNNotificationRequest( identifier: uuidString, content: content, trigger: trigger ) // 向系统调度通知请求 let notificationCenter = UNUserNotificationCenter.current() notificationCenter.add(request) { error in if error != nil { // 处理错误 Log.e("errr: \(String(describing: error?.localizedDescription))") } } }
此外,应用已在Signing & Capabilities中开启Background Modes的Location update选项用于地理位置追踪。当前遇到的问题:
- 当地理位置权限被拒绝时,本地通知无法展示,但远程通知可正常工作
- 该问题仅出现在TestFlight/App Store构建版本中,通过Xcode直接运行的模拟器Release版本,即使地理位置权限被拒绝,本地通知仍能正常展示
请问地理位置权限为何会影响本地重要通知的展示?
分析与解答
地理位置权限影响本地通知的核心原因和iOS的后台执行策略、正式构建环境的权限校验逻辑直接相关,具体如下:
1. 后台模式权限的关联性限制
你开启了Location update后台模式,当用户拒绝地理位置权限后,iOS会判定应用无资格使用该后台模式。对于TestFlight/App Store的正式构建包,iOS会严格校验后台模式的使用资格:若应用申请了某类后台模式但未获得对应权限,系统会限制应用的后台活动,包括禁止后台调度本地通知——系统认为你申请后台模式的核心目的是基于位置追踪,既然位置权限被拒,后台活动的必要性就不存在了。
而Xcode直接运行的模拟器版本,系统对后台模式的权限校验会宽松很多,不会严格限制后台活动的执行,因此即使位置权限被拒,本地通知仍能正常调度。
2. 关键通知的后台状态限制
你调度的是critical类型通知(isCritical: true),这类通知虽优先级较高,但仍受应用后台状态的约束。当应用因位置权限被拒而失去后台活动资格时,系统会阻止这类本地通知的触发;而远程通知由APNs直接推送,不受应用后台状态限制,因此能正常展示。
3. 正式构建的合规校验逻辑
TestFlight/App Store的构建包会经过苹果的合规校验,其中包含后台模式的使用合理性检查。若应用申请了Location update但未获得权限,系统会默认限制应用的后台行为,避免滥用后台资源。而模拟器的调试构建则跳过了部分合规校验逻辑,因此不会触发该限制。
解决建议
- 解耦功能逻辑:若本地通知不需要依赖位置追踪,将其调度逻辑与位置权限分离,避免因位置权限影响通知功能
- 明确权限用途:申请位置权限时,向用户清晰说明权限用途,提升用户授权率
- 真机测试正式构建:使用Ad Hoc构建包在真机上测试,提前复现TestFlight环境下的权限问题
内容的提问来源于stack exchange,提问作者Sunbey13

