【问题标题】:didReceiveRemoteNotification not called, iOS 10未调用 didReceiveRemoteNotification,iOS 10
【发布时间】:2023-03-25 09:41:01
【问题描述】:

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

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

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

应该如何解决这个问题?有什么想法吗?

【问题讨论】:

标签: ios objective-c swift3 apple-push-notifications


【解决方案1】:

我认为这是按设计完成的,我目前正在开发 iOS 14,并且发生了同样的情况。我意识到,如果您启用“后台获取”功能并实现 [didReceiveRemoteNotification: withCompletionHandler:] «您可能还想使用 [performBackgroundFetch:] 来执行此操作»,那么您可以在该委托方法中设置断点并调试远程通知

【讨论】:

    【解决方案2】:

    Swift 4 和 IOS 12。

    虽然可能有多种原因(已在其他答案中提到)导致此问题发生,但在我个人的情况下,解决方案与发送推送通知时的有效负载有关:

    您需要将 json 负载上的 "content-available" 键设置为 1。

    例如:

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

    【讨论】:

      【解决方案3】:

      工作版本iOS 11、Swift 4、Xcode 9。只需将以下代码复制粘贴到 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)")
          }
      
      
      }
      

      【讨论】:

      • 您调用 application.registerForRemoteNotifications() 不会等待 requestAuthorization。好吗?
      【解决方案4】:

      类型转换

      适用于 Swift3

      -

      样品见this

      导入UserNotifications框架并在Appdelegate中添加UNUserNotificationCenterDelegate

      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!")
       }
      

      使用此委托接收通知

       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


      目标 C

      AppDelegate.h 有以下几行:

      第一步

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

      第二步

      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;
      }
      

      这将作为调用 registerForRemoteNotifications 的结果触发:

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

      然后,当用户点击通知时,会触发:

      当应用程序处于前台或后台但未关闭时,这将在 iOS 10 中触发

       -(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) {  
      }];  
      }  
      

      那么对于iOS 10,这两种方法:

      - (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
         }
      

      【讨论】:

      • 请不要跨多个问题重新发布答案。每个答案都应针对特定问题进行定制,并且在适用的情况下应将问题标记为重复。
      • 您不需要使用 UserNotificationCenter 请求授权。只需注册为代表就足以解决问题。
      • 抱歉,当我收到 didReceive 通知时如何获取 userInfo?
      • @Svitlana - 你可以在这里找到 NSLog(@"%@", response.notification.request.content.userInfo);
      • 您是否还需要在后台模式中启用“远程通知”。实际上,我对启用图像中显示的“推送通知”与启用here 中的“远程通知”之间的区别感到有些困惑。如果我只照你说的做而不启用“远程通知”会怎样?
      【解决方案5】:

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

        func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
      
      //Your code to handle events
      
      }
      

      【讨论】:

        【解决方案6】:

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

        【讨论】:

          【解决方案7】:

          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)
          }
          

          【讨论】:

            【解决方案8】:

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

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

            【讨论】:

              【解决方案9】:

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

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

              Source.

              【讨论】:

              • 此代码对我不起作用。我正在 iOS 15.0 模拟器上对其进行测试。收到通知 -> 出现横幅 -> didReceiveRemoteNotification 未调用。
              • @nitin.agam 推送通知在 iPhone 模拟器上不起作用
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2017-03-28
              • 2020-06-30
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2020-05-07
              • 1970-01-01
              相关资源
              最近更新 更多