在App未运行时处理推送通知

时间:2012-08-24 20:35:58

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

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

当应用 正在运行时,推送通知可以完美 - 无论是作为活动应用还是在后台 - 但没有任何作用当应用 正在运行时正确无误。

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

任何人都有任何想法如何在应用程序未运行时如何使Push Notifications工作?

编辑:这是我在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");
}

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

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

UPDATE / EDIT#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 - 应用程序启动,但我根本没有得到推送通知警报它发射。它只是坐在那里。

猜猜我需要明确那个排列......

8 个答案:

答案 0 :(得分:36)

当您的应用未运行或被杀时,您点按推送通知此功能将触发;

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

所以你应该像这样处理它,

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

答案 1 :(得分:11)

最好是覆盖didReceiveRemoteNotification 你去吧

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

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

答案 2 :(得分:7)

我试过了@ dianz的回答,这对我没有用,但我从答案中得到了帮助。

就我而言;

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

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

答案 3 :(得分:3)

虽然已经回答了这个问题,但所提供的答案都没有真正起作用。这是我的实现,我能够工作。

此代码位于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只是一个有趣的小库,我在我的所有项目中使用它包含有用且常用的扩展和方法。只需使用适合您应用需求的任何形式的延迟。

答案 4 :(得分:3)

我遇到了同样的问题,但是当使用Notification Service Extension处于非活动状态(未运行)时,我终于可以处理推送通知。这个解决方案是由Apple Team Support推荐的,它仅适用于iOS 10,我实现了它并且运行良好!我留下链接:

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

这是程序:

  1. 为您的应用创建新的通知服务扩展程序。打开您的项目,然后按文件 - 新建 - 目标并在iOS部分选择“通知服务扩展”选项。放置扩展名和所需信息。之后,Xcode将添加两个使用Objective C语言的文件:.h和.m文件。
  2.   

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

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

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

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

    4.   

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

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

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

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

          

        NSUserDefaults * defaultsGroup = [[NSUserDefaults alloc]   initWithSuiteName:@“app group的标识符”];

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

      5. - (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恢复到共享资源中:
        2. NSUserDefaults *defaultsGroup = [[NSUserDefaults alloc] initWithSuiteName: @"Identifier for app group"];
          NSMutableArray *notifications = [[defaultsGroup objectForKey:@"notifications"] mutableCopy];
          
          1. 享受吧!
          2. 我希望每一步都清楚。我将写一篇帖子来实现这个解决方案,并在我的页面中显示图像。您应该考虑的另一点是它不适用于静音推送通知。

答案 5 :(得分:1)

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

答案 6 :(得分:0)

试试这个

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

答案 7 :(得分:0)

Swift 3 xCode 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
}