苹果的远程推送APNS:
原理过程什么的就不说了,这里主要是为了记录一下今天解决推送所遇到的坑。
步骤主要分为四部分:
- 请求证书
- 处理证书以及p.12文件等问题
- 客户端这边根据需要设置一下
- 测试一下可行性
请求证书 && 处理证书及p.12文件
- 创建APP ID
登录Apple Member Center :https://developer.apple.com/membercenter,选择certificates,identifiers&profiles
选项,如下图所示:
选择identity
中的APP IDs
,如下图所示:
注意:创建Explicit App ID
时,要注意此时设置的Bundle ID要与APP以后的Bundle ID一致,如下图所示:
选择Push Notification
来开通Push功能,如下图所示:
点击下方的register
按钮,几秒钟之后下方会变成一个Done
,表示APP ID已经创建完成,如下图所示:
注意: 创建的APP ID要与自己项目的Bundle ID保持一致。如果已经有APP ID,请确保自己的APP ID已经开通了Push功能,如果没有开通,可以点击APP ID,在其底部有一个Edit按钮,点击后选中Push服务并创建,如下图所示:
至此,APP ID创建完毕。
- 创建CSR文件
如果你已经有CSR文件,请继续进行下一步的设置。
CSR是Cerificate Signing Request的英文缩写,即证书请求文件。证书申请者在申请数字证书时由CSP(加密服务提供者)在生成私钥的同时也生成证书请求文件。证书申请者只要把CSR文件提交给证书颁发机构后,证书颁发机构使用其根证书私钥签名就生成了证书公钥文件,也就是颁发给用户的证书。
在电脑中找到钥匙串----->钥匙串访问------>证书管理------>从证书颁发机构请求证书,如下图所示:
设置完证书信息后,点击“继续”,然后选择存储位置,点击存储, 至此,CSR文件创建成功。
- 创建开发调试证书
如果你已经有开发调试证书,请继续进行下一步的设置。
选择Development(如果是发布上线,需要选择Distribution),如下图所示:
在 choose file...中选择本地的 CertificateSigningRequest(CSR)文件,然后点击继续,如下图所示:
点击 Download,将证书下载到本地,双击下载的开发调试证书(文件名为: iOS_development.cer),就可以在钥匙串访问中的我的证书中找到。
至此,开发调试证书设置完毕。
-
添加测试设备
测试推送需要添加测试设备,添加方法如下所示:
- 创建Provisioning Profiles文件
选择Development,创建开发环境的Provisioning Profiles(如果是发布上线,需要选择Distribution),如下图所示:
创建新的Provisioning Profiles,并选择之前生成好的App ID。如下图所示:
选中创建的证书:
选中测试设备:
把创建的 Provisioning Profiles, 调试证书, 推送证书下载下来(文件名:umengpushtestdemo.mobileprovision)以后双击证书。
- 创建推送证书
选择Apple Push Notification service SSL(Sandbox)
注意:推送证书分为开发环境和生产环境,如果需要生成生产环境的推送证书请选择: Apple Push Notification service SSL (Sandbox&Production)
,如下图所示:
选中APP ID后,点击continue,直到上传CRS文件,如下图所示:
点击Download,将证书下载到本地后,双击下载的开发环境推送证书(文件名为:aps_development.cer),就可以在钥匙串访问中的我的证书中找到。
** 这里我要说的坑就是,在双击开发证书之后,在登录选项下,竟然没有发现上述图片所说的那个秘钥!!!!!!!在这里我删了又重来删了有重来好几次了**
最后。。。。我™直接拉进去,竟然可以了~
- 导出推送证书的P12文件
注意:在钥匙串访问(KeyChain)的我的证书中选择刚刚导入的证书,选择导出,注意不要选中私钥,并设置相应密码即可。
注意:此步骤所设置的密码将在之后在U-Push后台上传推送证书时所使用。
生产环境的推送证书也是以同样的方式导出。
至此,P12证书导出完毕。
上面所说的那些,我都是在友盟看回来的,感谢友盟
客户端接收设置
1、注册远程推送以及设置相关选项:
// 这里其实还有个ios版本区分的,但是项目需求是7.0以上的版本,所以这里没有考虑其他情况。
UIRemoteNotificationType types = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert;
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:types];
这里还需要对Capabilites进行设置以确保能接受到推送:
2、在APPDelegate.m的接收函数
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
if (launchOptions) {
//如果应用还没启动,则通过push冷启动后,仍能在激动之后获取Dictionary
NSDictionary *userInfo = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
if (userInfo) {
//有推送消息优先处理推送消息
NSLog(@"Dictionary:%@",userInfo);
}
// 当userInfo设置了badge,应用图标上将一直显示一个数字提示,如果要清除数字提示,或者设置成其他数字,调用下面函数就可以完成。
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
}
return YES;
}
//注册成功回调方法,其中deviceTocken是APNS返回的token
-(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
NSLog(@"Devtocken:%@",deviceToken);
}
//注册失败返回调用方法,处理失败情况
-(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{
NSLog(@"获取DeviceTocken失败:%@",error);
}
//当程序在前台运行,接收到消息不会有消息提示(提示框或横幅)。
//当程序运行在后台,接收到消息会有消息提示,点击消息后进入程序,
//AppDelegate的didReceiveRemoteNotification函数会被调用,消息做为此函数的参数传入
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)payload {
NSLog(@"remote notification: %@",[payload description]);
NSString* alertStr = nil;
NSDictionary *apsInfo = [payload objectForKey:@"aps"];
NSObject *alert = [apsInfo objectForKey:@"alert"];
if ([alert isKindOfClass:[NSString class]])
{
alertStr = (NSString*)alert;
}
else if ([alert isKindOfClass:[NSDictionary class]])
{
NSDictionary* alertDict = (NSDictionary*)alert;
alertStr = [alertDict objectForKey:@"body"];
}
application.applicationIconBadgeNumber = [[apsInfo objectForKey:@"badge"] integerValue];
//当程序存活并受到来自APNS的推送时执行的方法:
if ([application applicationState] == UIApplicationStateActive && alertStr != nil)
{
UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:@"Pushed Message" message:alertStr delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alertView show];
}
if ([application applicationState] == UIApplicationStateBackground) {
UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:@"Pushed Message" message:alertStr delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alertView show];
}
}
测试一下
在网上搜罗了一下,有好几种方式可以达到检测的目的,首推的,也是最简单的,在Mac上运行的,直接在github上可以拿到改demo:PushMeBaby
这里只需要简单的在APPdelegate中配置一下DeviceToken以及把推送证书放到项目工程中就可以了。 ** 此处有坑 **:这里需要把这个选项给选上,不然在读取证书路径的时候就会失败。
** 同时这里还存在第二个坑:**
在设置deviceToken时,需要保留空格,去掉尖括弧
运行一下,push一下就可以了,有时候网络问题也会导致一些延迟。
这里我其实还测试了另外的一种方法:php推送
1 .首先将证书文件和私钥处理成单个方便使用的pem文件,假设CSR、p12和cer文件都放在桌面上。
$ cd ~/Desktop$ls
aps_development.cer
CertificateSigningRequest.certSigningRequest
PushKey.p12
2 .将aps_development.cer转换为pem文件。
$ openssl x509 -in aps_development.cer -inform der -out PushCert.pem
$ls
aps_development.cer
CertificateSigningRequest.certSigningRequest
PushCert.pem
PushKey.p12
3 .将p12私钥文件转换为pem文件。
$ openssl pkcs12 -nocerts -out PushKey.pem -in PushKey.p12
Enter Import Password:
MAC verified OK
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
4 .将两个文件合成同一个。
$ cat PushCert.pem PushKey.pem > ck.pem
$ls
aps_development.cer
CertificateSigningRequest.certSigningRequest
ck.pem
PushCert.pem
PushKey.pem
PushKey.p12
5 .测试证书是否有效。
$ openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert PushCert.pem -key PushKey.pem
如果有效的话,会输出一堆信息,并且建立连接,否则不会成功建立连接。
6 .使用PHP进行测试,下载SimplePush.php,修改文件并填入deviceToken和密码。在终端运行该代码。
$ php simplepush.php Connected to APNSMessage successfully delivered
成功发送推送消息。
(此方法感谢:戴维营教育原创文章)
** 关于推送json格式的说明 **
- 推送负载:
远程通知负载的大小根据Provider使用的API不同而不同。当使用HTTP/2 provider API时,负载最大为4096bytes,即4kB;当使用legacy binary interface时,负载最大为2048bytes,即2kB。当负载大小超过规定的负载大小时,APNs会拒绝发送此消息。
- 远程推送负载内容
内容格式必要要知道的啊,服务端一般会要我们客户端定义好格式给他们的。
每一条通知的消息都会组成一个JSON字典对象,其格式如下所示,示例中的key值为苹果官方所用key。自定义字段的时候要避开这些key值。
每一条通知的消息都会组成一个JSON字典对象,其格式如下所示,示例中的key值为苹果官方所用key。自定义字段的时候要避开这些key值。
{
"aps" : {
"alert" : { // string or dictionary
"title" : "string"
"body" : "string",
"title-loc-key" : "string or null"
"title-loc-args" : "array of strings or null"
"action-loc-key" : "string or null"
"loc-key" : "string"
"loc-args" : "array of strings"
"launch-image" : "string"
},
"badge" : number,
"sound" : "string"
"content-available" : number;
"category" : "string"
},
}
aps:推送消息必须有的key
alert:推送消息包含此key值,系统就会根据用户的设置展示标准的推送信息
badge:在app图标上显示消息数量,缺少此key值,消息数量就不会改变,消除标记时把此key对应的value设置为0
sound:设置推送声音的key值,系统默认提示声音对应的value值为default
content-available:此key值设置为1,系统接收到推送消息时就会调用不同的回调方法,iOS7之后配置后台模式
category:UIMutableUserNotificationCategory's identifier 可操作通知类型的key值
title:简短描述此调推送消息的目的,适用系统iOS8.2之后版本
body:推送的内容
title-loc-key:功能类似title,附加功能是国际化,适用系统iOS8.2之后版本
title-loc-args:配合title-loc-key字段使用,适用系统iOS8.2之后版本
action-loc-key:可操作通知类型key值,不详细叙述
loc-key:参考title-loc-key
loc-args:参考title-loc-args
launch-image:点击推送消息或者移动事件滑块时,显示的图片。如果缺少此key值,会加载app默认的启动图片。
后边这一对是自定义的,但是要注意不可以和前面的重复
"badge" : number,
"sound" : "string"
"content-available" : number;
"category" : "string"
此处出自TIME_for 的《iOS推送之远程推送(iOS Notification Of Remote Notification》)
搬运工再次感谢各位前辈的付出。谢谢!