iOS 消息推送 APNs 配置说明

由于业务需要,今天学习了配置苹果的远程通知。

虽然网上的资料很多,可是还是遇到了不少问题,记录一下好了。

需要办的事儿有:

  • 在iOS APP中注册通知
  • 在Apple Developer申请证书
  • 配置推送服务器

在iOS中注册通知

pic17

↑首先创建项目,设置Bundle Identifier为net.iwpz.demoapp。

pic18

↑然后,配置项目的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);
}

↑收到服务器推送的通知后会调用。存在细节,后文会说。

pic19

↑至此,App已经配置完毕。请先真机运行一次,如果配置没问题,会提示你是否允许通知,请选择允许

注册远程通知成功,token:eccbe410884e0d8e1508cc39de097196af3462788a2d6530177fb73e28164b34

↑另外为了测试,运行时控制台应该会输出这台机器的deviceToken,请保留以便服务器测试用。

在Apple Developer申请证书

接下来我们需要根据这个Bundle Identifier,在Apple Developer创建一个App ID。

传送门:点我

↑首先点击Identifiers 里的 App IDs,然后点击右上角的 +pic02

↑然后输入你的App的信息,包括Name和Bundle ID。其中:Name为App在Apple Developer显示的名称,可以随便取;Bundle ID为程序的唯一标识符,苹果推荐使用反域名,比如 com.yourwebsite.yourapp。

pic03

↑然后选择App 需要用的服务,我们这里勾选“推送通知”

然后点击蓝色的Continue

pic04

↑如果是这个样子,就可以点击蓝色的Register注册这个App了。

注册完成后,请点击Done。

pic05

↑在这里选择刚刚注册的App,点击展开。

pic06

↑这里我们看到 Push Notifications右侧的2个灯是黄色的,我们就需要配置它们的证书。所以请点击Edit

pic07

↑点击Edit后找到Push Notifications这里,在这里我们需要分别配置开发环境(红框)和发布环境(绿框)的证书,步骤是相同的,这里我以开发环境举例。

点击红色框中的 Create Certificate…

pic08

↑这里需要你从自己的电脑创建一个CSR(证书注册请求)文件,我们可以根据苹果的提示创建。

pic09

↑首先我们需要打开OS X中的钥匙串应用,选择 钥匙串访问 -> 证书助理-> 从证书颁发机构请求证书…

pic10

↑输入自己的Email地址和常用名称,然后选择 存储到磁盘 ,点击继续

存储成功后,你会得到一个 CertificateSigningRequest.certSigningRequest 文件。

带着它我们回到Apple Developer,点击蓝色的Continuepic11

↑浏览你刚才生成的CertificateSigningRequest.certSigningRequest文件,点击蓝色的Continue

pic12

↑这时我们已经成功申请到了推送服务的证书,点击蓝色的Download将它下载到本地。

为了后续操作不出现错误,不推荐修改默认文件名,所以我们下载到了一个叫做aps_development.cer的文件。

pic13

↑双击它,导入到自己的Mac,然后,就可以在钥匙串应用中的“登录”页找到它。

pic14

↑右键单击,选择导出“Apple Development IOS Push Services:net.iwpz.demoapp”…

这里默认的名字是“证书”,为了方便终端操作,我们改名为demoapp。

pic15

↑然后需要输入设置保护这个证书的密码,请牢记。这里我设置成了 test

输入2次确认后,请输入你的OS X用户密码,并点击“允许”。

现在我们有了一个“demoapp.p12”文件。

然后我们打开OS X的终端,开始制作PEM文件。

先cd到证书文件所在目录,然后执行

openssl pkcs12 -in demoapp.p12 -out demoapp.pem -nodes

执行后输入上面设置的保护密码,我这里是test

pic16

↑到这里我们已经成功得到了服务器的证书文件demoapp.pem,可以配置推送服务器了。

配置推送服务器

这里我用PHP举例,其他语言请自助。

&lt;?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" =&gt; array("alert" =&gt; $message, "badge" =&gt; 3,"sound"=&gt;'default',"yourkey" =&gt; 'yourValueForKey' ,"youranotherkey" =&gt; '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);
?&gt;

↑PHP端demo代码,请自行修改配置内容,并将申请证书时生成的.pem文件放到PHP可以访问到的地方,并在PHP中配置其路径。如果将pem文件和php文件放到同一目录,则如上代码,只写文件名即可。

保存运行,如果没有问题,则你的App已经可以收到推送了。

访问这个API:

http://localhost/remotePush.php?message=这是一条推送

pic20

↑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。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注