Apple native remote push

1. Through the certificate assistant, Apple’s official website generated 3 files
1. PushChat.certSigningRequest
2. PushChatKey.p12
3. aps_developer_identity.cer

2. Add the following code to the didFinishLaunchingWithOptions method in AppDelegate, and tell the application through the registerForRemoteNotificationTypes method that it can accept push notifications:

// iOS8.0 以上在AppDelegate.m 中,并且遵循协议UNUserNotificationCenterDelegate
#ifdef NSFoundationVersionNumber_iOS_9_x_Max
#import <UserNotifications/UserNotifications.h>
#endif

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [self replyPushNotificationAuthorization:application];
    return YES;
}


- (void)replyPushNotificationAuthorization:(UIApplication *)application{
    if (IOS10_OR_LATER) {
        //iOS 10 later
        UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
        //必须写代理,不然无法监听通知的接收与点击事件
        center.delegate = self;
        [center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert) completionHandler:^(BOOL granted, NSError * _Nullable error) {
            if (!error && granted) {
                //用户点击允许
                NSLog(@"注册成功");
            } else {
                //用户点击不允许
                NSLog(@"注册失败");
            }
        }];
 
        // 可以通过 getNotificationSettingsWithCompletionHandler 获取权限设置
        //之前注册推送服务,用户点击了同意还是不同意,以及用户之后又做了怎样的更改我们都无从得知,现在 apple 开放了这个 API,我们可以直接获取到用户的设定信息了。注意UNNotificationSettings是只读对象哦,不能直接修改!
        [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
            NSLog(@"========%@",settings);
//打印结果 ========<UNNotificationSettings: 0x1740887f0; authorizationStatus: Authorized, notificationCenterSetting: Enabled, soundSetting: Enabled, badgeSetting: Enabled, lockScreenSetting: Enabled, alertSetting: NotSupported, carPlaySetting: Enabled, alertStyle: Banner>        
        }];
    } else if (IOS8_OR_LATER) {
        //iOS 8 - iOS 10系统
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
        [application registerUserNotificationSettings:settings];
    } else {
        //iOS 8.0系统以下
        [application registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound];
    }
 
    //注册远端消息通知获取device token
    [application registerForRemoteNotifications];
}

3. Registration result callback

#pragma mark - 获取device Token
//获取DeviceToken成功
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
 
    //解析NSData获取字符串
    //我看网上这部分直接使用下面方法转换为string,你会得到一个nil(别怪我不告诉你哦)
    //错误写法
    //NSString *string = [[NSString alloc] initWithData:deviceToken encoding:NSUTF8StringEncoding];
 
 
    //正确写法
    NSString *deviceString = [[deviceToken description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
    deviceString = [deviceString stringByReplacingOccurrencesOfString:@" " withString:@""];
 	// 然后将获得的deviceString传给服务器
    NSLog(@"deviceToken===========%@",deviceString);
}
 
//获取DeviceToken失败
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{
    NSLog(@"[DeviceToken Error]:%@\n",error.description);
}

4. Callback method after receiving push

// 处理远程消息
// 调用时机:App处于前台收到推送;在iOS7后,开启了 Remote Notification,App处于后台收到推送。
// 方法二是在iOS 7之后新增的方法,可以说是 方法一 的升级版本,如果app最低支持iOS 7的话可以不用添加 方法一了。
//- (void)application:(UIApplication *)application //didReceiveRemoteNotification:(NSDictionary *)userInfo
//{
//    NSLog(@"userinfo:%@",userInfo);
//    NSLog(@"收到推送消息:%@",[[userInfo objectForKey:@"aps"] objectForKey:@"alert"]);
//}

// 其中completionHandler这个block可以填写的参数UIBackgroundFetchResult是一个枚举值。主要是用来在后台状态下进行一些操作的,比如请求数据,操作完成之后,必须通知系统获取完成,可供选择的结果有
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
    NSLog(@"userinfo:%@",userInfo);
    NSLog(@"收到推送消息:%@",[[userInfo objectForKey:@"aps"] objectForKey:@"alert"]);
    
    completionHandler(UIBackgroundFetchResultNewData);
//    typedef NS_ENUM(NSUInteger, UIBackgroundFetchResult) {
//        UIBackgroundFetchResultNewData,
//        UIBackgroundFetchResultNoData,
//        UIBackgroundFetchResultFailed
//    }
}


// iOS10.0之后,新增两个方法。原来的方法还是需要实现的,各自的调用时机不一样。
// App处于前台接收到通知
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
    if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        NSLog(@"iOS10 收到远程通知");
    }else {
        // 判断为本地通知
        NSLog(@"iOS10 收到本地通知");
    }
    
    // 在前台默认不显示推送,如果要显示,就要设置以下内容
    // 微信设置里-新消息通知-微信打开时-声音or振动  就是该原理
    // 需要执行这个方法,选择是否提醒用户,有Badge、Sound、Alert三种类型可以设置
    completionHandler(UNNotificationPresentationOptionBadge|
                      UNNotificationPresentationOptionSound|
                      UNNotificationPresentationOptionAlert);
}

// 点击通知后会调用
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
    completionHandler(UIBackgroundFetchResultNewData);
    NSDictionary *userInfo = response.notification.request.content.userInfo;
    //程序关闭状态点击推送消息打开 可以在App启动方法的launchOptions获知
    if (self.isLaunchedByNotification) {
        //TODO
    } else{
        //前台运行
        if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
            //TODO
        }  else{  //后台挂起时
            //TODO
        }
        //收到推送消息手机震动,播放音效
        AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
        AudioServicesPlaySystemSound(1007);
    }
    //设置应用程序角标数为1
    [UIApplication sharedApplication].applicationIconBadgeNumber = 1;
    
    // 此处必须要执行下行代码,不然会报错
    completionHandler();
}

5. In addition to the deviceToken, the server
also needs a certificate to connect to APNS. This certificate can be obtained from the two files we generated earlier.

Use OpenSSL to generate a certificate file for communication between the server and APNS.

1. Convert aps_developer_identity.cer to aps_developer_identity.pem format.

openssl x509 -in aps_developer_identity.cer -inform DER -out aps_developer_identity.pem -outform PEM

2. To convert the private key in p12 format to pem, you need to set the password 4 times. The passwords here are all set to: abc123.

openssl pkcs12 -nocerts -out PushChat_Noenc.pem -in PushChat.p12

3. Use the certificate and the key to create a file in PKCS#12 format.

openssl pkcs12 -export -in aps_developer_identity.pem -inkey PushChat_Noenc.pem -certfile PushChat.certSigningRequest -name “aps_developer_identity” -out aps_developer_identity.p12

This way we get the certificate file used in the server: aps_developer_identity.p12.

The entire push process is as follows: Insert image description here
Reference link: https://www.jianshu.com/p/3fc46a8764ed

Guess you like

Origin blog.csdn.net/qq_31709953/article/details/98973441
Recommended