iOS Push Notification APNS消息推送全攻略
iOS 消息推送是及其重要的功能,但其配置并不如想象中的那么简单——甚至可以说比较复杂,博主在部署过程中可是遇到了不少问题。
本着分享至上的原则,本文将从零开始,一步步指引你完成消息推送的部署。
一、推送原理: APNS(Apple Push Notification Service)
iOS平台所有的消息推送都要依赖APNS(翻译过来就是苹果消息推送服务),目前虽然有很多第三方推送平台如百度云推送、极光推送等等也提供类似服务,但最终还是要依赖APNS。
消息推送流程图:
一句话攻略:服务器(Provider)发推送请求 –> APNS确认 –> 发给指定设备(iPhone、iPad…) –> 发消息给指定App
但是我们的App是如何知道自己需要接收推送呢?流程如下:
可以概括为:
1、App启动时在APNS注册推送需求(一般在didFinishLaunchingWithOptions中)
2、注册成功,返回deviceToken即推送令牌(didRegisterForRemoteNotificationsWithDeviceToken中)。在这里我们将此令牌发回自己的服务器并存储下来,证明这个设备已经可以接收消息推送啦^_^
3、服务器想推送消息时,把消息内容和deviceToken发送给APNS,其他什么都不用考虑。
听起来很简单,是吧?那么让我们开始进入地狱难度~
二、证书和授权
在此之前需要声明,推送服务不支持模拟器,所以请务必先搞到一台iPhone/iPad或其他iOS设备。
1、创建CSR,这个不是本文重点,我就直接搬运了~
打开钥匙串,然后:
生成CSR文件的同时,在钥匙串中会生成常用名对应的公钥和私钥,待会会有用
2、登陆苹果开发者平台,开始创建证书,地址:https://developer.apple.com/account/ios/certificate/
2.1 创建App ID,记得选Explicit App ID并且勾选Push Notifications。
完成之后不要急,还需要创建SSL证书,此时推送功能待配置:
点Edit进入此App的编辑页面,创建并下载相应证书,详细步骤将在下一步说明:
创建完后下载之,得到aps_development.cer,双击导入钥匙串。确保Push Notifications处于Enabled状态,如图
2.2 创建证书(接上一步,如果上一步你已经做了就不用看了,跳2.3)
选择刚刚生成的App ID
上传我们在第1步中制作的CSR
完成后下载证书,导入钥匙串
2.3 创建Profile
主要记得选择刚才的App ID,并且将自己的开发设备给选进去
完成后下载,双击打开
2.4 导出p12私钥
打开钥匙串,找到我们生成的CSR常用名对应私钥,导出为p12文档。导出过程中会让输入一个文档访问密码(要牢记)以及一次电脑登陆密码。
至此我们得到了全部的文件:
①、pushKey.p12 ——私钥
②、aps_development.cer ——SSL证书
③、AppID.mobileprovision ——开发者描述文档,用于iOS项目
但想要立即进行测试则还需要进行一定处理(我们将利用一个PHP文档做简易的服务端)
3、证书格式转换及打包
3.1 转换SSL证书和私钥
打开终端,进入证书和私钥路径,执行以下命令
1 | openssl x509 -in aps_development.cer -inform der -out PushCert.pem |
1 | openssl pkcs12 -nocerts -out PushKey.pem -in PushKey.p12 |
转换私钥时会让输入刚才导出时的密码,并设定一个新密码 囧,建议设定成一样吧不然容易混淆。
3.2 打包(php中用到)
我们已经由上一步得到了PushCert.pem和PushKey.pem,接下来把它们打包一下:
1 | cat PushCert.pem PushKey.pem > ck.pem |
3.4 连接测试
用自带的telnet命令连接gateway.sandbox.push.apple.com 2195,这是苹果的测试推送服务器地址。如果成功,你会看到以下输出;失败的话检查你的防火墙是否没开放2195端口
1 2 3 4 | telnet gateway.sandbox.push.apple.com 2195 Trying 17.172.232.18... Connected to gateway.sandbox.push-apple.com.akadns.net. Escape character is '^]'. |
接下来测试证书是否有效
1 2 3 | openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert PushCert.pem -key PushKey.pem //接下来要输入一次私钥的密码 //然后是一大串输出结果 |
结尾是这样就算成功啦
三、真机推送测试
用Xcode新建一个测试项目,填好Bundle Identifier并选择对应Team
Build Settings -> Code Signing设置为开发者,Provisioning Profile选择我们刚才创建的,博主被坑了很久才搞定的:
若测试过程中出现问题的话建议先删除所有Provisioning Profile,再重新来过。
接下来在AppDelegate.m文件中实现以下方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { //进行消息推送注册,iOS 8之前和现在调用方法不同,以下为兼容性写法 if ([application respondsToSelector:@selector(isRegisteredForRemoteNotifications)]) { // iOS 8 Notifications [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]]; [application registerForRemoteNotifications]; } else { // iOS < 8 Notifications [application registerForRemoteNotificationTypes: (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound)]; } return YES; } ///注册成功、失败及消息接收 - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{ NSLog(@"regisger success:%@",deviceToken); //注册成功,将deviceToken保存到应用服务器数据库中 } - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{ NSLog(@"Registfail%@",error); //注册失败 } - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{ #if !TARGET_IPHONE_SIMULATOR NSLog(@"remote notification: %@",[userInfo description]); NSDictionary *apsInfo = [userInfo objectForKey:@"aps"]; NSString *alert = [apsInfo objectForKey:@"alert"]; NSLog(@"Received Push Alert: %@", alert); NSString *sound = [apsInfo objectForKey:@"sound"]; NSLog(@"Received Push Sound: %@", sound); NSString *badge = [apsInfo objectForKey:@"badge"]; NSLog(@"Received Push Badge: %@", badge); application.applicationIconBadgeNumber = [[apsInfo objectForKey:@"badge"] integerValue]; #endif } |
到此iOS工程配置完毕,连上你的手机,运行并允许接收推送。不出意外的话应该在控制台能够得到deviceToken。
开始配置简易服务端:
点此下载简易服务端PHP,解压后将pushTest.php与ck.pem放置到同一目录
1、更改$deviceToken为你的设备的deviceToken(didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken获得),注意去掉中间空格
2、更改$pass为私钥密码
3、更改pem名称,要与你打包后的文件相同(本例中为ck.pem)
4、注意当前请求地址
沙盒测试地址:tls://gateway.sandbox.push.apple.com:2195
正式环境地址:tls://gateway.push.apple.com:2195
OS X默认是可以运行php的,因此直接打开终端,导航到php文件的路径,执行命令:
1 | php pushTest.php |
然后就可以看到手机收到消息啦!!
四、备注 & 问题
再次附上php下载地址:点我下载
php文件修改注意:
1、现在苹果推送服务器已经不支持使用SSL连接了,全部改为TLS(不过说不定哪天又改了)
2、DeviceToken不能有空格、不能有左右尖括号,并且开发环境和正式环境的DeviceToken是不同的
3、pem应该使用打包后的(本例中为ck.pem),博主就是最开始混淆用错了,浪费了很多时间囧
4、发布证书和开发证书使用的地址是不同的,一定要搞清楚
5、$badge指消息数量(桌面图标上显示的那个)。$sound指提示音,去除的话收到消息时不会有声音。
常见问题:
1、didRegisterForRemoteNotificationsWithDeviceToken不触发
先检查手机网络是否正常,连不上网是肯定不行的。之后才考虑是配置问题,检查Build Setting是否正确。实在不行建议先删除所有Provisioning Profile,再重新来过
2、php执行成功,但手机没有收到推送
首先检查deviceToken是否正确(不能有空格、不能有左右尖括号,并且值可能有变化);然后再考虑Build Setting的问题,检查设定、检查Provisioning Profile是否匹配等。
评论