一、通过证书助手,苹果官网生成了3个文件
1、PushChat.certSigningRequest
2、PushChatKey.p12
3、aps_developer_identity.cer
二、在AppDelegate中的didFinishLaunchingWithOptions方法中加入下面代码,通过registerForRemoteNotificationTypes方法,告诉应用程序,能接受push来的通知:
// iOS8.0 以上在AppDelegate.m 中,并且遵循协议UNUserNotificationCenterDelegate
#ifdef NSFoundationVersionNumber_iOS_9_x_Max
#import
#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);
//打印结果 ========
}];
} 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];
}
三、注册结果回调
#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);
}
四、收到推送后回调方法
// 处理远程消息
// 调用时机: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();
}
五、除了deviceToken之外,服
务器还需要一个与APNS连接的证书。这个证书可以通过我们前面生成的两个文件中得到。
使用OpenSSL生成服务器和APNS通信的证书文件。
1、将aps_developer_identity.cer转换成 aps_developer_identity.pem格式。
openssl x509 -in aps_developer_identity.cer -inform DER -out aps_developer_identity.pem -outform PEM
2、将p12格式的私钥转换成pem,需要设置4次密码,这里密码都设置为:abc123。
openssl pkcs12 -nocerts -out PushChat_Noenc.pem -in PushChat.p12
3、用certificate和the key 创建PKCS#12格式的文件。
openssl pkcs12 -export -in aps_developer_identity.pem -inkey PushChat_Noenc.pem -certfile PushChat.certSigningRequest -name “aps_developer_identity” -out aps_developer_identity.p12
这样我们就得到了在服务器中使用的证书文件:aps_developer_identity.p12。