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就可以收到推送了。

继续阅读

iOS 版IT之家客户端

3月11日更新

  • 今天发现原来能用的程序,突然不能显示资讯页的新闻内容了,表现为文章内容只有一个”>”

查了半天发现NSXMLPaser解析到文章详情的<detail>部分只剩下一个”>”

随后发现IT之家原来的detail部分有<![CDATA,但是新的文章没有了

这就导致文章中的<p>被认为是xml元素了.

研究了一下,明白了SAX和DOM模式

原来的SAX模式逐行解析,弊端就出现了

而就算没有<![CDATA,DOM模式也能解析

所以使用了GDataXML修改了解析部分,现在一切正常.

  • 搞定了帖子页的回复显示

原理目前很粗暴,for循环拼接HTML,从数组里拿每条获取到的回复,拼接成符合格式的HTML语句

然后显示在webView中

  • 搞定了用户头像显示

IT之家客户端里没抓到头像相关的api,于是去IT之家web版看了用户头像URL,发现是

my.ruanmei.com/images/upload/avatars/XXX/XX/XX/XX_60.jpg

XX为用户ID,不足7位前面补0

于是就用这个了,没有头像的人加载noavatat.png

3月14日更新

今天主要做了二维码识别模块

IT之家用的是ZXing

看了一下,自己能仿制出来,就没用三方

写了一晚上,还是学到很多东西的

不过不知道IT之家,或者ZXing用的是动画还是什么

扫描的动画我是用UIScrollView粗暴实现的

至少看上去效果一样啦~

在写上架的项目,停更