1.APNS的推送机制

首先我们看一下苹果官方给出的对ios推送机制的解释。如下图


Provider就是我们自己程序的后台服务器,APNS是Apple Push Notification Service的缩写,也就是苹果的推送服务器。
上图可以分为三个阶段:
第一阶段:应用程序的服务器端把要发送的消息、目的iPhone的标识打包,发给APNS。
第二阶段:APNS在自身的已注册Push服务的iPhone列表中,查找有相应标识的iPhone,并把消息发送到iPhone。
第三阶段:iPhone把发来的消息传递给相应的应用程序,并且按照设定弹出Push通知。

APNS推送通知的详细工作流程
下面这张图是说明APNS推送通知的详细工作流程:


根据图片我们可以概括一下:
1、应用程序注册APNS消息推送。
2、iOS从APNS Server获取devicetoken,应用程序接收device token。
3、应用程序将device token发送给程序的PUSH服务端程序。
4、服务端程序向APNS服务发送消息。
5、APNS服务将消息发送给iPhone应用程序。

准备工作
首先要有一台苹果的设备,模拟器是不支持推送的,所以你需要一台iphone,ipod touch或者ipad。

我们的客户端与苹果服务器之间和我们自己的服务器与苹果服务器之间都需要证书来进行链接。下面我们来开始进入证书的制作过程。

2.注册证书

首先苹果证书主要分为上线证书和测试证书,相信都有所了解 在此不再累赘了 ,

一 CSR文件
首先我们要有生成一个Certificate Signing Request(也就是CSR)的请求文件。
在应用程序里的使用工具中找到钥匙串访问。


Snip20160728_10.png

填上你的邮箱和常用名 或者是公司关联账号,常用名要记一下,一会
会用到。


Snip20160728_13.png

然后选择保存到磁盘,继续


Snip20160728_15.png

这时桌面上会有一个CertificateSigningRequest.certSigningRequest的请求文件,也就是我们说的CSR文件。在我们生成CSR文件的同时,会在钥匙串访问中

生成一对秘钥,名称为刚才我们填写的常用名

二 下载开发证书和发布证书

https://developer.apple.com/devcenter/ios/index.action登录后,在右侧的ios Developer Program里点击iOS Provisioning Portal。
进入下一级页面后在左侧选择Certificates


点击红色的部分生成一个开发证书


点击选择文件,选择刚才我们生成到桌面的CSR请求文件。
注意,如果你在后面测试的时候出现了问题,请检查一下这里,这里的CSR请求文件必须是我们刚才生成的那个



选择完成后点击Submit提交


提交完成后返回页面。页面会是这样的,然后我们刷新一下页面


刷新后会出现一个下载按钮,我们点击下载。现在我们的开发证书已经配置并下载好了,发布证书的配置过程和开发证书是一致的,不再赘述。

下载完后双击,会跳到钥匙串访问里。这就是我们之后要进行测的证书

三 配置AppID,配置并下载SSL证书
点击左侧的App IDs,找到我们要做推送功能的程序的id(如果没有的话要先New一个。注意:这里的App ID必须不能是通配的,通配的

不可以做推送)
点击Configure


进入后默认推送功能是关闭的,我们需要把推送功能打开


选中打开后,点击右边灰色的Configure按钮



这里的文件同样的,还是选择我们生成在桌面上的CSR请求文件




然后点击继续


出现了我们需要的SSL证书,我们点击下载后点击Done完成。


Status状态变成了绿色可用了。这里右边的下载和上一步的下载是一样的,如果在上一步中下载了证书,便无需再次下载。此时我们有了一

个名字叫aps_development.cer的SSL证书,同样,我们把他放在桌面。双击后会跳到钥匙串访问,出现我们的SSL推送证书
同样的,发布的SSL证书的步骤也是一样的。

四 下载Provisioning证书
在左侧选择Provisioning


配置好后点击提交(注意App ID要与我们刚的程序对应)

之后变回出现下载按钮,我们点击下载。下载后双击,并将我们的设备上的描述文件更新一下(最好把之前的全部删除,然后再安装,防止出错)。

五 从钥匙串访问中导出秘钥
打开钥匙串访问,找到我们的专用秘钥(专用秘钥的名称就是我们在最开始生成CSR请求的时候填写的常用名)


右键选择导出


导出的文件名我们叫做Push


在这里需要输入一个密码来对文件进行加密。这里我们选择abc123,当然你也可以自己选择是什么,但是这个密码必须要铭记,切记!


然后输入你电脑的密码,点击允许。
这样我们就在桌面上生成了一个Push.p12文件。

到此为止,我们在桌面上一共生成了三个文件。一个是CSR请求文件,一个是aps_development .cer的SSL证书文件,还有一个刚才生成的Push.p12秘钥文件。

现在我们的准备工作已经做完了。要开始对生成的文件进行处理了。原因上面已经解释过,因为我们的服务链接苹果服务器也是需要证书的,但是我们直接生成

的证书windows系统(我们一般的服务器都是win系统的)是不识别的,所以我们需要生成一个后缀为pem的带证书带秘钥的文件。
六 处理证书
下面我们打开终端(位置:应用程序à实用工具à终端)。
cd到桌面,我们那三个文件所在的位置

1、把.cer的SSL证书转换为.pem文件,执行命令:

openssl x509 -in aps_development.cer -inform der -out PushChatCert.pem

在桌面上会生成一个PushChatCert.pem文件



2、把私钥Push.p12文件转化为.pem文件:

openssl pkcs12 -nocerts -out PushChatKey.pem -in Push.p12


这里需要我们输入密码,这个密码也就是我们导出p12文件时的密码,也就是我们上面设置的abc123。然后,需要我们对生成的pem文件设置一个密语,这里我们推荐还是用上面这个abcabc,防止混乱(当然你也可以设置成别的更有意义的密语),这里的密语是要告诉我们服务器的。这样,桌面上又会生成一个PushChatKey.pem文件

3、对生成的这两个pem文件再生成一个pem文件,来把证书和私钥整合到一个文件里:

cat PushChatCert.pem PushChatKey.pem > ck.pem

生成ck.pem文件


这样,我们的文件就制作完了。下面进入测试阶段
为了测试证书是否工作,执行下面的命令

telnet gateway.sandbox.push.apple.com 2195

它将尝试发送一个规则的,不加密的连接到APNS服务。如果你看到上面的反馈,那说明你的MAC能够到达APNS。按下Ctrl+C关闭连接。如果得到一个错误信息,那么你需要确保你的防火墙允许2195端口。一般这里都不会出现什么问题。


下面我们要使用我们生成的SSL证书和私钥来设置一个安全的链接去链接苹果服务器:

openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert PushChatCert.pem -key PushChatKey.pem

执行完这一句命令后需要我们输入密语
Enter pass phrase for PushChatKey.pem:
我们输入abcabc按回车
你会看到一个完整的输出,让你明白OpenSSL在后台做什么。如果链接是成功的,你可以随便输入一个字符,按下回车,服务器就会断开链接,如果建立连接时有问题,OpenSSL会给你返回一个错误信息。

当你在最后的时候你看到这样说明你已经成功了:

CONNECTED(00000003)
depth=1 /C=US/O=Entrust, Inc./OU=www.entrust.net/rpa isincorporated by reference/OU=(c) 2009 Entrust, Inc./CN=Entrust CertificationAuthority - L1C
verify error:num=20:unable to get local issuercertificate
verify return:0
Certificate chain
0s:/C=US/ST=California/L=Cupertino/O=Apple >Inc./OU=iTMSEngineering/CN=gateway.sandbox.push.apple.com
i:/C=US/O=Entrust, Inc./OU=www.entrust.net/rpa is incorporated byreference/OU=(c) 2009 Entrust, Inc./CN=Entrust Certification Authority - L1C
1s:/C=US/O=Entrust, Inc./OU=www.entrust.net/rpa is incorporated byreference/OU=(c) 2009 Entrust, Inc./CN=Entrust Certification Authority - L1C
i:/O=Entrust.net/OU=www.entrust.net/CPS_2048incorp. by ref. (limits liab.)/OU=(c) 1999 Entrust.net Limited/CN=Entrust.netCertification Authority (2048)
Server certificate
-----BEGIN CERTIFICATE-----
MIIFGzCCBAOgAwIBAgIETBz90jANBgkqhkiG9w0BAQUFADCBsTELMAkGA1UEBhMC
……省略……
fMGbLqkGn8YogdPqe5T1
-----END CERTIFICATE-----
subject=/C=US/ST=California/L=Cupertino/O=AppleInc./OU=iTMS Engineering/CN=gateway.sandbox.push.apple.com
issuer=/C=US/O=Entrust, Inc./OU=www.entrust.net/rpa isincorporated by reference/OU=(c) 2009 Entrust, Inc./CN=Entrust CertificationAuthority - L1C
No client certificate CA names sent
SSL handshake has read 2731 bytes and written 2165 bytes
New, TLSv1/SSLv3, Cipher is AES256-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1
Cipher : AES256-SHA
Session-ID:
Session-ID-ctx:
Master-Key:C7A47EED5E1F5……省略……369D4
Key-Arg : None
Start Time:1361862882
Timeout : 300 (sec)
Verify return code: 0 (ok)

在这里提醒一下,也许你会看到像我这样的提示:verify error:num=20:unable to get local issuercertificate
verify return:0
其实是没问题的。


七 项目测试

建立我们的推送的项目(注意BundleIdentifier必须和我们推送应用的App id一致)

在AppDelegate里didFinishLaunchingWithOptions函数里写
- (BOOL)application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    //推送的形式:标记,声音,提示
   [[UIApplication sharedApplication] registerForRemoteNotificationTypes: UIRemoteNotificationTypeBadge
|UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert];
   return YES;
}

- (void)application:(UIApplication *)applicationdidRegisterForRemoteNotificationsWithDeviceToken:(NSData *)pToken {
   NSLog(@"regisger success:%@",pToken);
   //注册成功,将deviceToken保存到应用服务器[数据库](http://lib.csdn.net/base/14)中
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
    // 处理推送消息
    NSLog(@"userinfo:%@",userInfo);

    NSLog(@"收到推送消息:%@",[[userInfo objectForKey:@"aps"] objectForKey:@"alert"]);
}
- (void)application:(UIApplication *)applicationdidFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
   NSLog(@"Registfail%@",error);
}

我们运行程序的时候会有提示,说我们的程序要发送推送通知

下面我们把php服务器代码和生成的ck.pem文件放在统一文件夹下面(这里我们还是统一放在桌面上)。
用Xcode打开(其他工具也可以)php服务器端的代码,把deviceToken改成我们现在要进行测试的iphone的deviceToken(获得方法:首先运行我们的程序,程序启动后打印的日志文件里可以看到。感谢 边玩勺子把儿去 同学的提醒),密语改成我们之前设置的abc123。然后保存。
然后在终端运行命令(如果刚才你关闭了终端的话,最好ls一下,看看当前是不是在桌面),执行命令:
php pushMe.php
然后回车(pushMe为服务器文件名称)


如果出现这样的提示说明成功了,然后在iphone上,我们期待已久的推送消息终于来了。


IMG_2759.PNG
常见问题:

1、在用证书和秘钥链接服务器时出现提示:

Error opening client certificate private key filePushChatKey.pem20839:error:02001002:system library:fopen:No such file ordirectory:/SourceCache/OpenSSL098/OpenSSL098-44/src/crypto/bio/bss_file.c:356:fopen('PushChatKey.pem','r')
20839:error:20074002:BIO
routines:FILE_CTRL:systemlib:/SourceCache/OpenSSL098/OpenSSL098-44/src/crypto/bio/bss_file.c:358:
unable to load client certificate private key file

解决:
文件路径不对。cd到生成的pem文件路径下再进行链接

2、前期测试没有问题,将ck.pem给服务器,通过服务器进行推送时推送不成功,提示链接APNS失败。
解决:一,看一下证书的名称,密语是否正确;二,路径是否正确;然后检查一下库,OpenSSL和libssl;此外apache还要开启OpenSSL权限,确保可以访问pem

3、APNS地址 (**一定记住切换地址,好多推送不成功就是地址不对,pushMe.php中的代码地址我已经换成测试的了**)
测试地址gateway.sandbox.push.apple.com:2195
发布地址 gateway.push.apple.com:2195
测试的地址用的是沙盒,发布地址是不同的。发布软件的时候记得改过来

4、要注意顺序问题,一定要按照这个顺序来:
生成钥匙串请求 -->配置下载开发证书--> 配置App ID ,配置、下载SSL证书-->Provisioning证书

实例代码 和 pushMe.php

下载地址:github: https://github.com/one-tea/APNS_test.git
有什么问题可以与我私信,如果喜欢欢迎关注,更好的东西共享给大家!
后台的配置问题
在这里说下后台配置,主要分两类:
一. Java、PHP可以通用,上面pushMe.php也就是适用代码;

二. 另一种有.net后台的(比如我们公司),给后台证书为.p12格式 制作方法:
在钥匙中找到你安装过的推送证书,记不住就返回上面证书配置那块看


Snip20160803_12.png

Snip20160803_13.png

导出为.p12,密钥也为abc123好了, 这个秘钥需要和.p12一起给后台
至于后台有写好的代码 .net 项目中引PushSharp.Apple.dll,PushSharp.Core.dll(这两个文件在网上搜一下,有源码的)

文/海诺_简书(简书作者)
原文链接:http://www.jianshu.com/p/032bfc949917
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

iOS 远程消息推送,原理和开发详解篇(新手推荐)的更多相关文章

  1. iOS远程消息推送原理

    1. 什么是远程消息推送? APNs:Apple Push Notification server 苹果推送通知服务苹果的APNs允许设备和苹果的推送通知服务器保持连接,支持开发者推送消息给用户设备对 ...

  2. 分分钟搞定IOS远程消息推送

    一.引言 IOS中消息的推送有两种方式,分别是本地推送和远程推送,本地推送在http://my.oschina.net/u/2340880/blog/405491这篇博客中有详细的介绍,这里主要讨论远 ...

  3. iOS远程消息推送自我整理版

    @interface AppDelegate () <UIApplicationDelegate> @end @implementation AppDelegate - (BOOL)app ...

  4. iOS远程消息推送

    iOS 推送基础知识 Apple 使用公共密钥数字证书对来自 iOS 应用程序的推送请求进行身份验证,所以您首先需要创建身份验证密钥,并向 Apple 注册它们.我将在下一节中花相当长的篇幅来直接介绍 ...

  5. iOS开发消息推送原理

    转载自:http://www.cnblogs.com/cdts_change/p/3240893.html 一.消息推送原理: 在实现消息推送之前先提及几个于推送相关概念,如下图1-1: 1.Prov ...

  6. iOS开发——远程消息推送的实现

    在我们使用App的过程中.总是会收到非常多的消息推送.今天我们就要来实现这个功能.首先消息推送分为本地消息推送和远程消息推送.而当中又以远程消息最为经常使用. 可是在推送远程消息之前.有两个前提条件. ...

  7. iOS开发笔记8:Remote Notification远程消息推送处理

    远程消息推送处理场景有三种:分别是app还没有运行.app在前台运行以及app在后台运行,下面介绍相关流程及三种场景下处理步骤 1.流程 (1)注册通知 首先是在注册远程消息推送,需要注意的是iOS8 ...

  8. IOS - 消息推送原理和实现

    一.消息推送原理: 在实现消息推送之前先提及几个于推送相关概念,如下图1-1: 1.Provider:就是为指定IOS设备应用程序提供Push的服务器,(如果IOS设备的应用程序是客户端的话,那么Pr ...

  9. iOS 消息推送原理及实现Demo

    一.消息推送原理: 在实现消息推送之前先提及几个于推送相关概念,如下图1-1: 1.Provider:就是为指定IOS设备应用程序提供Push的服务器,(如果IOS设备的应用程序是客户端的话,那么Pr ...

随机推荐

  1. 导出数据子集:带where条件的exp导出

    举个例子:用select * from all_objects创建了一张表T.想要导出object_id小于5000的所有行.(1)windows下: exp userid=cms0929/cms09 ...

  2. async/await 的一些知识

    博文 Don't Block on Async Code What is the purpose of "return await" in C#? Any difference b ...

  3. /usr,/usr/local/ 还是 /opt ?

    Linux 的软件安装目录是也是有讲究的,理解这一点,在对系统管理是有益的(好吧处女座表示完全不能接受不正确的路径选择,看着会不舒服的……) /usr:系统级的目录,可以理解为C:/Windows/, ...

  4. ACM Ignatius and the Princess II

    Problem Description Now our hero finds the door to the BEelzebub feng5166. He opens the door and fin ...

  5. MongoDB 排序

    MongoDB sort()方法 在MongoDB中使用使用sort()方法对数据进行排序,sort()方法可以通过参数指定排序的字段,并使用 1 和 -1 来指定排序的方式,其中 1 为升序排列,而 ...

  6. Docker 列出镜像

    使用 docker images 显示本地已有的镜像. $ sudo docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE ubuntu ...

  7. Java异常处理-----finally

    finally 1: 实现方式一: try{ // 可能发生异常的代码 } catch( 异常类的类型 e ){ // 当发生指定异常的时候的处理代码 }catch- 比较适合用于专门的处理异常的代码 ...

  8. 【安卓开发】用PageTransformer打造更好的动画效果

    Android的ViewPager类已经变成一个相当流行的Android应用组件了.它简单直观,并且提供了极好的功能.你可以经常在设置向导,图片画廊种看到它,它还是分开应用内容的良好方式. 标准的Vi ...

  9. Java基本语法-----java二维数组

    由于word里的样式在csdn上调太麻烦了,所以我再次贴图了,后面二维数组那里是文字的,大家将就看吧. 二维数组常见的操作: 1.遍历二维数组 2.对二维数组求和 class Demo { // 定义 ...

  10. Android必知必会-获取View坐标和长宽的时机

    如果移动端访问不佳,请访问–>Github版 背景 最近要实现一个功能,用到了一些属性动画,需要获取一些View的坐标信息,设计图如下: 这里我使用的是DialogFragment来实现的,可以 ...