Flutter+OneSignal:iOS后台推送通知更新UI问题求助
1. NotificationServiceExtension 能否向 AppDelegate 传递数据?
可以,但无法直接通过内存共享——Extension 和主 App 运行在独立进程,属于不同沙盒容器。实现跨进程数据传递的常用方式是通过 App Groups 共享存储:
- 登录苹果开发者后台,给主应用和 NotificationServiceExtension 配置同一个 App Group(例如
group.com.your.app.notification) - 在两端代码中使用带 App Group 标识的 UserDefaults:
// NotificationServiceExtension 中写入通知数据 let sharedDefaults = UserDefaults(suiteName: "group.com.your.app.notification") sharedDefaults?.set(notificationContent.userInfo, forKey: "latest_notification") sharedDefaults?.synchronize() // AppDelegate 中在后台唤醒时主动读取 override func applicationDidBecomeActive(_ application: UIApplication) { super.applicationDidBecomeActive(application) let sharedDefaults = UserDefaults(suiteName: "group.com.your.app.notification") if let notification = sharedDefaults?.value(forKey: "latest_notification") { flutterChannel.invokeMethod("getNotification", arguments: notification) // 读取后清空,避免重复处理 sharedDefaults?.removeObject(forKey: "latest_notification") } }
除了 UserDefaults,也可以用 Keychain 实现共享(同样需要配置 App Group),适合存储敏感数据。
2. 能否直接将 NotificationServiceExtension 中的数据传递至 Flutter 端?
不行。NotificationServiceExtension 进程中没有 Flutter 引擎实例,无法获取 binaryMessenger,因此无法直接通过 MethodChannel 调用 Flutter 方法。必须先将数据传递到主 App 进程,再由主 App 转发给 Flutter。
3. 其他捕获通知并传递至 Flutter 端的方案
方案一:利用 OneSignal 原生回调(最推荐)
你的 didReceiveRemoteNotification 方法未触发,大概率是因为 OneSignal SDK 已经接管了该生命周期方法。可以通过 OneSignal 提供的回调来捕获通知:
// AppDelegate 中添加 OneSignal 通知接收监听 override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { // 先让 OneSignal 处理通知逻辑 OneSignal.didReceiveRemoteNotification(userInfo, fetchCompletionHandler: completionHandler) // 提取通知数据传递给 Flutter if let alert = userInfo["aps"]?["alert"] as? [String: Any], let title = alert["title"], let body = alert["body"] { flutterChannel.invokeMethod("getNotification", arguments: ["title": title, "body": body]) } }
同时在 Flutter 端,也可以直接监听 OneSignal 的通知回调:
OneSignal.Notifications.addForegroundWillDisplayListener((event) { // 前台收到通知时更新列表 updateNotificationList(event.notification); }); OneSignal.Notifications.addClickListener((event) { // 点击通知时更新列表 updateNotificationList(event.notification); });
方案二:后台唤醒时读取共享数据
当 NotificationServiceExtension 将通知数据写入 App Group 共享存储后,主 App 在后台被唤醒时(例如收到推送通知后系统触发唤醒),主动读取共享数据并传递给 Flutter,实现列表更新。
方案三:使用 APNS 静默推送
如果只需要更新列表而无需显示通知,可以发送静默推送(推送 payload 包含 content-available: 1,不含 alert 字段),此时主 App 的 didReceiveRemoteNotification 会被触发,直接处理数据并传递给 Flutter。
内容的提问来源于stack exchange,提问作者Kyrylo Petrenko

