iOS 远程推送APNS从0至发布-代码集成篇

说明

  • 此文以极光推送来举例,相信其它第三方原理相同.

  • 支持到 iOS10.2

  • 全部为笔者今天测试结论,如有变化,请注意日期

  • 测试环境:

  • Xcode 8.2,

  • iOS 10.2 & iOS 9.2.1

  • 本系列包括三大部分:

    • 证书集成篇 http://www.jianshu.com/p/f5ffb49e6173
    • 代码集成篇 http://www.jianshu.com/p/9e2464be0fd5
    • 极光推送&真机测试篇 http://www.jianshu.com/p/6812a8a84d31

头文件

#import "AppDelegate.h"
#import "JPUSHService.h"

// iOS10注册APNs所需头文件
#ifdef NSFoundationVersionNumber_iOS_9_x_Max
#import 
#endif

//JPush
static NSString *const appKey = @"5a6e94518f6bd85ba173cf77";
static NSString *const channel = @"App Store";
static BOOL const isProduction = YES;

@interface AppDelegate ()

@end

辅助测试的UI代码:


#pragma mark --------------------------------------------------------
#pragma mark observe & addView
- (void)networkDidReceiveMsg:(NSNotification *)note{
    
//    NSDictionary * userInfo = [note userInfo];
//    NSString *content = [userInfo valueForKey:@"content"];
//    NSDictionary *extras = [userInfo valueForKey:@"extras"];
//    NSString *customizeField1 = [extras valueForKey:@"customizeField1"]; //服务端传递的Extras附加字段,key是自己定义的
    
    NSString *text = @"NSNotification";
    [self addTestViewRed:text];
}

- (void)addTestViewYellow:(NSString *)text{
    UIView *testView = [[UIView alloc] init];
    testView.backgroundColor = [[UIColor yellowColor] colorWithAlphaComponent:0.5];
    testView.yh_size = CGSizeMake(100, 100);
    testView.center = [UIApplication sharedApplication].keyWindow.center;
    UITextView *textView = [[UITextView alloc] init];
    textView.bounces = YES;
    textView.text = text;
    textView.frame = testView.bounds;
    textView.yh_height -= 20;
    [testView addSubview:textView];
    [self.window.rootViewController.view addSubview:testView];
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(testGes:)];
    [testView addGestureRecognizer:tap];
}
- (void)addTestViewRed:(NSString *)text{
    UIView *testView = [[UIView alloc] init];
    testView.backgroundColor = [[UIColor redColor] colorWithAlphaComponent:0.5];
    testView.yh_size = CGSizeMake(100, 100);
    testView.center = self.window.center;
    UITextView *textView = [[UITextView alloc] init];
    textView.bounces = YES;
    textView.text = text;
    textView.frame = testView.bounds;
    textView.yh_height -= 20;
    [testView addSubview:textView];
    [self.window.rootViewController.view addSubview:testView];
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(testGes:)];
    [testView addGestureRecognizer:tap];
}
- (void)testGes:(UITapGestureRecognizer *)tapGes{
    
    [tapGes.view removeFromSuperview];
}

注册代码:


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    application.applicationIconBadgeNumber = 0;
    //设置推送
    [self setupJPush:launchOptions];
    return YES;
}

//建立JPush
- (void)setupJPush:(NSDictionary *)launchOptions{
    
    
    //Required
    if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
        JPUSHRegisterEntity * entity = [[JPUSHRegisterEntity alloc] init];
        entity.types = UNAuthorizationOptionAlert|UNAuthorizationOptionBadge|UNAuthorizationOptionSound;
        [JPUSHService registerForRemoteNotificationConfig:entity delegate:self];
    }
    else if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
        //可以添加自定义categories
        [JPUSHService registerForRemoteNotificationTypes:(UIUserNotificationTypeBadge |
                                                          UIUserNotificationTypeSound |
                                                          UIUserNotificationTypeAlert)
                                              categories:nil];
    } else {
        //categories 必须为nil
        [JPUSHService registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge |
                                                          UIRemoteNotificationTypeSound |
                                                          UIRemoteNotificationTypeAlert)
                                              categories:nil];
    }
    
    //Required
    [JPUSHService setupWithOption:launchOptions appKey:appKey
                          channel:channel
                 apsForProduction:isProduction];
    
    
    ///极光文档:只有在前端运行的时候才能收到自定义消息的推送。
   //笔者并没有测试到执行这个通知方法
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkDidReceiveMsg:) name:kJPFNetworkDidReceiveMessageNotification object:nil];
    
    if (launchOptions) {
        
        NSString *alert = launchOptions[@"aps"][@"alert"];
        NSString *string = [NSString stringWithFormat:@"%@%@", @"有通知: setupJPush", alert];
        [self addTestViewRed:string];
    }
    
}

处理推送的各方法

#pragma mark ------------------------------------------
#pragma mark JPush methods
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    
    /// Required - 注册 DeviceToken
    [JPUSHService registerDeviceToken:deviceToken];
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    
    NSString *alert = userInfo[@"aps"][@"alert"];
    if (application.applicationState == UIApplicationStateActive) {
        YHLog(@"active,接收到远程通知userInfo--");
        
        application.applicationIconBadgeNumber = 0;
        
        ///接收到远程通知后的操作
        NSString *text = [NSString stringWithFormat:@"%@%@", @"fetchCompletionHandler -- UIApplicationStateActive---", alert];
        [self addTestViewRed:text];
        
    }else if(application.applicationState == UIApplicationStateBackground){
        //程序处于后台,推送时不勾选`content avaliable` 时没有这个模式
        NSString *text = [NSString stringWithFormat:@"%@%@", @"fetchCompletionHandler -- UIApplicationStateBackground---", alert];
        [self addTestViewRed:text];
        
    }else if (application.applicationState == UIApplicationStateInactive){
        YHLog(@"UIApplicationStateInactive");
        
        ///接收到远程通知后的操作
        NSString *text = [NSString stringWithFormat:@"%@%@", @"fetchCompletionHandler -- UIApplicationStateInactive---", alert];

        [self addTestViewRed:text];
    }
    
    //     IOS 7 Support Required
    [JPUSHService handleRemoteNotification:userInfo];
    completionHandler(UIBackgroundFetchResultNewData);
}

#pragma mark JPUSHRegisterDelegate
// iOS 10 Support
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger))completionHandler {
    
    // Required
    NSDictionary * userInfo = notification.request.content.userInfo;
    if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        [JPUSHService handleRemoteNotification:userInfo];
    }
    completionHandler(UNNotificationPresentationOptionAlert); // 需要执行这个方法,选择是否提醒用户,有Badge、Sound、Alert三种类型可以选择设置
    
    NSString *text = [NSString stringWithFormat:@"%@%@", @"JPUSHRegisterDelegate -- willPresentNotification---", userInfo[@"aps"][@"alert"]];
    [self addTestViewYellow:text];
}

// iOS 10 Support
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
    
    // Required
    NSDictionary * userInfo = response.notification.request.content.userInfo;
    if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        [JPUSHService handleRemoteNotification:userInfo];
    }
    completionHandler();  // 系统要求执行这个方法
    
    NSString *text = [NSString stringWithFormat:@"%@%@", @"JPUSHRegisterDelegate -- didReceiveNotificationResponse---", userInfo[@"aps"][@"alert"]];
    [self addTestViewYellow:text];
    
}

不同情况下调用的方法总结

iOS 10

1.应用在前台,

1.1 没有设置 content-available ,
  • 1.1.1 调用JPUSHRegisterDelegate 方法:
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center 
willPresentNotification:(UNNotification *)notification 
withCompletionHandler:(void (^)(NSInteger))completionHandler
  • 1.1.2 如果此时点击了通知栏,会再调用下 JPUSHRegisterDelegate 方法:
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center 
didReceiveNotificationResponse:(UNNotificationResponse *)response 
withCompletionHandler:(void (^)())completionHandler
1.2 设置了 content-available ,
  • 1.2.1 先调用方法, 其中application.applicationState == UIApplicationStateActive
- (void)application:(UIApplication *)application 
didReceiveRemoteNotification:(NSDictionary *)userInfo 
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
  • 1.2.2 再调用方法 JPUSHRegisterDelegate 方法:
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center 
willPresentNotification:(UNNotification *)notification 
withCompletionHandler:(void (^)(NSInteger))completionHandler
  • 1.2.3 如果此时点击了通知,会再调用下 JPUSHRegisterDelegate 方法:
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center 
didReceiveNotificationResponse:(UNNotificationResponse *)response 
withCompletionHandler:(void (^)())completionHandler 

2.应用在后台,

2.1 没有设置 content-available :
  • 2.1.1 用户没有点击通知栏打开的app,不可以拦截.且app切换至前台后,通知栏消失.
  • 2.1.2 如果用户点击了通知栏,就可以拦截.调用 JPUSHRegisterDelegate 方法:
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center 
didReceiveNotificationResponse:(UNNotificationResponse *)response 
withCompletionHandler:(void (^)())completionHandler 
2.2 设置 content-available :
  • 2.2.1 调用方法, 其中 application.applicationState == UIApplicationStateBackground
- (void)application:(UIApplication *)application 
didReceiveRemoteNotification:(NSDictionary *)userInfo 
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler 
  • 2.2.2 如果用户点击app图标打开的app,则当前通知栏的这条通知自动消失; 如果用户点击通知栏打开的app,会再调用下方法:
 - (void)jpushNotificationCenter:(UNUserNotificationCenter *)center 
didReceiveNotificationResponse:(UNNotificationResponse *)response 
withCompletionHandler:(void (^)())completionHandler

3.应用由死到生,

3.1 无论是否设置 content-available ,
  • 3.1.1 点击通知栏打开, 依次调用方法:
    1. 方法一
 - (BOOL)application:(UIApplication *)application 
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
    1. 方法二 JPUSHRegisterDelegate :
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center 
didReceiveNotificationResponse:(UNNotificationResponse *)response 
withCompletionHandler:(void (^)())completionHandler 
  • 3.1.2 点击app图标打开app,则拦截不到通知.此时 launchOptions 也为空. 个人认为这正常,app从死到生,所以是正常的过程,不需要也拿不到通知信息.

一. iOS 9

应用在前台,

无论是否设置 content-available , 都会调用方法,其中 application.applicationState == UIApplicationStateActive
- (void)application:(UIApplication *)application 
didReceiveRemoteNotification:(NSDictionary *)userInfo 
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler

应用在后台,

没有设置 content-available , 有通知栏提示
  • 2.1.1 点击通知栏会调用方法,其中 application.applicationState == UIApplicationStateInactive
- (void)application:(UIApplication *)application 
didReceiveRemoteNotification:(NSDictionary *)userInfo 
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
  • 2.1.2 不点击通知栏,或点击图标打开app,都不会调用上通知处理方法
2.2 设置 content-available , 有通知栏提示
    1. 调用方法,其中 application.applicationState == UIApplicationStateBackground
- (void)application:(UIApplication *)application 
didReceiveRemoteNotification:(NSDictionary *)userInfo 
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
    1. 如果点击了通知栏, 会再次调用这个方法,其中 application.applicationState == UIApplicationStateInactive
- (void)application:(UIApplication *)application 
didReceiveRemoteNotification:(NSDictionary *)userInfo 
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler

应用由死到生,

3.1 无论是否设置 content-available
  • 3.1.1 点击通知栏打开app, 依次调用方法:
    1. 方法一
  - (BOOL)application:(UIApplication *)application 
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
  • 2)方法二, 其中 application.applicationState == UIApplicationStateInactive
- (void)application:(UIApplication *)application 
didReceiveRemoteNotification:(NSDictionary *)userInfo 
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
  • 3.1.2 点击app图标打开app,则拦截不到通知.此时 launchOptions 也为空. 个人认为这正常,app从死到生,所以是正常的过程,不需要也拿不到通知信息.

注: 转载就注明出处: http://www.jianshu.com/p/9e2464be0fd5

你可能感兴趣的:(iOS 远程推送APNS从0至发布-代码集成篇)