45

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

推送通知在应用程序运行时可以完美运行——无论是作为活动应用程序还是在后台运行——但当应用程序运行时,没有任何东西可以正常工作。

我尝试注销launchOptionsNSDictionaryapplication: didFinishLaunchingWithOptions:以查看它带来的负载 - 但它显示为“(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 - 应用程序启动,但在启动时我根本没有收到推送通知警报。它只是坐在那里。

我想我接下来需要弄清楚这个排列......

4

8 回答 8

37

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

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

所以你应该这样处理它,

UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (localNotif) {
    NSString *json = [localNotif valueForKey:@"data"];
    // Parse your string to dictionary
}
于 2012-08-25T03:00:02.447 回答
11

最好是如果你覆盖didReceiveRemoteNotification 这里你去

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

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

于 2013-05-02T09:37:49.117 回答
7

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

就我而言;

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

NSDictionary *apnsBody = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (apnsBody) {
    // Do your code with apnsBody
}
于 2012-10-15T07:39:05.103 回答
5

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

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

于 2016-05-19T23:51:12.913 回答
4

我遇到了同样的问题,但我终于可以在使用通知服务扩展处于非活动状态(未运行)时处理推送通知。此解决方案由 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: @"identifier for app group"];

  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 方法中,使用以下代码将数组恢复到共享资源中:
NSUserDefaults *defaultsGroup = [[NSUserDefaults alloc] initWithSuiteName: @"Identifier for app group"];
NSMutableArray *notifications = [[defaultsGroup objectForKey:@"notifications"] mutableCopy];
  1. 好好享受!

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

于 2017-05-30T22:59:22.883 回答
1

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

于 2012-08-24T23:36:44.063 回答
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;
}
于 2014-12-10T02:56:21.943 回答
0

斯威夫特 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
}
于 2017-05-22T14:51:40.987 回答