didReceiveRemoteNotification 未调用,iOS 10

didReceiveRemoteNotification not called, iOS 10

在 iOS 9.3 中,didReceiveRemoteNotification 方法会在以下两种情况下被调用。

1) 收到推送通知时 2) 当用户通过点击通知启动应用程序时。

但是在 iOS 10,我注意到 didReceiveRemoteNotification 方法在用户通过点击通知启动应用程序时 NOT 触发。只有在收到通知时才会调用它。因此,应用程序从通知启动后,我无法执行任何进一步的操作。

解决这个问题的方法是什么?有什么想法吗?

类型转换

对于 Swift3

-

示例参见 this

import the UserNotifications framework and add the UNUserNotificationCenterDelegate in Appdelegate

import UserNotifications

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate,UNUserNotificationCenterDelegate  


func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.

    //create the notificationCenter
    let center  = UNUserNotificationCenter.current()
    center.delegate = self
    // set the type as sound or badge
    center.requestAuthorization(options: [.sound,.alert,.badge,  .providesAppNotificationSettings]) { (granted, error) in
        // Enable or disable features based on authorization

        }
        application.registerForRemoteNotifications()

    return true
}


 func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
 // let chars = UnsafePointer<CChar>((deviceToken as NSData).bytes)
  var token = ""

  for i in 0..<deviceToken.count {
//token += String(format: "%02.2hhx", arguments: [chars[i]])
   token = token + String(format: "%02.2hhx", arguments: [deviceToken[i]])
  }

  print("Registration succeeded!")
  print("Token: ", token)
 }

 func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
  print("Registration failed!")
 }

receive the Notifications using this delegates

 func userNotificationCenter(_ center: UNUserNotificationCenter,  willPresent notification: UNNotification, withCompletionHandler   completionHandler: @escaping (_ options:   UNNotificationPresentationOptions) -> Void) {
    print("Handle push from foreground")
    // custom code to handle push while app is in the foreground
    print("\(notification.request.content.userInfo)")
 }

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
    print("Handle push from background or closed")
    // if you set a member variable in didReceiveRemoteNotification, you  will know if this is from closed or background
    print("\(response.notification.request.content.userInfo)")
}

func userNotificationCenter(_ center: UNUserNotificationCenter, openSettingsFor notification: UNNotification?) {
let navController = self.window?.rootViewController as! UINavigationController
let notificationSettingsVC = NotificationSettingsViewController()
navController.pushViewController(notificationSettingsVC, animated: true)
}

有关更多信息,您可以在 Apple 中查看 API Reference


objective C

AppDelegate.h 有这些行:

第一步

//Add Framework in your project "UserNotifications"
#import <UserNotifications/UserNotifications.h>  
@interface AppDelegate : UIResponder <UIApplicationDelegate,UNUserNotificationCenterDelegate>  

第 2 步

AppDelegate.m

  // define macro
  #define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)  
  #define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)  

第三步

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
application.applicationIconBadgeNumber = 0;
    if( SYSTEM_VERSION_LESS_THAN( @"10.0" ) ) {  
        [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound |    UIUserNotificationTypeAlert | UIUserNotificationTypeBadge |  UIUserNotificationTypeprovidesAppNotificationSettings) categories:nil]];  
        [[UIApplication sharedApplication] registerForRemoteNotifications];  

        //if( option != nil )  
        //{  
        //    NSLog( @"registerForPushWithOptions:" );  
        //}  
    } else {  
      UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];  
      center.delegate = self;  
      [center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error) {
        if( !error ) {
            // required to get the app to do anything at all about push notifications  
            [[UIApplication sharedApplication] registerForRemoteNotifications];
            NSLog( @"Push registration success." );  
        } else {
            NSLog( @"Push registration FAILED" );  
            NSLog( @"ERROR: %@ - %@", error.localizedFailureReason, error.localizedDescription );  
            NSLog( @"SUGGESTIONS: %@ - %@", error.localizedRecoveryOptions, error.localizedRecoverySuggestion );  
        }
        }];
    }

    return YES;
}

This will fire as a result of calling registerForRemoteNotifications:

 - (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken  
{  
// custom stuff we do to register the device with our AWS middleman  
 }

Then, when a user taps a notification, this fires:

This will fire in iOS 10 when the app is foreground or background, but not closed

 -(void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void  
  (^)(UIBackgroundFetchResult))completionHandler  
  {  
// iOS 10 will handle notifications through other methods  

if( SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO( @"10.0" ) )  
{  
  NSLog( @"iOS version >= 10. Let NotificationCenter handle this one." );  
 // set a member variable to tell the new delegate that this is background  
  return;  
}  
NSLog( @"HANDLE PUSH, didReceiveRemoteNotification: %@", userInfo );  

// custom code to handle notification content  

if( [UIApplication sharedApplication].applicationState == UIApplicationStateInactive )  
{  
  NSLog( @"INACTIVE" );  
  completionHandler( UIBackgroundFetchResultNewData );  
}  
else if( [UIApplication sharedApplication].applicationState == UIApplicationStateBackground )  
{  
  NSLog( @"BACKGROUND" );  
  completionHandler( UIBackgroundFetchResultNewData );  
}  
else  
{  
  NSLog( @"FOREGROUND" );  
  completionHandler( UIBackgroundFetchResultNewData );  
}  
}  

或使用

  - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo  
{  
[self application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:^(UIBackgroundFetchResult result) {  
}];  
}  

Then for iOS 10, these two methods:

- (void)userNotificationCenter:(UNUserNotificationCenter *)center  
    willPresentNotification:(UNNotification *)notification  
  withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler  
    {  
  NSLog( @"Handle push from foreground" );  
  // custom code to handle push while app is in the foreground  
    NSLog(@"%@", notification.request.content.userInfo);
   }  

- (void)userNotificationCenter:(UNUserNotificationCenter *)center  
didReceiveNotificationResponse:(UNNotificationResponse *)response  
  withCompletionHandler:(void (^)())completionHandler  
   {  
     NSLog( @"Handle push from background or closed" );  
     // if you set a member variable in didReceiveRemoteNotification, you  will know if this is from closed or background  
     NSLog(@"%@", response.notification.request.content.userInfo);
    }  

    - (void)userNotificationCenter:(UNUserNotificationCenter *)center 
   openSettingsForNotification:(UNNotification *)notification{
        Open notification settings screen in app
   }

我遇到了同样的问题。出现通知横幅,但未调用 -application:didReceiveRemoteNotification:fetchCompletionHandler: 方法。对我有用的解决方案是添加 - application:didReceiveRemoteNotification: 方法的实现并将调用转发给 -application:didReceiveRemoteNotification:fetchCompletionHandler::

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    [self application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:^(UIBackgroundFetchResult result){}];
}

Source.

Swift代码:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    // Override point for customization after application launch.

    if #available(iOS 10.0, *) {
        let center = UNUserNotificationCenter.currentNotificationCenter()
        center.delegate = self
    }

    // ...

    return true
}

@available(iOS 10.0, *)
public func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {        
    print(response.notification.request.content.userInfo)        
}

@available(iOS 10.0, *)
public func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    print(notification.request.content.userInfo)
}

这是一个 iOS 错误。它将在 iOS 10.1 中修复。但只需等待 10 月发布 10.1,而不是实施新库并稍后将其删除。

https://forums.developer.apple.com/thread/54322

顺便说一句,这个问题似乎已在 iOS 10.1 中修复。我在 10.1 上测试了我的应用程序,一切正常

工作版本 iOS11,Swift4,Xcode9。只需将以下代码复制粘贴到 AppDelegate 中。

import UIKit
import UserNotifications
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate,UNUserNotificationCenterDelegate {

    var window: UIWindow?


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        if #available(iOS 10, *)
        { // iOS 10 support
            //create the notificationCenter
            let center = UNUserNotificationCenter.current()
            center.delegate = self
            // set the type as sound or badge
            center.requestAuthorization(options: [.sound,.alert,.badge]) { (granted, error) in
                if granted {
                    print("Notification Enable Successfully")
                }else{
                    print("Some Error Occure")
                }
            }
            application.registerForRemoteNotifications()
        }
        else if #available(iOS 9, *)
        {
            // iOS 9 support
            UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.badge, .sound, .alert], categories: nil))
            UIApplication.shared.registerForRemoteNotifications()
        }
        else if #available(iOS 8, *)
        {
            // iOS 8 support
            UIApplication.shared.registerUserNotificationSettings(UIUserNotificationSettings(types: [.badge, .sound,
                                                                                                     .alert], categories: nil))
            UIApplication.shared.registerForRemoteNotifications()
        }
        else
        { // iOS 7 support
            application.registerForRemoteNotifications(matching: [.badge, .sound, .alert])
        }
        return true
    }


    //get device token here
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken
        deviceToken: Data)
    {
        let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
        let token = tokenParts.joined()
        print("Registration succeeded!")
        print("Token: ", token)

        //send tokens to backend server
    }

    //get error here
    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error:
        Error) {
        print("Registration failed!")
    }

    //get Notification Here below ios 10
    func application(_ application: UIApplication, didReceiveRemoteNotification data: [AnyHashable : Any]) {
        // Print notification payload data
        print("Push notification received: \(data)")
    }

    //This is the two delegate method to get the notification in iOS 10..
    //First for foreground
    @available(iOS 10.0, *)
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (_ options:UNNotificationPresentationOptions) -> Void)
    {
        print("Handle push from foreground")
        // custom code to handle push while app is in the foreground
        print("\(notification.request.content.userInfo)")
    }
    //Second for background and close
    @available(iOS 10.0, *)
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response:UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void)
    {
        print("Handle push from background or closed")
        // if you set a member variable in didReceiveRemoteNotification, you will know if this is from closed or background
        print("\(response.notification.request.content.userInfo)")
    }


}

swift 4,如果你使用的是ios11或者xcode版本大于9.0 那么你必须使用 UNUserNotification delegate 方法来调用 didReceiveRemoteNotification

  func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {

//Your code to handle events

}

Swift 4 和 IOS 12.

虽然可能有多种原因(已在其他答案中提到)为什么会发生此问题,但就我个人而言,解决方案与发送推送通知时的有效负载有关:

您需要将 json 负载上的 “内容可用” 键设置为 1。

例如:

{"aps":{"alert":"Test", "content-available":1, "badge":1,"sound":"default"}}

我认为这是设计使然,我目前正在研究 iOS 14,同样的情况也发生了。我意识到,如果您启用 'Background Fetching' 功能并实现 [didReceiveRemoteNotification: withCompletionHandler:] «您可能也想使用 [performBackgroundFetch:] 这样做»,那么您可以在该委托方法中设置一个断点并调试远程通知