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:
Reference link: https://www.jianshu.com/p/3fc46a8764ed