在应用程序未运行时处理推送通知

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

当应用程序运行时,推送通知可以完美地工作 – 既可以作为活动应用程序,也可以在后台运行 – 但是当应用程序运行时没有任何工作正常。

我尝试在application: didFinishLaunchingWithOptions: launchOptions NSDictionary application: didFinishLaunchingWithOptions:查看加载它的是什么 – 但它出现为“(null)”。 所以它基本上不包含任何内容 – 这是不合理的,不应该包含通知的负载?

任何人有任何想法如何使推送通知工作,当他们到达而应用程序不运行?

编辑:这里是我在application: didReceiveRemoteNotification使用的代码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”的build议(下面),我修改了我的application: didFinishLaunchingWithOptions的代码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上select的内容,并据此进行操作。

这与didReceiveRemoteNotification逻辑一起工作完美。

但是,当应用程序没有运行,我发送一个推送通知,如果我不点击推送通知警报一到达,而是等待它淡出(发生在像3- 4秒), 然后我点击应用程序的图标 – 现在有1的BADGE – 应用程序启动,但我没有得到推送通知警报在启动时。 它只是坐在那里。

猜猜我需要弄清楚下面的排列

当你的应用程序没有运行或死亡,你点击推送通知此function将触发;

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

所以你应该这样处理

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

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

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

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

我试了@ dianz的回答,这不是我的工作,但我得到了答案。

在我的情况下,

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

尽pipe已经得到解答,但是所提供的答案实际上并不正确。 这是我的实现,我能够工作。

此代码进入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) }) } 

Objective-C的:

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

一对夫妇笔记:

  • 可能是由于iOS队列分配的方式,在被杀死之后启动应用程序时,根UIApplication.sharedApplication().window对象为零。 增加1毫秒的延迟解决了这个问题。 没有在Objective-C中testing这个

  • 需要投到[NSObject:AnyObject]以避免types冲突,但我没有尝试这么多; 在您自己的项目中实施时,请牢记在心。 Objective-C不需要这个。

  • 夸克只是一个有趣的小图书馆,我用在我的所有项目中,包含有用和常用的扩展和方法。 只需使用适合您应用需求的任何forms的延迟。

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

我有同样的问题,但我终于可以处理推送通知时,处于非活动(未运行)使用通知服务扩展。 这个解决scheme是由苹果团队支持推荐的,它只适用于iOS 10,我实现了它,它运行良好! 我离开链接:

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

这是程序:

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

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

  1. 有必要启用应用程序组以创build一个资源,您可以在其中保存和读取您的应用程序和扩展的信息。 点击“显示项目导航器”。 进入目标列表select你的主要项目。 然后,点击“Capabilities”并打开名为“App Groups”的选项。 请添加App Group的标识符以识别共享资源。 您应该为您创build的扩展目标执行相同的步骤(select扩展名的目标 – function – 在“应用程序组”中打开 – 为App组添加相同的标识符)

  2. 您应该将您的扩展程序的标识符添加到Apple开发人员网站以确定通知服务扩展,同时您还应该创build新的临时configuration文件(开发,AdHoc和/或生产)并将其与新的临时configuration文件相关联。

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

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

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

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

  3. 回到项目导航器,select你的扩展名的文件夹。 打开.m文件。 您将看到一个名为didReceiveNotificationRequest的方法:(UNNotificationRequest *)请求。 在这个方法中,你将创build一个与SuiteName完全相同的NSUserDefaults,就像这样:

    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. 好好享受!

我希望每一步都清楚。 我要写一篇文章来实现这个解决scheme与我的网页中的图像。 另一点,你应该考虑的是它不适用于无声推送通知。

尝试这个

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

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 }