【问题标题】:didReceiveRemoteNotification not called in iOS 13.3 when app is in background应用程序处于后台时,iOS 13.3 中未调用 didReceiveRemoteNotification
【发布时间】:2020-05-09 15:08:44
【问题描述】:

我在敲我的头。我正在实施推送通知。一切正常(收到推送,更新徽章),但在 iOS 13.3 下,当应用程序在后台时,不会调用方法 application(_:didReceiveRemoteNotification:fetchCompletionHandler:) 。如果应用程序在前台或使用 iOS 12 设备,则调用该方法。我通过以下方式注册推送通知:

[[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert) completionHandler:^(BOOL granted, NSError * _Nullable error) {
    if (granted) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [[UIApplication sharedApplication] registerForRemoteNotifications];
        });
    }
}];

payload设置如下

{"aps": {
    "badge": 10,
    "alert": "test",
    "content-available": 1
}}

我尝试在所有变体中添加“远程通知”和“后台处理”作为应用程序功能(仅“远程通知”/“后台处理”,没有任何这些功能,同时启用两者),没有任何更改。我为 UNUserNotificationCenter 设置了委托,但再次没有成功。我相应地设置了标题:

curl -v \
 -H 'apns-priority: 4' \
 -H 'apns-topic: xx.xxxxx.xxxx' \
 -H 'apns-push-type: alert' \
 -H 'Content-Type: application/json; charset=utf-8' \
 -d '{"aps": {"badge": 10,"alert": "test", "content-available":1}}' \
 --http2 \
 --cert pushcert.pem \
 https://api.sandbox.push.apple.com/3/device/1234567890

从文档中可以看出,即使应用程序处于后台,也会调用此方法:

使用此方法为您的应用处理传入的远程通知。 与 application:didReceiveRemoteNotification: 方法不同,它是 仅当您的应用程序在前台运行时调用,系统 当您的应用在前台运行时调用此方法或 背景。

对于 iOS 13,我在这里缺少什么?

【问题讨论】:

  • 请参见上文:一切正常(收到推送,更新徽章)但在 iOS 13.3 下,当应用程序在后台时,不会调用方法 application(_:didReceiveRemoteNotification:fetchCompletionHandler:) .
  • application(_:didReceiveRemoteNotification:fetchCompletionHandler:) 将在您点击通知横幅时被调用
  • 是的,这是正确的。我的问题是:为什么应用程序在后台时不调用它。据我了解,文档是这样说的。
  • 您是否尝试过实现application(_:didReceiveRemoteNotification:withCompletionHandler:) 方法?

标签: ios objective-c apple-push-notifications ios13 silent-notification


【解决方案1】:

你设置了吗

"content-available": 1

在您的后端 APS 有效负载中?

还需要确保您在 iOS 应用的 info.plist 文件中启用了后台模式

<key>UIBackgroundModes</key>
<array>
    <string>processing</string>
    <string>remote-notification</string>
</array>

【讨论】:

  • @matt 在我输入所有答案之前,该帖子被意外提交了。现在已经完成了应用端更改。
  • 是的,我做到了。您可以从我最初的帖子中的 CURL 请求中看到。我还添加了 "content-available": 1 并尝试了所有后台模式(启用、禁用、变体),但仍然没有调用 application(_:didReceiveRemoteNotification:fetchCompletionHandler:)。仅当应用处于活动状态时。
  • processing => 这是重要的一行
  • @ZhangZhan:你解决过这个问题吗?我遇到了同样的问题,即使正确设置了内容可用密钥,也没有收到静默/后台通知。在 iOS 12 上,一切正常,但在 iOS13 上,只有声音/视觉通知工作。我知道苹果需要在通知中包含一个新的标头类型,但已经处理(我们正在使用 SNS)。有趣的是,这不适用于具有最新 XCode 版本的 apns 文件的模拟器。
【解决方案2】:

这个委托方法:-

-(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler{

当我们点击 iOS 13 的通知并且应用在后台时被调用。

【讨论】:

  • 是的,但我正在寻找一种无需点击通知即可获取有效负载的方法。
【解决方案3】:

我花了一张支持票来获得这个问题的答案。

事实证明,有关此主题的 iOS 13 文档并非 100%“有效”。设备决定是否唤醒。虽然文档说明略有不同。

Apple 作为通知扩展的首选实施方式。之后,您必须调整有效负载以包含“可变内容”。

我后来询问支持人员是否应该提交雷达,他们回答“是”。

【讨论】:

  • 如果您提供通知扩展,应用会被唤醒吗?
  • 当然,扩展作为一个单独的进程运行,具有一个单独的包标识符。因此,如果您尝试更新应用中的某些数据,则需要使用一些应用组数据共享方法。
【解决方案4】:

需要激活“后台获取”转到文件项目 - 登录功能 - 背景模式 - 并检查后台获取和远程通知

记住在 didFinishAlunchWithOptions 中

    Messaging.messaging().delegate = self
    UNUserNotificationCenter.current().delegate = self

我在方法中有一个响应 - didReceive 响应 - 在后台但只有在点击通知时。

我找到了这个信息...但我不知道是不是真的

“如果这是来自 iOS 的新系统行为,那么 FCM 不太可能提供解决方法。需要注意的几点:

Apple 的文档提到系统会限制静默通知以节省电量。过去,我们已经看到,在您的设备插入电源的情况下测试静音通知会减少限制。 在较旧的 iOS 版本中,Apple 的文档已经提到强制退出应用程序将完全阻止从静默通知中唤醒。我不确定是否仍然如此。”

当我收到通知时,我仍在后台寻找应用程序中更新徽章图标的通知。

【讨论】:

    【解决方案5】:

    在您的应用代理中实现didRegisterForRemoteNotificationsWithDeviceTokendidFailToRegisterForRemoteNotificationsWithError,以检查设备是否与Apple 的APN 服务器建立了良好的连接。如果不是这种情况,请重新启动设备和/或尝试通过另一个 Wi-Fi 网络建立连接并重新启动应用程序。

    【讨论】:

      【解决方案6】:

      我遇到了同样的问题。 阅读本文:https://medium.com/fenrir-inc/handling-ios-push-notifications-the-not-so-apparent-side-420891ddf10b

      我用的是 iPhone XS 软件版本 13.7

      1。 在 iOS 10 之前,使用 UIApplication 方法: registerUserNotificationSettings(:) 从 iOS 10 开始,使用 UserNotifications 框架方法: requestAuthorization(选项:completionHandler :) setNotificationCategories(:)

      if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
              {
                  UNUserNotificationCenter.Current.RequestAuthorization(UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound,
                                                                          (granted, error) => InvokeOnMainThread(UIApplication.SharedApplication.RegisterForRemoteNotifications));
              }
              else if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
              {
                  var pushSettings = UIUserNotificationSettings.GetSettingsForTypes(
                          UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound,
                          new NSSet());
      
                  UIApplication.SharedApplication.RegisterUserNotificationSettings(pushSettings);
                  UIApplication.SharedApplication.RegisterForRemoteNotifications();
              }
              else
              {
                  UIRemoteNotificationType notificationTypes = UIRemoteNotificationType.Alert | UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound;
                  UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(notificationTypes);
              }
      

      需要“推送通知”、“远程通知”和后台模式功能(info.plist 和 Entitlements.plist)

      3.

      实现 DidReceiveRemoteNotification 方法和 RegisteredForRemoteNotifications

      在此更改之后,调用了 DidReceiveRemoteNotification 方法。

      试试这个静音推送通知:

      {
          "aps" : {
              "alert" : "",
              "content-available" : 1
          },
      }
      

      试试这个普通推送通知:

      {
          "aps" : {
              "alert" : "Alert!!!"
          },
      }
      

      【讨论】:

        【解决方案7】:

        你需要实现一个通知内容扩展

        当我使用 OneSignal 及其设置代码时,这对我来说很好用 https://documentation.onesignal.com/docs/ios-sdk-setup

        不确定 OneSignal 位是否有所不同,但无论如何都要附加它们

        import UserNotifications
        import OneSignal
        
        class NotificationService: UNNotificationServiceExtension {
            
            var contentHandler: ((UNNotificationContent) -> Void)?
            var receivedRequest: UNNotificationRequest!
            var bestAttemptContent: UNMutableNotificationContent?
            
            override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
                self.receivedRequest = request;
                self.contentHandler = contentHandler
                bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
                
                if let bestAttemptContent = bestAttemptContent {
                    OneSignal.didReceiveNotificationExtensionRequest(self.receivedRequest, with: self.bestAttemptContent)
                    contentHandler(bestAttemptContent)
                }
            }
            
            override func serviceExtensionTimeWillExpire() {
                // Called just before the extension will be terminated by the system.
                // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
                if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {
                    OneSignal.serviceExtensionTimeWillExpireRequest(self.receivedRequest, with: self.bestAttemptContent)
                    contentHandler(bestAttemptContent)
                }
            }
            
        }
        

        ObjC

        #import <OneSignal/OneSignal.h>
        
        #import "NotificationService.h"
        
        @interface NotificationService ()
        
        @property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
        @property (nonatomic, strong) UNNotificationRequest *receivedRequest;
        @property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;
        
        @end
        
        @implementation NotificationService
        
        - (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
            self.receivedRequest = request;
            self.contentHandler = contentHandler;
            self.bestAttemptContent = [request.content mutableCopy];
            
            //If your SDK version is < 3.5.0 uncomment and use this code:
            /*
            [OneSignal didReceiveNotificationExtensionRequest:self.receivedRequest
                               withMutableNotificationContent:self.bestAttemptContent];
            self.contentHandler(self.bestAttemptContent);
            */
            
            /* DEBUGGING: Uncomment the 2 lines below and comment out the one above to ensure this extension is excuting
                          Note, this extension only runs when mutable-content is set
                          Setting an attachment or action buttons automatically adds this */
            // NSLog(@"Running NotificationServiceExtension");
            // self.bestAttemptContent.body = [@"[Modified] " stringByAppendingString:self.bestAttemptContent.body];
            
            // Uncomment this line to set the default log level of NSE to VERBOSE so we get all logs from NSE logic
            //[OneSignal setLogLevel:ONE_S_LL_VERBOSE visualLevel:ONE_S_LL_NONE];
            [OneSignal didReceiveNotificationExtensionRequest:self.receivedRequest
                               withMutableNotificationContent:self.bestAttemptContent
                                           withContentHandler:self.contentHandler];
        }
        
        - (void)serviceExtensionTimeWillExpire {
            // Called just before the extension will be terminated by the system.
            // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
            
            [OneSignal serviceExtensionTimeWillExpireRequest:self.receivedRequest withMutableNotificationContent:self.bestAttemptContent];
            
            self.contentHandler(self.bestAttemptContent);
        }
        
        @end
        

        【讨论】:

        • 这个问题是针对ios中的Objective-c的。您的答案似乎适用于 Android 中的 Kotlin。
        • 不,它显然是适用于 iOS 的 Swift
        • 抱歉,刚刚发现。
        猜你喜欢
        • 1970-01-01
        • 2021-10-02
        • 1970-01-01
        • 1970-01-01
        • 2016-02-24
        • 1970-01-01
        • 2017-10-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多