You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter集成OneSignal:后台/关闭时addForegroundWillDisplayListener不触发

解决方案:实现后台/关闭状态下保存OneSignal通知到SharedPreferences

你的问题核心是addForegroundWillDisplayListener仅在APP前台时触发,后台或关闭状态下不会执行,因此无法保存通知。以下是针对OneSignal 5.2.2版本的完整解决方案:

1. 重构代码:抽离保存逻辑并补充监听回调

首先将通知保存逻辑抽为独立函数,然后添加全局通知接收监听和启动通知获取,覆盖前台、后台、APP关闭后启动三种场景:

抽离保存逻辑

// 独立的通知保存函数,复用所有场景
Future<void> saveNotificationToSharedPreferences(OSNotification notification) async {
  // 跳过缺少必要字段的通知
  if (notification.additionalData?['myappurl'] == null || notification.title == null || notification.body == null) {
    return;
  }

  String title = notification.title!;
  String url = notification.additionalData!['myappurl'];
  String someBody = notification.body!.length > 10
      ? notification.body!.substring(0, 10)
      : notification.body!;

  SharedPreferences sp = await SharedPreferences.getInstance();
  List<OldNotification> oldDatas = readNotificationsFromSharedp(sp, 'SavedNotifications');

  OldNotification newSingleData = OldNotification(
      title: title, url: url, body: someBody, isOpened: false);
  
  if (isElementNotExistByURL(oldDatas, newSingleData)) {
    oldDatas.add(newSingleData);
    var correctedOrder = oldDatas.reversed.toList();
    List<String> favListing = correctedOrder.map((fav) => jsonEncode(fav.toJson())).toList();
    await sp.setStringList('SavedNotifications', favListing);
  } else {
    print('通知已存在,无需重复保存');
  }
}

修改初始化逻辑

Future<void> initPlatformState() async {
  AppConstants constants = AppConstants();
  OneSignal.Debug.setLogLevel(OSLogLevel.verbose);
  OneSignal.Debug.setAlertLevel(OSLogLevel.none);
  
  // 确保OneSignal初始化完成
  await OneSignal.initialize(constants.OneSignalKey);
  await OneSignal.Notifications.requestPermission(true);

  // 通知点击事件处理(保留原有逻辑)
  OneSignal.Notifications.addClickListener((event) {
    print('NOTIFICATION CLICK LISTENER CALLED WITH EVENT: $event');
    String url = event.notification.additionalData!['myappurl'];
    webController?.loadUrl(urlRequest: URLRequest(url: WebUri(url)));
  });

  // 前台通知展示前处理(保留原有逻辑)
  OneSignal.Notifications.addForegroundWillDisplayListener((event) async {
    print('NOTIFICATION WILL DISPLAY LISTENER CALLED WITH: ${event.notification.jsonRepresentation()}');
    event.preventDefault();
    event.notification.display();
    await saveNotificationToSharedPreferences(event.notification);
  });

  // 全局通知接收监听(前台/后台均触发,iOS需额外配置)
  OneSignal.Notifications.addNotificationReceivedListener((notification) async {
    print('NOTIFICATION RECEIVED: ${notification.jsonRepresentation()}');
    await saveNotificationToSharedPreferences(notification);
  });

  // 处理APP关闭后点击通知启动的场景
  final launchNotification = await OneSignal.Notifications.getLaunchNotification();
  if (launchNotification != null) {
    print('LAUNCH NOTIFICATION: ${launchNotification.jsonRepresentation()}');
    await saveNotificationToSharedPreferences(launchNotification);
  }
}

2. iOS端配置:启用Notification Service Extension

iOS默认在后台不会执行Flutter代码,必须通过Service Extension让OneSignal在后台触发通知接收逻辑:

  1. 打开Xcode中的iOS项目(ios/Runner.xcworkspace),右键点击Runner文件夹 → New Target。
  2. 选择Application Extension分类下的Notification Service Extension,命名为OneSignalNotificationServiceExtension,语言选Swift,点击Finish并激活方案。
  3. 替换NotificationService.swift内容:
import UserNotifications
import OneSignalFramework

class NotificationService: UNNotificationServiceExtension {
    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?

    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
        
        if let bestAttemptContent = bestAttemptContent {
            // 委托OneSignal处理通知,触发Flutter端的监听回调
            OneSignal.didReceiveNotificationExtensionRequest(request, with: bestAttemptContent)
            contentHandler(bestAttemptContent)
        }
    }
    
    override func serviceExtensionTimeWillExpire() {
        if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {
            OneSignal.serviceExtensionTimeWillExpireRequest(bestAttemptContent)
            contentHandler(bestAttemptContent)
        }
    }
}
  1. 在ios/Podfile中添加Extension的依赖:
target 'OneSignalNotificationServiceExtension' do
  use_frameworks!
  use_modular_headers!
  
  pod 'OneSignalFramework', '>= 5.0.0'
end

然后执行pod install更新依赖。

3. Android端配置(无需额外操作)

OneSignal 5.x版本在Android后台默认会触发addNotificationReceivedListener,只需确保AndroidManifest.xml中已包含OneSignal的默认配置(Flutter插件会自动添加):

<meta-data android:name="com.onesignal.NotificationOpened.DEFAULT" android:value="DISABLE" />
<service android:name="com.onesignal.notifications.services.OSNotificationReceiveService"
         android:permission="android.permission.BIND_JOB_SERVICE"
         android:exported="false" />

测试验证

  • 前台场景:通知到达,两个监听回调触发,通过去重逻辑避免重复保存。
  • 后台场景:通知到达后,addNotificationReceivedListener触发,自动保存通知,系统正常展示通知。
  • APP关闭场景:通知到达后系统展示,用户点击通知启动APP时,getLaunchNotification获取启动通知并保存。

内容的提问来源于stack exchange,提问作者Biruk Damte

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 21:57:32