今天研究了下ios的远程推送,网上的相关教程很多,做了一遍下来记录一下遇到的问题和注意事项(转载请注明)

1.证书及乱七八糟的配置

  公钥:app id管理那儿的“Development Push SSL Certificate” push证书,我这儿下载下来叫"aps_developer.cer"

  私钥:申请证书时候从钥匙串生成的"CertificateSigningRequest.certSigningRequest"文件在"钥匙串->密钥"那儿生成的与之前输入的名字相同的“专用密钥”,可以右键导出为***.p12文件

  合成PEM证书

  1)转换公钥

openssl x509 -in aps_developer.cer -inform der -out public.pem

  2)转换私钥

openssl pkcs12 -nocerts -in MyPushChatKey.p12 -out private.pem

  (这时候要输入密码的)

  有了这两个pem文件其实就可以测试一下能否联通苹果的服务器了,网上有,就简写了

telnet gateway.sandbox.push.apple.com 2195 (测试是否能连通苹果的推送测试服务器)
Trying 17.172.232.226...
Connected to gateway.sandbox.push-apple.com.akadns.net.
Escape character is '^]'.

  要是出现上面的结果就ok了,然后测试刚才的两个pem:

openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert public.pem -key private.pem

  输完密码之后,要是输出一堆提示信息就算是ok了

  3)把两个证书合成(为了服务器用着方便)

cat public.pem private.pem > push_cert.pem

  (这里先输入私钥密码,再输入合成之后的新密码,新密码得记住了,之后server用这个pem发推送的时候要用到)

  保存好这些文件,证书这就算ok了。

 2.在app里获得deviceToken

  刚才一步是让app和苹果推送服务器以及server和苹果推送服务器之间用证书建立起了安全的连接通行证,要想真正实现推送还要有一个deviceToken,设备的唯一令牌,在appDelegateDidFinishLunch里面加入代码:

    //请求远程推送
UIRemoteNotificationType type = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound |UIRemoteNotificationTypeAlert;
[application registerForRemoteNotificationTypes:type];

  这个type是可选的推送的三个属性,这句话一旦运行之后app就会弹出aleat说请求推送通知是否许可,用户选择之后就进入了

- (void)application:didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
- (void)application:didFailToRegisterForRemoteNotificationsWithError:(NSError *)error

  两个方法其中一个内,要是成功了就获得了一个deviceToken,不过我试验的时候出现了error:

Error: Error Domain=NSCocoaErrorDomain Code=3000 UserInfo=0x1655c0 "未找到应用程序的“aps-environment”的权利字符串"

  排查之后发现问题是本地的provisioning Profiles(我觉得翻译成开发许可证之类的)并不是最新的(配置过push之后的),最简单的解决办法是在xcode的orgnizer里面把之前的证书删了,把苹果账户后台那儿的profile删了重建一次,再从orgnizer那儿refresh下来,之后就解决了。

  获得了一个device token

<b5fb5f22 d764c335 aba18eca 0114e8af acb74ff7 4e624dfe 24c9d59f 8fb6a903>

  这个关键的东西就拿到了,一个手机对一个app生成的这个deviceToken是唯一的,要想服务器发推送这个token就要上传到服务器上去。

  趁着写这个,先写着app接到远程push时候的回调,简单Log一下

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
  NSLog("remote push:%@", userInfo);
}

3.用python写个简单的测试push server

  这里有个open source的封装openssl(s_client)的python包,APNSWrapper,可以方便的使用它给苹果推送服务器发送请求,就可以不care苹果规定的那个严格的发送包的格式了,不过苹果规定推送的数据不能超过256字节,没试过。

http://code.google.com/p/apns-python-wrapper/wiki/APNSWrapperOverview

  这个库先别install,直接引用着,后面要改它源码小优化下

  按这个lib提供的例子就能挺简单的使用,不过用起来就发现一些问题(也怪我python刚学)

  1) 引用,引这个lib的时候,这个库把__init__.py当做整个库的索引了

import sys
sys.path.append("./APNSWrapper")
from __init__ import *

  2) deviceToken,这真心蛋疼,我之前2了,一直以为token是带着那个尖括号的一串,其实是里面那8X8的串,而且要把空格去掉

  目测这个样子

deviceToken = “b5fb5f22d764c335aba18eca0114e8afacb74ff74e624dfe24c9d59f8fb6a903”

  但是这个怎么测试也不对,后发现苹果给的这个token并不是他要我们传过去的,而是要转码一下

import binascii
deviceToken = binascii.unhexlify("b5fb5f22d764c335aba18eca0114e8afacb74ff74e624dfe24c9d59f8fb6a903");

  解16进制之后的这个token才是最后我们要传过去进行通讯的token

  之后就可以写发送的代码了,测试了一个最简单的推送

#创建通知对象
notification = APNSNotification()
notification.token(deviceToken)
notification.alert("alert")
notification.badge(5)
notification.sound() #创建发送通知的这个wrapper
pem_cert_name = "push_cert.pem"
wrapper = APNSNotificationWrapper(pem_cert_name, True)
wrapper.append(notification)
wrapper.notify()

  运行这个python文件之后,会要求输入PEM的密码,在之后等一两秒,刚部署程序的真机就发出了熟悉的提示音,提示内容就是刚才alert的内容了

  打开推送进入程序之后,刚才Log的地方打印出了一个推送数据的dict,这就算成功了。

4.额外内容,使用PEM证书时省去一遍遍输入密码以及一次验证多次推送

  网上的教程大多就止于上面的内容了,但是真正的推送服务器跑起来之后怎么也不能每个推送验证一遍证书输一次密码吧,起初试了openssl的命令移除pem里面的密码,但貌似不好使,于是就想到了把密码嵌入到openssl的命令行里面(APNSWrapper里面本质上等价于在命令行里输入openssl命令(打开强制命令行属性后)),找了半天发现代码是命令后加上<-pass pass:my_password>,于是乎找这个APNSWrapper的代码,在connection.py中找到了:

    def _command(self):
command = "%(executable)s s_client -ssl3 -cert %(cert)s -connect %(host)s:%(port)s % \
{
'executable' : self.executable,
'cert' : self.certificate,
'host' : self.host,
'port' : self.port
}

  这就是他内部组合这个command的地方,最简单的方法直接把这个command串后面加上刚才的密码,类似:

    def _command(self):
command = "%(executable)s s_client -ssl3 -cert %(cert)s -connect %(host)s:%(port)s -pass pass:MY_PASSWORD" % \
{
'executable' : self.executable,
'cert' : self.certificate,
'host' : self.host,
'port' : self.port
}

  ok,再重新运行试试发现木有变化,原因是APNSConnection(APNSConnectionContext):这个类里会如果不设置force_ssl_command会优先使用SSLModuleConnection执行:

    try:
if force_ssl_command:
raise ImportError, "There is force_ssl_command forces command line tool" # use ssl library to handle secure connection
import ssl as ssl_module
self.connectionContext = SSLModuleConnection(certificate, ssl_module = ssl_module)
except:
# use command line openssl tool to handle secure connection
if not disable_executable_search:
executable = find_executable(ssl_command)
else:
executable = ssl_command if not executable:
raise APNSNoCommandFound, "SSL Executable [%s] not found in your PATH environment" % str(ssl_command) self.connectionContext = OpenSSLCommandLine(certificate, executable, debug = debug, password = password)

  好办,在数值化这个Wrapper的时候把这个参数设上就好了:

#1.cert 2.is_sandbox 3.will_debug 4.force_ssl_command
wrapper = APNSNotificationWrapper('push_cert.pem', True, False, True)

   再次运行,发现不用输入密码就ok了。

  其实这个方法并不地道,在参考http://www.36coder.com/study/1012.html 的文章之后明白了其实可以只进行一次验证证书之后进行N次发送推送,这也是openssl支持的通信方式,只是这个库没有封装罢了,按照这为仁兄的方法改过之后,这个简单的python push server就可以挺不错的工作了,当然真实的情况下这个deviceToken是和user一一对应的,每次都要提取相应的token而非测试时候的写死,而且真正上线之后的推送服务器地址也是把刚才地址里面的sandbox去掉。

  远程推送这块就算ok了,by the way这个推送推过来的速度真心不确定,在单位的时候瞬间收到,回到宿舍的时候就过了半分钟才收到,测试时候还得耐心等等。还有真心希望网上的筒子们不要死转一篇文章,怎么也加上点亲测之后遇到的问题,多一点有价值的内容而不是无限重复的内容。

ios远程推送和python版push server相关笔记的更多相关文章

  1. iOS远程推送之友盟Push

    更新记录: 1.2015年10月23日上午10:10分更新,优化了该类,去除了不必要的方法. ----------------------------------------------------- ...

  2. IOS远程推送

    IOS远程推送 一.关于推送通知 推送通知,也被叫做远程通知,是在iOS 3.0以后被引入的功能.是当程序没有启动或不在前台运行时,告诉用户有新消息的一种途径,是从外部服务器发送到应用程序上的.一般说 ...

  3. iOS远程推送原理及实现过程

    ➠更多技术干货请戳:听云博客 推送通知,是现在的应用必不可少的功能.那么在 iOS 中,我们是如何实现远程推送的呢?iOS 的远程推送原理又是什么呢?在做 iOS 远程推送时,我们会遇到各种各样的问题 ...

  4. iOS APNs远程推送流程精简版

    1.去Apple Developer Center里创建应用的信息,指定APP ID(Bundle ID),配置里开启推送功能(Push Notifications). 后续步骤需要用到这个应用的包名 ...

  5. iOS 远程推送通知 详解

    1: ios本地通知和远程通知 http://wangjun.easymorse.com/?p=1482 2: 苹果远程通知服务申请激活例图 (外国佬写的.) http://mobiforge.com ...

  6. iOS 远程推送通知

    1.什么是推送通知 在某些特殊情况下,应用程序被动收到的以不同种界面形式出现的提醒信息 推送通知的作用:可以让不在前台运行的app通知app发生了改变 iOS中得推送通知种类 远程推送通知(Remot ...

  7. IOS 远程推送通知(UIRemoteNotification)

    ●  什么是远程推送通知 ●  顾名思义,就是从远程服务器推送给客户端的通知(需要联网) ●  远程推送服务,又称为APNs(Apple Push Notification Services) ●   ...

  8. iOS远程推送1

    一.APNS 远程推送 1.所有的苹果设备,在联网状态下,都会与苹果服务器建立长连接. 2.长连接:就是只要联网了,就一直建立连接. 3.长连接的作用:时间校准,系统升级,查找我的iPhone. 4. ...

  9. [置顶] 手把手教你iOS消息推送证书生成以及Push消息

    iOS推送消息是许多iOS应用都具备的功能,今天在给应用加推送功能,在生成证书的过程中,发生了各种令人蛋痛的事.下面就把步骤拿出来分享下: iOS消息推送的工作机制可以简单的用下图来概括: Provi ...

随机推荐

  1. 超线程技术——超线程技术让(P4)处理器增加5%的裸晶面积,就可以换来15%~30%的效能提升,本质单核模拟双核!和异步编程的思想无异。

    超线程是Intel 所研发的一种技术,于2002年发布.超线程的英文是HT技术,全名为Hyper-Threading,中文又名超线程.超线程技术原先只应用于Intel Xeon处理器中,当时称为Sup ...

  2. js页面报错javax.servlet.jsp.PageContext cannot be resolved to a type解决

    构建了一个maven项目但是项目创建好的jsp总会报错javax.servlet.jsp.PageContext cannot be resolved to a type,但是不影响项目运行.但总归难 ...

  3. Python之Split函数

    python中的split()函数用来拆分一个字符串,通过指定的分隔符对字符串进行切割,返回切割后的字符串列表list. split()函数用法: str.split(str=' ',num = st ...

  4. 稳定婚姻(tarjan)

    传送门 这道题一开始可能以为是二分图匹配……?不过后来发现和二分图没啥大关系. 简单分析之后发现,把夫妻之间连边(男性向女性连边),之后再将每对曾经是情侣的人连边(女性向男性连边),当然以上的方向可以 ...

  5. 单纯形 BZOJ3112: [Zjoi2013]防守战线

    题面自己上网查. 学了一下单纯形.当然 证明什么的 显然是没去学.不然估计就要残废了 上学期已经了解了 什么叫标准型. 听起来高大上 其实没什么 就是加入好多松弛变量+各种*(-1),使得最后成为一般 ...

  6. java日期和时间戳格式互转

    // 将日期格式转换成时间戳 public static void main(String[] args) throws Exception{ String time = "2018-05- ...

  7. Tomcat闪退的解决办法

    1 首先考虑的是端口占用 2 现在讲的是这一种方法 (1)找到解压缩的文件的bin目录 找到startup.bat 记事本打开 开头加上两句话 SET JAVA_HOME=C:\Program Fil ...

  8. UVa 12712 && UVaLive 6653 Pattern Locker (排列组合)

    题意:给定 一个n * n 的宫格,就是图案解锁,然后问你在区间 [l, r] 内的所有的个数进行组合,有多少种. 析:本来以为是数位DP,后来仔细一想是排列组合,因为怎么组合都行,不用考虑实际要考虑 ...

  9. bzoj 1640||1692: [Usaco2007 Dec]队列变换【后缀数组】

    注意输出是80字符个一行!! 首先贪心很显然,就是两头尽量拿小的. 然后需要处理两头一样的情况,显然是选字典序小的一串,把数组反着接在原数组后面,然后跑sa,判断的时候直接比较rk数组 #includ ...

  10. quickpow || 快速幂

    洛谷例题 推荐自行脑补:百度百科 如果  ,那么 : 前言:快速幂就是快速算底数的n次幂.其时间复杂度为 O(log₂N), 与朴素的O(N)相比效率有了极大的提高. 拿题目样例 Input :2 1 ...