Flutter iOS端如何处理后台通知实现通知数据SQLite存储
Flutter iOS端无法捕获通知执行SQLite存储的解决方案
iOS系统对通知回调有严格的权限和场景限制,写了background handler却捕获不到通知,基本都是配置缺失、实现不符合系统规则导致的,按以下步骤排查修复即可:
- 先区分通知场景,补全前台回调
很多开发者只注册了后台handler,完全没处理前台场景:APP在前台打开状态下收到通知,iOS不会触发后台handler,只会触发前台消息回调(如果用firebase_messaging就是FirebaseMessaging.onMessage,用其他推送插件对应找前台回调方法)。
前台回调运行在主Isolate,可以直接调用已经初始化好的SQLite实例存储通知,注意不要在这个回调里跑太耗时的操作阻塞UI。 - 修正后台消息handler的实现和配置
后台handler触发必须同时满足以下所有条件,缺一个都不会执行:- Xcode中打开工程的
Signing & Capabilities,添加Background Modes能力,勾选Remote notifications选项,否则系统不会给APP开放后台执行通知逻辑的权限。 - 推送的APNs payload必须符合要求:如果是静默通知,
aps节点必须携带"content-available": 1;如果是带弹窗、声音的可见通知,还要额外加"mutable-content": 1,缺这两个字段的话系统会直接弹出通知,不会把消息抛给Flutter层。 - 后台handler必须是顶级函数或者静态函数,不能是类的实例方法,同时必须加
@pragma('vm:entry-point')注解,防止release构建时被编译器裁剪。 - 后台handler运行在独立的Isolate,和主Isolate内存不共享,不要直接引用主Isolate里初始化的SQLite实例、全局变量,必须在handler内部重新初始化Flutter绑定、重新打开数据库再执行存储逻辑,正确写法参考:
注册handler的代码要写在// 写在main函数外,全局顶级作用域 @pragma('vm:entry-point') Future<void> notificationBackgroundHandler(RemoteMessage message) async { // 后台环境下必须手动初始化引擎绑定,否则无法调用插件 WidgetsFlutterBinding.ensureInitialized(); // 重新初始化数据库,不要复用主Isolate的db对象 final db = await DBHelper().openDB(); // 执行通知入库逻辑 await db.insert('notifications', { 'id': message.messageId, 'title': message.notification?.title, 'content': message.notification?.body, 'extra': jsonEncode(message.data), 'create_time': DateTime.now().millisecondsSinceEpoch }); }main.dart的main函数里,在runApp之前执行。
- Xcode中打开工程的
- 可见通知的拦截必须接入Notification Service Extension
这是绝大多数人踩的核心坑:如果是会弹出横幅的可见通知,iOS系统收到后会直接渲染弹出,默认不会把通知内容传递给宿主APP的Flutter层,哪怕你开了后台模式、写对了handler也拿不到。
这种场景要拦截通知内容存库,必须在iOS工程中新增Notification Service Extension:- 用Xcode打开iOS工程,依次点击File -> New -> Target,选择
Notification Service Extension,填写扩展名称完成创建,注意扩展的签名要和主APP保持一致。 - 扩展的执行内存上限很低、最长执行时间只有30秒,不要直接在扩展里操作SQLite,很容易被系统杀死。建议开启App Group能力让扩展和主APP共享存储空间,在扩展的
didReceive方法里拿到通知内容后,先写入共享空间的UserDefaults或者临时文件,等主APP下次冷启动、回到前台的时候,读取共享空间里暂存的通知批量写入SQLite即可。
- 用Xcode打开iOS工程,依次点击File -> New -> Target,选择
- 测试阶段的注意事项
- 不要连着Xcode调试后台通知逻辑,Xcode的调试挂载会干扰系统的后台调度,容易出现handler不触发的假象,建议打测试包断开Xcode,用macOS自带的Console.app查看设备日志排查问题。
- iOS 13及以上版本,如果用户手动上滑杀掉APP,系统会暂时屏蔽该APP的后台通知回调,直到用户下次手动打开APP才会恢复,这是系统级策略,没有绕过方案,需要在产品逻辑上做兼容。
- 模拟器对后台通知的支持有缺陷,所有和通知回调相关的测试必须用真机完成。
内容的提问来源于stack exchange,提问作者ahmad hasan
相关产品推荐
相关产品推荐

