19

I am banging my head. I am implementing push notification. Everything is working fine (push is received, badge is updated) but under iOS 13.3 the method application(_:didReceiveRemoteNotification:fetchCompletionHandler:) is not called when the app is in the background. If the app is in the foreground or using an iOS 12 device the method is called. I register for push notification in the following way:

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

The payload is set to the following

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

I tried adding "Remote notifications" and "Background processing" as app capabilities in all variations (only "Remote notifications"/"Background processing", without any of those capabilities, enabling both) without any change. I set the delegate for the UNUserNotificationCenter but again without success. I set the headers accordingly:

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

From the docs it states that this method is called even when the app is in background:

Use this method to process incoming remote notifications for your app. Unlike the application:didReceiveRemoteNotification: method, which is called only when your app is running in the foreground, the system calls this method when your app is running in the foreground or background.

What am I missing here for iOS 13?

4

8 回答 8

13

有没有设置

"content-available": 1

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

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

<key>UIBackgroundModes</key>
<array>
    <string>processing</string>
    <string>remote-notification</string>
</array>
于 2020-02-05T05:39:24.927 回答
5

这个委托方法: -

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

当我们单击 iOS 13 的通知并且应用程序处于后台时,将被调用。

于 2020-03-30T09:17:21.883 回答
4

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

事实证明,关于这个主题的 iOS 13 的文档不是 100%“有效”的。设备决定是否唤醒。尽管文档说明略有不同。

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

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

于 2020-03-22T14:02:28.433 回答
1

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

记得在 didFinishAlunchWithOptions

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

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

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

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

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

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

于 2020-09-24T02:42:11.770 回答
0

我有同样的问题。阅读: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(options: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!!!"
    },
}
于 2020-12-03T12:30:40.890 回答
0

我也面临同样的问题。

但是在我重新启动设备后它可以工作。

我正在使用 iOS 15.2

于 2022-02-25T01:34:26.860 回答
0

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

于 2020-03-20T17:41:45.157 回答
-1

您需要实现通知内容扩展

当我使用 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)
        }
    }
    
}

对象

#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
于 2020-04-30T10:04:21.180 回答