didReceiveRemoteNotification: fetchCompletionHandler: open from icon vs push notification 收到远程通知:fetchCompletionHandler:从图标打开与推送通知

54

我正在尝试实现后台推送通知处理,但是我遇到了一个问题,即无法确定用户是从推送通知打开应用程序还是从图标打开应用程序。

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {

    //************************************************************
    // I only want this called if the user opened from swiping the push notification. 
    // Otherwise I just want to update the local model
    //************************************************************
    if(applicationState != UIApplicationStateActive) {
        MPOOpenViewController *openVc = [[MPOOpenViewController alloc] init];
        [self.navigationController pushViewController:openVc animated:NO];
    } else {
        ///Update local model
    }

    completionHandler(UIBackgroundFetchResultNewData);
}

使用这段代码,无论用户如何打开应用程序,应用程序都会打开到MPOOpenViewController视图控制器。我该如何使其仅在从通知滑动打开应用程序时推送视图控制器?

与相同的代码一起,在iOS 6上运行良好,但使用新的iOS 7方法后,它的行为不符合我的要求。

编辑:我现在正在尝试在iOS 7上运行该应用程序,并且我们不支持iOS 7之前的任何版本。我在方法的iOS 6版本中使用了完全相同的代码(没有完成处理程序),并且它的行为符合我的期望。您可以滑动通知,然后将调用此方法。如果您从图标打开,则永远不会调用该方法。


看起来没问题。当你从图标打开应用程序时,这个方法永远不会被调用。那么你面临的问题是什么,或者你还想实现什么? - Arpit Kulsreshtha
@ArpitKumarKulshrestha 这不是真的。由于应用程序支持后台远程通知,因此在应用程序仍处于后台时调用此方法。例如,如果我在此处设置断点并关闭应用程序,则当我收到推送时,它会在应用程序仍然关闭的情况下触发断点。这在iOS6中没有发生。 - mverderese
在您的问题中,"使用相同的代码,在iOS 6上可以正常工作,但使用新的iOS 7方法后,它不能按照我的要求运行。"。请指明它正在运行的iOS版本。 - Arpit Kulsreshtha
我正在iOS 7上运行此程序。我们不支持iOS 7之前的任何版本。 - mverderese
@Arpit,你完全没有理解我的问题。这个方法每次我收到推送时都会被调用,就像它应该做的那样。问题是在后台,一个新的视图被推到了导航栈上。我只希望在用户从通知中滑动时才发生这种情况(他们希望立即看到内容)。如果他们点击图标,他们应该被带到主屏幕,在那里我们有一个徽章告诉用户他们的反馈中有新内容。 - mverderese
显示剩余3条评论
3个回答

88

好的,我理解了。该方法实际上被调用两次(一次是在接收推送时,一次是用户与图标或通知进行交互时)。

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {

    if(application.applicationState == UIApplicationStateInactive) {

        NSLog(@"Inactive");

        //Show the view with the content of the push

        completionHandler(UIBackgroundFetchResultNewData);

    } else if (application.applicationState == UIApplicationStateBackground) {

        NSLog(@"Background");

        //Refresh the local model

        completionHandler(UIBackgroundFetchResultNewData);

    } else {

        NSLog(@"Active");

        //Show an in-app banner

        completionHandler(UIBackgroundFetchResultNewData);

    }
}

感谢Tim Castelijns为我们提供以下内容:

注意:它被调用两次的原因是由于Payload中包含content_available : 1。如果你删除这个键及其值,则只有在点击时才会运行。这不会解决每个人的问题,因为有些人需要该键为true。


3
非常感谢!!! 这非常有帮助!!!如果有人遇到实现后台远程通知的问题,请参考此页面:http://developer.xamarin.com/guides/cross-platform/application_fundamentals/backgrounding/part_3_ios_backgrounding_techniques/updating_an_application_in_the_background/ - Sandy D.
3
只需进行一点优化。如果您在每个条件语句中都会调用completionHandler(UIBackgroundFetchResultNewData);,您可以无条件地调用它并删除其中两行代码。 - Moebius
8
UIApplicationStateInactive状态的问题在于,它不仅会在用户通过通知与应用交互打开应用时发生,还会在应用处于“非活动”状态时发生,例如:当接收到短信/电话、显示通知中心或控制中心时。因此,在上述情况下,它会导致误报并导航到相应的视图。 - Tom Kraina
2
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Lukasz Czerwinski
4
注意:它被称为两次的原因是因为 PN 具有 content_available=true。如果删除该键或将其设置为 false,则只会运行一次。这不能解决所有人的问题,因为某些人需要该键为 true。 - Tim
显示剩余4条评论

12

@MikeV在Swift 3中的解决方案(但使用了switch语句):

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {

    switch application.applicationState {

    case .inactive:
        print("Inactive")
        //Show the view with the content of the push
        completionHandler(.newData)

    case .background:
        print("Background")
        //Refresh the local model
        completionHandler(.newData)

    case .active:
        print("Active")
        //Show an in-app banner
        completionHandler(.newData)
    }
}

9

@MikeV在Swift 2中的解决方案:

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {

    if(application.applicationState == UIApplicationState.Inactive)
    {
        print("Inactive")
        //Show the view with the content of the push
        completionHandler(.NewData)

    }else if (application.applicationState == UIApplicationState.Background){

        print("Background")
        //Refresh the local model
        completionHandler(.NewData)

    }else{

        print("Active")
        //Show an in-app banner
        completionHandler(.NewData)
    }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接