iOS 8推送通知操作button – 当应用程序处于后台时,handleActionWithIdentifier中的代码不会始终运行

我将两个操作button添加到iOS 8上的推送通知:“ Acceptbutton和Denybutton。 这两个button都不会打开应用程序,但是不同的服务器请求将取决于按下哪个button。 这是我的设置:

 + (void)requestForPushNotificationToken { UIApplication *application = [UIApplication sharedApplication]; // if ios 8 or greater if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) { UIMutableUserNotificationAction *acceptAction = [[UIMutableUserNotificationAction alloc] init]; [acceptAction setActivationMode:UIUserNotificationActivationModeBackground]; [acceptAction setTitle:@"Accept"]; [acceptAction setIdentifier:@"ACCEPT_ACTION"]; [acceptAction setDestructive:NO]; [acceptAction setAuthenticationRequired:NO]; UIMutableUserNotificationAction *denyAction = [[UIMutableUserNotificationAction alloc] init]; [denyAction setActivationMode:UIUserNotificationActivationModeBackground]; [denyAction setTitle:@"Deny"]; [denyAction setIdentifier:@"DENY_ACTION"]; [denyAction setDestructive:NO]; [denyAction setAuthenticationRequired:NO]; UIMutableUserNotificationCategory *actionCategory = [[UIMutableUserNotificationCategory alloc] init]; [actionCategory setIdentifier:@"ACTIONABLE"]; [actionCategory setActions:@[acceptAction, denyAction] forContext:UIUserNotificationActionContextDefault]; NSSet *categories = [NSSet setWithObject:actionCategory]; UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert) categories:categories]; [application registerUserNotificationSettings:settings]; } else if ([application respondsToSelector:@selector(registerForRemoteNotificationTypes:)]) { // ios 7 or lesser UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound; [application registerForRemoteNotificationTypes:myTypes]; } } 

然后,在我的委托方法中,我指定用户按下其中一个操作button时要执行的操作:

 - (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void (^)())completionHandler { if ([identifier isEqualToString:@"ACCEPT_ACTION"]) { // Sending a request to the server here } else if ([identifier isEqualToString:@"DENY_ACTION"]) { // Sending a request to the server here } if (completionHandler) { completionHandler(); } } 

理想的情况是用户不需要在整个过程中启动应用程序; 按“ AcceptDeny将会对服务器进行不同的呼叫。 用上面的代码,我看到非常不稳定的行为与button操作:

  • 很多时候,当应用程序在后台并且根本没有服务器调用时,动作处理程序中的代码不会执行; 当发生这种情况时,如果我点击我的应用程序图标并启动我的应用程序,处理程序代码将立即在启动应用程序时运行。
  • 偶尔,处理程序代码被触发,一切正常。 服务器请求只要按下其中一个操作button即可完成。
  • 如果我在Xcode中放置断点并遍历处理程序代码,则成功率也是100%。 我不需要启动我的应用程序,处理程序代码在按下button时被执行。

任何人都可以请帮我找出是什么原因导致这种不稳定的行为? 提前致谢。

我终于找出原因了。 事实上,它有时是有效的,有时不应该提早给我提示。

根据苹果文档的application:handleActionWithIdentifier:forRemoteNotification:completionHandler: ::

此方法的实现应该执行与指定标识符关联的操作,并在完成后立即执行completionHandler参数中的块。 未能在实施结束时执行完成处理程序块将导致您的应用程序被终止。

我在application:handleActionWithIdentifier:forRemoteNotification:completionHandler程序的最后调用完成处理application:handleActionWithIdentifier:forRemoteNotification:completionHandler方法。 然而,我在我的处理程序代码中向服务器发送请求的事实意味着我end of implementation并不仅仅是方法的结尾; 我的真正目的在于回应我的要求。 我编写代码的方式,完成处理程序和callback是在两个不同的线程上,当完成处理程序在达到callback之前运行时,它将失败。

所以解决方法是将完成处理程序移入请求的callback方法,即真正的“实施结束”。 像这样的东西:

 [MyClient sendRequest:userInfo withSuccessBlock:^(id responseObject){ NSLog(@"Accept - Success"); if (completionHandler) { completionHandler(); } } withFailureBlock:^(NSError *error, NSString *responseString) { NSLog(@"Accept - Failure: %@",[error description]); if (completionHandler) { completionHandler(); } }]; 

在iOS8上,你需要打电话

 [application registerForRemoteNotifications]; 

application:didRegisterUserNotificationSettings: ::

 - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings { [application registerForRemoteNotifications]; }