【问题标题】:Handling Push Notifications when App is NOT running应用未运行时处理推送通知
【发布时间】:2012-08-20 10:10:46
【问题描述】:

当我的应用正在运行并收到推送通知时,如果我点击该通知,应用就会启动 - 但它不会提示用户使用我设置的警报视图,询问他们是否要查看通知的内容。它刚刚启动,然后就坐在那里。

当应用程序运行时,推送通知确实完美工作 - 无论是作为活动应用程序还是在后台运行 - 但没有任何效果当应用没有运行时正确。

我尝试在application: didFinishLaunchingWithOptions: 中注销launchOptions NSDictionary 以查看它带来了什么负载 - 但它显示为“(null)”。所以它基本上什么都不包含 - 这没有意义,因为它不应该包含通知的负载吗?

有人知道如何在应用未运行时让推送通知工作吗?

编辑:这是我在application: didReceiveRemoteNotification 中使用的代码,只是为了看看是什么:

if (UIApplicationStateBackground) {

    NSLog(@"===========================");
    NSLog(@"App was in BACKGROUND...");
}
else if (UIApplicationStateActive == TRUE) {
    NSLog(@"===========================");
    NSLog(@"App was ACTIVE");
}
else {
    [[UIApplication sharedApplication] setApplicationIconBadgeNumber: 99]; 
    UIAlertView *BOOM = [[UIAlertView alloc] initWithTitle:@"BOOM"
                                                   message:@"app was INACTIVE"
                                                  delegate:self
                                         cancelButtonTitle:@"a-ha!"
                                         otherButtonTitles:nil];
    [BOOM show];
    NSLog(@"App was NOT ACTIVE");
}

所以这应该处理所有应用程序的状态 - 但事实并非如此。推送通知仅在应用程序运行时有效 - 无论是在后台还是在前台......

================================================ =

更新/编辑#2: 根据“@dianz”的建议(如下),我修改了application: didFinishLaunchingWithOptions 的代码以包含以下内容:

UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (localNotif) {
    NSString *json = [localNotif valueForKey:@"data"]; 

    UIAlertView *bam = [[UIAlertView alloc] initWithTitle:@"appDidFinishWithOptions"
                                                  message:json   
                                                 delegate:self
                                        cancelButtonTitle:@"cool"
                                        otherButtonTitles:nil];
    [bam show];

}

这确实使 AlertView 框出现,但似乎没有有效负载:AlertView 的标题显示(“appDidFinishWithOptions”),但 json NSString 出现 EMPTY... 将继续调整...

=======================

编辑 #3 - 它现在工作几乎 100%
所以,在didFinishLaunchingWithOptions

UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
    if (localNotif) {
        // Grab the pushKey:
        pushKey = [localNotif valueForKey:@"pushKey"];
        // "pushKey" is an NSString declared globally
        // The "pushKey" in the "valueForKey" statement is part of my custom JSON Push Notification pay-load.
        // The value of pushKey will always be a String, which will be the name of the 
        // screen I want the App to navigate to. So when a Notification arrives, I go
        // through an IF statement and say "if pushKey='specials' then push the                                      
        // specialsViewController on, etc.

        // Here, I parse the "alert" portion of my JSON Push-Notification:
        NSDictionary *tempDict = [localNotif valueForKey:@"aps"];
        NSString *pushMessage = [tempDict valueForKey:@"alert"];


        // Finally, ask user if they wanna see the Push Notification or Cancel it:
        UIAlertView *bam = [[UIAlertView alloc] initWithTitle:@"(from appDidFinishWithOptions)"
                                                      message:pushMessage  
                                                     delegate:self
                                            cancelButtonTitle:@"Cancel"
                                            otherButtonTitles:@"View Info", nil];
        [bam show];

    }

接下来我实现alertView: clickedButtonAtIndex 方法以查看用户在 AlertView 上选择的内容并进行相应操作。

这与didReceiveRemoteNotification 逻辑一起完美运行。

但是......当应用程序未运行时,我向它发送推送通知,如果我没有在推送通知警报到达时立即单击它,而是等待它淡出(这发生在像 3-4 秒),然后然后我点击应用程序的图标 - 现在它上面的 BADGE 为 1 - 应用程序启动,但我根本没有收到推送通知警报它启动。它就在那里。

猜猜我接下来需要弄清楚那个排列...

【问题讨论】:

  • 那么当您不点击推送通知并直接点击应用程序图标时,您是否能够收到通知?
  • 你能做到吗? ?我的意思是当应用程序处于非运行状态时如何处理推送通知?如果您收到许多通知并且您没有打开应用程序,也没有点击系统的通知面板怎么办。您如何保留这些推送以供以后检索。
  • 你有没有碰巧得到最后的排列工作?
  • 这在 iOS 8.X 中有效吗?通过我的实验,除非用户点击通知,否则内容将永远丢失(即它不像它被存储并且可以在用户启动应用程序时检索)。此外,我看到的奇怪的事情是,即使我终止应用程序并在此之后单击传入通知,通知也会在 - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler: (void (^)(UIBackgroundFetchResult 结果))handler
  • 你解决了吗? @sirab33,我也需要回答这个问题吗?当应用程序未运行和通知进来时,我仍然无法获取数据,不点击它,仍然无法获取数据。任何帮助?

标签: iphone push-notification apple-push-notifications


【解决方案1】:

尝试转到didReceiveRemoteNotification 方法并在那里处理它。在那里,您可以通过对 applicationState 执行条件来检查应用程序状态,例如检查它是 UIApplicationStateActive 还是其他。

【讨论】:

  • 我正在处理applicationState - 我之前没有提到它,因为我不希望我的问题太长 - 但我会将该代码添加到我的问题中,很酷?
【解决方案2】:

当您的应用没有运行或被终止并且您点击推送通知时,此功能将触发;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

所以你应该这样处理它,

UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (localNotif) {
    NSString *json = [localNotif valueForKey:@"data"];
    // Parse your string to dictionary
}

【讨论】:

  • 我在application: didFinishLaunchingWithOptions: 中做了与此类似的事情非常。我写道:NSDictionary *launchDic = [launchOptions objectForKey:@"UIApplicationLaunchOptionsRemoteNotificationKey"]; NSLog(@"contains: %@", launchDic); - 我从NSLog 得到的输出是“(NULL)”。但我会尝试使用 UILocalNotification 变量,就像你拥有它一样,而不是 NSDictionary 变量。也许这会有所作为。我稍后会发布我的结果...
  • 很有趣 - 再次查看我的问题中的“编辑”(顶部)以了解您的建议刚刚做了什么......
  • dianz,我做了一些更改 - 请参阅我的问题底部的 EDIT #3(顶部)
  • 你能做到吗? ?我的意思是当应用程序处于非运行状态时如何处理推送通知?如果您收到许多通知并且您没有打开应用程序,也没有点击系统的通知面板怎么办。您如何保留这些推送以供以后检索。
  • 在 iOS 10 上运行良好。
【解决方案3】:

我尝试了@dianz 的答案,它对我不起作用,但我从答案中得到了帮助。

就我而言;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

NSDictionary *apnsBody = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (apnsBody) {
    // Do your code with apnsBody
}

【讨论】:

    【解决方案4】:

    最好覆盖didReceiveRemoteNotification 给你

    NSDictionary * pushNotificationPayload = [launchOptions valueForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
    if(pushNotificationPayload) {
        [self application:application didReceiveRemoteNotification:pushNotificationPayload];
    }
    

    这将再次触发didReceiveRemoteNotification 方法,并且您的push notification 代码将像在应用程序运行时一样执行。

    【讨论】:

    • 你能做到吗? ?我的意思是当应用程序处于非运行状态时如何处理推送通知?如果您收到许多通知并且您没有打开应用程序,也没有点击系统的通知面板怎么办。您如何保留这些推送以供以后检索。
    • - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    • 你从哪里得到 pushNotificationPayload?
    • @Rob85 应该是 [self application:application didReceiveRemoteNotification:aPushNotification];
    【解决方案5】:

    试试这个

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    
        // Override point for customization after application launch.
        self.window.backgroundColor = [UIColor whiteColor];
        [self.window makeKeyAndVisible];
    
        //register notifications
        if([application respondsToSelector:@selector(registerUserNotificationSettings:)]) // ios 8
        {
            [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
            [application registerForRemoteNotifications];
        }
        else // ios 7
        {
            [[UIApplication sharedApplication] registerForRemoteNotificationTypes:UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge];
        }
    
        // open app from a notification
        NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
    
        if (notification) 
        {
            //your alert should be here
        }
    
        // Set icon badge number to zero
        application.applicationIconBadgeNumber = 0;
    
        return YES;
    }
    

    【讨论】:

      【解决方案6】:

      尽管已经回答了这个问题,但所提供的答案实际上都没有正确工作。这是我能够开始工作的实现。

      此代码进入application:didFinishLaunchingWithOptions:

      斯威夫特:

      if let options = launchOptions, notification = options[UIApplicationLaunchOptionsRemoteNotificationKey] as? [NSObject : AnyObject] {
          // NOTE: (Kyle Begeman) May 19, 2016 - There is an issue with iOS instantiating the UIWindow object. Making this call without
          // a delay will cause window to be nil, thus preventing us from constructing the application and assigning it to the window.
          Quark.runAfterDelay(seconds: 0.001, after: {
              self.application(application, didReceiveRemoteNotification: notification)
          })
      }
      

      目标-C:

      if (launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]) {
          [self application:application didReceiveRemoteNotification:launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]];
      }
      

      几个注意事项:

      • 可能由于 iOS 队列分配的方式,根 UIApplication.sharedApplication().window 对象在被杀死后启动应用程序时为 nil。添加 1 毫秒延迟修复了此问题。没有在 Objective-C 中测试过这个

      • 强制转换为 [NSObject: AnyObject] 是为了避免出现类型冲突,但我没有做太多实验;在您自己的项目中实施时请牢记这一点。 Objective-C 不需要这个。

      • Quark 只是我在所有项目中使用的一个有趣的小库,其中包含有用且常用的扩展和方法。只需使用适合您应用程序需求的任何形式的延迟即可。

      【讨论】:

        【解决方案7】:

        Swift 3xCode 8.3.2

        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
            // your code here
        
            // Check if app was not running in background and user taps on Push Notification
            // This will perform your code in didReceiveRemoteNotification where you should handle different application states
            if let options = launchOptions, let notification = options[UIApplicationLaunchOptionsKey.remoteNotification] as? [NSObject : AnyObject] {
                self.application(application, didReceiveRemoteNotification: notification)
            }
        
            return true
        }
        

        【讨论】:

          【解决方案8】:

          我遇到了同样的问题,但我终于可以使用通知服务扩展在非活动(未运行)时处理推送通知。此解决方案由 Apple 团队支持推荐,仅适用于 iOS 10,我实施了它并且效果很好!我留下链接:

          https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/ModifyingNotifications.html

          这是程序:

          1. 为您的应用创建一个新的通知服务扩展。打开您的项目并按 File - New - Target 并在 iOS 部分选择“通知服务扩展”选项。输入扩展名和所需的信息。之后,Xcode 会用 Objective C 语言添加两个文件:.h 和 .m 文件。

          注意:考虑您将使用三个标识符: 1) 您的应用的标识符(您已经拥有) 2) 扩展程序的标识符(您将创建) 3) 应用组标识符。 (您将创建)

          1. 需要启用 App Groups 以创建资源,您可以在其中保存和读取您的应用程序和扩展程序的信息。单击“显示项目导航器”。在目标列表中选择您的主项目。然后,单击“功能”并打开名为“应用程序组”的选项。请添加 App Group 的标识符以识别共享资源。您应该对您创建的扩展目标执行相同的步骤(选择扩展目标 - 功能 - 在“应用程序组”处打开 - 为应用程序组添加相同的标识符)

          2. 您应该将您的扩展的标识符添加到 Apple 开发者网站以识别通知服务扩展,您还应该创建新的临时配置文件(开发、临时和/或生产)并将其与新的临时配置文件相关联个人资料。

          3. 在两个标识符(应用程序和扩展程序)上,您应该编辑它们并在它们中启用“应用程序组”服务。您应该将应用程序组的标识符添加到应用程序组服务中。

          注意:应用程序标识符和扩展程序标识符应该具有 应用组的标识符相同。

          1. 在 Xcode 上下载新的临时配置文件并将它们与您的通知服务扩展相关联。请确保您一切正常。

          2. 之后,进入您的应用和扩展程序的“功能”,打开“应用组”部分并更新它们。这三个步骤 - 1) 将 App Groups 权利添加到您的权利文件,2) 将 App Groups 功能应用到您的 App ID 和 3) 将 App Groups 添加到您的 App ID - 应该检查。

          3. 返回项目导航器并选择您的扩展文件夹。打开 .m 文件。您将看到一个名为 didReceiveNotificationRequest:(UNNotificationRequest *)request 的方法。在此方法中,您将创建一个不同的 NSUserDefaults,其 SuiteName 与应用组的标识符完全相同,如下所示:

            NSUserDefaults *defaultsGroup = [[NSUserDefaults alloc] initWithSuiteName:@"应用组标识符"];

          4. 在同样的方法中,获取通知正文并将其保存到 NSMutableArray 中,然后将其保存在共享资源中。像这样:

          - (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler{
              self.contentHandler = contentHandler;
              self.bestAttemptContent = [request.content mutableCopy];
          
              NSMutableArray *notifications = [NSMutableArray new];
              NSUserDefaults *defaultsGroup = [[NSUserDefaults alloc] initWithSuiteName: @"Identifier for app group"];
              notifications = [[defaultsGroup objectForKey:@"notifications"] mutableCopy];
              if (notifications != nil){
                  [notifications addObject:self.bestAttemptContent.userInfo];
              }else{
                  notifications = [NSMutableArray new];
                  [notifications addObject:self.bestAttemptContent.userInfo];
              }
              [defaultsGroup setObject:notifications forKey:@"notifications"];    
          }
          
          1. 最后,进入主项目的 App Delegate,在 didFinishLaunchingWithOptions 方法中,使用以下代码将 Array 恢复到共享资源中:
          NSUserDefaults *defaultsGroup = [[NSUserDefaults alloc] initWithSuiteName: @"Identifier for app group"];
          NSMutableArray *notifications = [[defaultsGroup objectForKey:@"notifications"] mutableCopy];
          
          1. 尽情享受吧!

          我希望每一步都清楚。我要写一篇文章来在我的页面中使用图像来实现这个解决方案。您应该考虑的另一点是它不适用于静默推送通知。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-06-14
            • 1970-01-01
            • 2018-11-14
            • 1970-01-01
            • 2016-11-25
            相关资源
            最近更新 更多