在APN之后不会在后台调用didReceiveRemoteNotification或didFinishLaunchingWithOptions

时间:2015-01-28 14:16:20

标签: ios iphone ipad

我发送以下APN

{“aps”:{“alert”:{“body”:“你好先生”,“action-loc-key”:“第二个按钮的标题”},“徽章”:1,“声音”: “默认”, “内容提供”:1}, “KEY1”: “值1”, “密钥2”: “值2”}

如您所见,我正在设置“content-available”:1作为有效载荷的一部分

当我的应用程序在前台运行时,一切正常。但是当我的应用程序在后台运行并且APN Notification出现时。通知正确显示在屏幕上。当我点击图标时,它不会调用didReceiveRemoteNotification或didFinishLaunchingWithOptions

我不知道我错过了什么。

我的代码如下:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
    UINavigationController *navigationController = [splitViewController.viewControllers lastObject];
    navigationController.topViewController.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem;
    splitViewController.delegate = self;


    // Register for Remote Push Notification 
    if ([application respondsToSelector:@selector(registerUserNotificationSettings:)])
    {
        UIUserNotificationType types = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert;
        UIUserNotificationSettings *mySetings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
        [[UIApplication sharedApplication] registerUserNotificationSettings:mySetings];
        [application registerForRemoteNotifications];
        NSLog(@"didFinishLaunchingWithOptions called");
    }



    //Accept push Notification when app is not open
    NSLog(@"Accept push Notification when app is not open");
    NSDictionary *remoteNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
    if (remoteNotif)
    {
        NSLog(@"Accept push Notification when app is not open if stat ");
        [self processRemoteNotificationApplicationStateActive:remoteNotif];
    }
    return YES;
}




-(void) sendDeviceToken:(NSString *) DeviceToken
{
    NSLog(@"sendDeviceToken called");

}


-(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    NSString *deviceTokenString = [[[NSString stringWithFormat:@"%@", deviceToken]      //convert NSData to NSString with stringWithFormat
                                    stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]]stringByReplacingOccurrencesOfString:@" " withString:@""]; // trim the "<>" then remove the spaces
    NSLog(@"deviceTokenString : %@", deviceTokenString);
    [self sendDeviceToken:deviceTokenString];
    NSLog(@"didRegisterForRemoteNotificationsWithDeviceToken called");
}

-(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
    NSLog(@"Error in registration. Error: %@", error);
}


- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
     NSLog(@"didReceiveRemoteNotification called");

    if ( application.applicationState == UIApplicationStateActive)
    {
        //App is already in the foreground
        NSLog(@"App is already in the foreground");
        [self processRemoteNotificationApplicationStateActive:userInfo];
    }
    else
    {
        NSLog(@"App was just brought from background to foreground");
        //App was just brought from background to foreground
        [self processRemoteNotificationApplicationStateActive:userInfo];
    }

}

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
     NSLog(@"didReceiveRemoteNotification fetchCompletionHandler called");

    if ( application.applicationState == UIApplicationStateActive)
    {
        //App is already in the foreground
        NSLog(@"App is already in the foreground");
        [self processRemoteNotificationApplicationStateActive:userInfo];
    }
    else
    {
        NSLog(@"App was just brought from background to foreground");
        //App was just brought from background to foreground
        [self processRemoteNotificationApplicationStateActive:userInfo];
    }

    completionHandler(UIBackgroundFetchResultNewData);
}



-(void)processRemoteNotificationApplicationStateActive:(NSDictionary *)userInfo
{


    [self.myDetailViewController performAPNUpdate];

}



- (void)applicationWillResignActive:(UIApplication *)application {
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
    NSLog(@"applicationWillResignActive called");

}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    NSLog(@"applicationDidEnterBackground called");
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
     NSLog(@"applicationWillEnterForeground called");
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    NSLog(@"applicationDidBecomeActive called");
}

- (void)applicationWillTerminate:(UIApplication *)application {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
     NSLog(@"applicationWillTerminate called");
}

#pragma mark - Split view

- (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController {
    if ([secondaryViewController isKindOfClass:[UINavigationController class]] && [[(UINavigationController *)secondaryViewController topViewController] isKindOfClass:[DetailViewController class]] && ([(DetailViewController *)[(UINavigationController *)secondaryViewController topViewController] detailItem] == nil)) {
        // Return YES to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
        return YES;
    } else {
        return NO;
    }
}

2 个答案:

答案 0 :(得分:4)

当您通过点按应用图标打开应用时,您无法获得有关推送通知的任何信息。在这种情况下,Apple希望您与自己的服务器同步。

因此,永远不会调用didReceiveRemoteNotification。如果您的应用程序被终止,将调用didFinishLaunchingWithOptions,但您不会获得有关推送通知的任何信息。

这种行为对我个人来说没有多大意义,但为了解决这个问题,我们在应用程序打开时创建了一个同步webservice的通知。

答案 1 :(得分:1)

当您的应用在后台运行并且收到content-available的推送时,将立即调用回调方法application:didReceiveRemoteNotification:fetchCompletionHandler:

当您点击警报并且此时打开应用程序时,将不会调用其他回调方法。这是预期的行为,因为application:didReceiveRemoteNotification:fetchCompletionHandler:已被调用。

如果您的日志根本没有显示application:didReceiveRemoteNotification:fetchCompletionHandler:,那将会很奇怪。

另外,请确保UIBackgroundModes包含remote-notification 无声推送