iOS 8的推送通知的操作按钮 - 在handleActionWithIdentifier code不经常运行应用程序时,在后台

iOS 8的推送通知的操作按钮 - 在handleActionWithIdentifier code不经常运行应用程序时,在后台

问题描述:

我在iOS 8添加两个动作按钮到我的推送通知。无论是按钮,将打开的应用程序,但不同的服务器请求将取决于哪个按钮是pressed进行。这里是我的设置:

I am adding two action buttons to my push notifications on iOS 8: an Accept button and a Deny button. Neither button will open the app, but different server requests will be made depending on which button is pressed. Here's my setup:

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

然后,在我的委托方法,我指定要采取的行动,当用户pressed的操作按钮之一:

Then, in my delegate method, I am specifying actions to be taken when user pressed one of the action buttons:

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

理想的情况是,用户不需要启动该应用的全过程; pressing 接受拒绝将对服务器不同的呼叫。通过上面的code,我看到很不稳定的行为与该按钮操作:

The ideal scenario is that the user does not need to launch the app in the whole process; pressing Accept or Deny will make different calls to the server. With the code above, I am seeing very unstable behaviors with the button actions:


  • 很多时候,当应用程序在后台,也没有调用服务器在所有在做的动作处理程序中的code不执行;发生这种情况时,如果我点击我的应用程序图标,启动我的应用程序,处理程序code将立即对启动应用程序运行。

  • 偶尔,处理code被触发,一切工作正常。服务器请求,只要我preSS的操作按钮中的一个进行。

  • 如果我把断点在我的X code,并通过处理器code步骤,成功率也是100%。我并不需要启动我的应用程序,而当按钮pssed $ P $处理code被执行。

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

Could anyone please help me figure out what's causing such unstable behavior? Thanks in advance.

我终于想通了的原因。它有时工作,有时不应该更快给我提示的事实。

I have finally figured out the reason. The fact that it sometimes works and sometimes doesn't should have given me the hint much sooner.

应用程序的苹果文档:handleActionWithIdentifier:forRemoteNotification:completionHandler:

您此方法的实现应该执行与指定的标识符相关的动作,一旦你完成执行在completionHandler参数块。失败在你执行结束,执行完成处理程序块将导致您的应用程序将被终止。

Your implementation of this method should perform the action associated with the specified identifier and execute the block in the completionHandler parameter as soon as you are done. Failure to execute the completion handler block at the end of your implementation will cause your app to be terminated.

我呼吁在应用程序的最终完成处理程序:handleActionWithIdentifier:forRemoteNotification:completionHandler 方法。然而,我在我的处理程序code发送请求到服务器的事实意味着执行我的到底是不是简单地在方法结束;我真正结束在于我的请求的回调中。路上我code吧,完成处理器和回调都在两个不同的线程,当完成处理程序运行到达回调之前,它会失败。

I am calling the completion handler at the end of the application:handleActionWithIdentifier:forRemoteNotification:completionHandler method. However, the fact that I am sending requests to the server in my handler code means that my end of implementation is not simply at the end of the method; my real end lies within the callback of my requests. The way I code it, completion handler and callback are on two different threads, and when completion handler runs before it reaches callback, it'll fail.

因此​​,解决方案是将完成处理程序移动到请求,即真正的执行结束的回调方法。事情是这样的:

So the solution is to move the completion handler into the callback methods of the request, i.e., the real "end of the implementation". Something like this:

[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();
    }
}];