由于业务需要,今天学习了配置苹果的远程通知。
虽然网上的资料很多,可是还是遇到了不少问题,记录一下好了。
需要办的事儿有:
- 在iOS APP中注册通知
- 在Apple Developer申请证书
- 配置推送服务器
在iOS中注册通知
↑首先创建项目,设置Bundle Identifier为net.iwpz.demoapp。
↑然后,配置项目的Background Modes,开启后勾选Remote notifications。
然后,我们需要在AppDelegate中重写如下方法:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound) categories:nil]; [[UIApplication sharedApplication] registerUserNotificationSettings:settings]; [[UIApplication sharedApplication] registerForRemoteNotifications]; return YES; }
↑在程序运行时注册通知该方法只适用于iOS8以上,iOS8或以下请自助。
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { NSString *tokenString = [NSString stringWithFormat:@"%@", deviceToken]; tokenString = [tokenString substringFromIndex:1]; //去掉开头的< tokenString = [tokenString substringToIndex:tokenString.length - 1]; //去掉结尾的> tokenString = [tokenString stringByReplacingOccurrencesOfString:@" " withString:@""]; //去掉空格 NSLog(@"注册远程通知成功,token:%@",tokenString); }
↑注册通知成功会回调这个方法,参数的deviceToken是设备的唯一标识符,存在细节,后文会说。打印出来形如
<219bfc5c 3462afe6 3c022327 6bfd7a60 2457cb7f 3eb6d414 602fb0e2 f8a30b5d>
服务器推送时需要去掉空格和首位的尖括号,在这里我们可以把这个token记录到服务器。
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{ NSLog(@"注册远程通知失败,错误:%@",error); }
↑注册通知失败时会调用
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{ NSLog(@"收到服务器的通知,内容:%@",userInfo); }
↑收到服务器推送的通知后会调用。存在细节,后文会说。
↑至此,App已经配置完毕。请先真机运行一次,如果配置没问题,会提示你是否允许通知,请选择允许
注册远程通知成功,token:eccbe410884e0d8e1508cc39de097196af3462788a2d6530177fb73e28164b34
↑另外为了测试,运行时控制台应该会输出这台机器的deviceToken,请保留以便服务器测试用。
在Apple Developer申请证书
接下来我们需要根据这个Bundle Identifier,在Apple Developer创建一个App ID。
传送门:点我
↑首先点击Identifiers 里的 App IDs,然后点击右上角的 +
↑然后输入你的App的信息,包括Name和Bundle ID。其中:Name为App在Apple Developer显示的名称,可以随便取;Bundle ID为程序的唯一标识符,苹果推荐使用反域名,比如 com.yourwebsite.yourapp。
↑然后选择App 需要用的服务,我们这里勾选“推送通知”
然后点击蓝色的Continue
↑如果是这个样子,就可以点击蓝色的Register注册这个App了。
注册完成后,请点击Done。
↑在这里选择刚刚注册的App,点击展开。
↑这里我们看到 Push Notifications右侧的2个灯是黄色的,我们就需要配置它们的证书。所以请点击Edit
↑点击Edit后找到Push Notifications这里,在这里我们需要分别配置开发环境(红框)和发布环境(绿框)的证书,步骤是相同的,这里我以开发环境举例。
点击红色框中的 Create Certificate…
↑这里需要你从自己的电脑创建一个CSR(证书注册请求)文件,我们可以根据苹果的提示创建。
↑首先我们需要打开OS X中的钥匙串应用,选择 钥匙串访问 -> 证书助理-> 从证书颁发机构请求证书…
↑输入自己的Email地址和常用名称,然后选择 存储到磁盘 ,点击继续
存储成功后,你会得到一个 CertificateSigningRequest.certSigningRequest 文件。
带着它我们回到Apple Developer,点击蓝色的Continue
↑浏览你刚才生成的CertificateSigningRequest.certSigningRequest文件,点击蓝色的Continue
↑这时我们已经成功申请到了推送服务的证书,点击蓝色的Download将它下载到本地。
为了后续操作不出现错误,不推荐修改默认文件名,所以我们下载到了一个叫做aps_development.cer的文件。
↑双击它,导入到自己的Mac,然后,就可以在钥匙串应用中的“登录”页找到它。
↑右键单击,选择导出“Apple Development IOS Push Services:net.iwpz.demoapp”…
这里默认的名字是“证书”,为了方便终端操作,我们改名为demoapp。
↑然后需要输入设置保护这个证书的密码,请牢记。这里我设置成了 test
输入2次确认后,请输入你的OS X用户密码,并点击“允许”。
现在我们有了一个“demoapp.p12”文件。
然后我们打开OS X的终端,开始制作PEM文件。
先cd到证书文件所在目录,然后执行
openssl pkcs12 -in demoapp.p12 -out demoapp.pem -nodes
执行后输入上面设置的保护密码,我这里是test
↑到这里我们已经成功得到了服务器的证书文件demoapp.pem,可以配置推送服务器了。
配置推送服务器
这里我用PHP举例,其他语言请自助。
<?php //设备的Token码 $deviceToken = 'eccbe410884e0d8e1508cc39de097196af3462788a2d6530177fb73e28164b34'; //保护密码 $passphrase = 'test'; //推送的消息 $message = $_GET["message"]; if(!$message){ $message = 'no message'; } $ctx = stream_context_create(); stream_context_set_option($ctx, 'ssl', 'local_cert', 'demoapp.pem');//证书文件 stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase); $fp = stream_socket_client(//打开一个到APNS服务器的连接 // 开发环境服务器 ssl://gateway.sandbox.push.apple.com:2195 // 发布环境服务器 ssl://gateway.push.apple.com:2195 'ssl://gateway.sandbox.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx); if (!$fp){ exit("Failed to connect: $err $errstr" . PHP_EOL); } echo 'Connected to APNS' . PHP_EOL ." "; $body = array("aps" => array("alert" => $message, "badge" => 3,"sound"=>'default',"yourkey" => 'yourValueForKey' ,"youranotherkey" => 'yourAnotherValueForKey')); $payload = json_encode($body); echo "the payload body is ".$payload." "; $msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload; $result = fwrite($fp, $msg, strlen($msg)); if (!$result){ echo 'Message not delivered' . PHP_EOL; }else{ echo 'Message successfully delivered' . PHP_EOL." ".$message; } fclose($fp); ?>
↑PHP端demo代码,请自行修改配置内容,并将申请证书时生成的.pem文件放到PHP可以访问到的地方,并在PHP中配置其路径。如果将pem文件和php文件放到同一目录,则如上代码,只写文件名即可。
保存运行,如果没有问题,则你的App已经可以收到推送了。
访问这个API:
http://localhost/remotePush.php?message=这是一条推送
↑App就可以收到推送了。
看起来很顺利,但是在配置的时候也遇到过不少坑。
所以在配置时候请注意以下事项:
- deviceToken并不是永久唯一值。
用户安装App开始,你就可以得到他的设备的deviceToken,但是经过测试
XCode中重新编译安装,deviceToken 不变
长按删除App,XCode中重新编译安装,deviceToken改变
也就是用户如果重装了你的App,他的token会变
所以在记录这个值的时候,需要判断用户的token是否改变,以便更新数据。
- 你给用户推送的内容,允许自定义。
在
– (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
NSLog(@”收到服务器的通知,内容:%@”,userInfo);
}
中收到的通知信息是个字典,叫做userInfo。
以上面的PHP代码为例,我收到的通知内容如下:
收到服务器的通知,内容:{
aps = {
alert = “这是一条推送”;
badge = 0;
sound = default;
youranotherkey = yourAnotherValueForKey;
yourkey = yourValueForKey;
};
}
其中alert是推送显示的内容
badge是推送后你App在iOS主界面显示的数字(小红点)
sound是推送播放的声音,支持自定义,细节请自助。
其他的是我自定义的key,经过验证是可以收到的,所以我们可以推送一些附加信息给App。
- 通知相关的函数的运行顺序
程序初次运行:
didFinishLaunching
didRegisterForRemoteNotificationsWithDeviceToken
程序在前台收到推送通知:
didReceiveRemoteNotification
程序在后台收到推送通知并不会执行任何推送相关函数。
程序在后台时,点击推送进入App:
didReceiveRemoteNotification
由此可以看出,程序在运行时收到通知会自动执行didReceiveRemoteNotification,而在后台时,当用户忽略推送,程序什么也不会做,但是如果用户点击这条推送进入App,则会执行didReceiveRemoteNotification。
- 注意开发环境和发布环境使用的是不同的服务器
也就是上面图里的红框和绿框,一定要使用对应服务器,否则收不到通知
- 使用该服务(包括测试时使用开发环境)需要交年费
- 配置服务端和请求证书过程基于2016年6月的Apple Developer环境,目前适用与任何iOS版本
- demo代码只适用与iOS9,因为注册通知的方式在iOS9有了更新,请自行查阅iOS8之前的注册方式,但是无论如何,只要注册成功即可使用。
其实这个流程满大街都是,我只是整理了一下- 我截图里的圈是绿色,因为我越狱装了ColorBadges。