2012-08-24 249 views
38

当我的应用程序是运行并接收推送通知,如果我点击该通知,应用启动 - 但是它不与提示用户我建立了Alert-View,询问他们是否想查看Notification的内容。它刚刚启动,并坐在那里。处理推送通知时,应用程序无法运行

的推送通知做的工作完美当应用程序运行 - 无论是作为活跃APP或者在后台 - 但没有正常工作时,应用程序是运行。

我试图注销launchOptions NSDictionary在application: didFinishLaunchingWithOptions:看看是什么加载它的带来 - 但它出现为“(空)”。所以它基本上不包含任何内容 - 这不合理,因为它不应该包含通知的负载?

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

编辑:这里是我使用的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 - 应用程序启动,但在启动时我没有收到推送通知警报。它只是坐在那里。

想我需要弄清楚排列在下...

+2

所以是你能得到通知时,你没有点击推送通知,并直接点击应用程序图标? –

+1

你有这个工作。 ?我的意思是当应用程序处于非运行状态时如何处理推送通知?如果如果您收到很多通知并且您没有打开该应用程序,那么您也不会点击系统的通知面板。你如何保留这些推动以便以后检索。 –

+0

你碰巧得到最后的排列工作吗? –

回答

33

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

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

我在'application:didFinishLaunchingWithOptions:'中做了一些类似于此的事情。我写道:'NSDictionary * launchDic = [launchOptions objectForKey:@“UIApplicationLaunchOptionsRemoteNotificationKey”]; NSLog(@“contains:%@”,launchDic);' - 我从NSLog得到的输出是“(NULL)”。但我会尝试使用'UILocalNotification'变量,就像你拥有它,而不是一个NSDictionary变量。也许这会有所作为。我会发布我的结果有点... – sirab333

+0

有趣的 - 请参阅我的问题中的“编辑”再次(顶部)更新您的建议刚刚做了什么... – sirab333

+0

尝试登录localNotif? – dianz

1

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

+0

我处理'applicationState' - 我的事业,我不想我的问题是太久之前没有提到它 - 但我会添加代码,以我的问题上去顶,很酷吧? – sirab333

7

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

对我而言;

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

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

,如果你重写didReceiveRemoteNotification 在这里你去

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

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

+2

您是否能够正常工作。 ?我的意思是当应用程序处于非运行状态时如何处理推送通知?如果如果您收到很多通知并且您没有打开该应用程序,那么您也不会点击系统的通知面板。你如何保留这些推动以便以后检索。 –

+0

谢谢你! :-) – ArturOlszak

+0

在哪里写这段代码? –

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

虽然这已经回答了,没有提供答案的实际工作正常。这是我能够工作的实现。

此代码放在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

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

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

0

斯威夫特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 
} 
1

我有同样的问题,但我终于可以用通知服务扩展处理推送通知时无效(不运行) 。这个解决方案是Apple Team Support推荐的,它只适用于iOS 10,我实现了它,它运行良好!我离开的链接:

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

这是程序:

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

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

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

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

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

  • 注:标识符App和标识符扩展应该有APP集团 相同的标识符。

  • 下载Xcode中上新的临时配置文件,并将它们与通知服务扩展关联。请确保你一切都安好。

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

  • 回来到项目导航并选择扩展的文件夹。打开.m文件。您将看到一个名为didReceiveNotificationRequest的方法:(UNNotificationRequest *)请求。到这个方法将创建与SuiteName不同NSUserDefaults的正好等于标识符的应用程序组是这样的:

    * NSUserDefaults的defaultsGroup = [[ALLOC NSUserDefaults的] initWithSuiteName:@ “标识符的应用程序组”];

  • 在这种方法中,获取通知的主体并将其保存到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"];  
    } 
    
  • 最后,为您的主项目的应用代表,在你的didFinishLaunchingWithOptions方法,恢复阵列到分享资源此代码:
  • NSUserDefaults *defaultsGroup = [[NSUserDefaults alloc] initWithSuiteName: @"Identifier for app group"]; 
    NSMutableArray *notifications = [[defaultsGroup objectForKey:@"notifications"] mutableCopy]; 
    
  • 享受它!
  • 我希望每一步都清楚。我将写一篇文章来实现这个解决方案,在图像中添加图片。另一点你应该考虑的是它不适用于无声推送通知。

    相关问题