ios远程推送和python版push server相关笔记
今天研究了下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相关笔记的更多相关文章
- iOS远程推送之友盟Push
更新记录: 1.2015年10月23日上午10:10分更新,优化了该类,去除了不必要的方法. ----------------------------------------------------- ...
- IOS远程推送
IOS远程推送 一.关于推送通知 推送通知,也被叫做远程通知,是在iOS 3.0以后被引入的功能.是当程序没有启动或不在前台运行时,告诉用户有新消息的一种途径,是从外部服务器发送到应用程序上的.一般说 ...
- iOS远程推送原理及实现过程
➠更多技术干货请戳:听云博客 推送通知,是现在的应用必不可少的功能.那么在 iOS 中,我们是如何实现远程推送的呢?iOS 的远程推送原理又是什么呢?在做 iOS 远程推送时,我们会遇到各种各样的问题 ...
- iOS APNs远程推送流程精简版
1.去Apple Developer Center里创建应用的信息,指定APP ID(Bundle ID),配置里开启推送功能(Push Notifications). 后续步骤需要用到这个应用的包名 ...
- iOS 远程推送通知 详解
1: ios本地通知和远程通知 http://wangjun.easymorse.com/?p=1482 2: 苹果远程通知服务申请激活例图 (外国佬写的.) http://mobiforge.com ...
- iOS 远程推送通知
1.什么是推送通知 在某些特殊情况下,应用程序被动收到的以不同种界面形式出现的提醒信息 推送通知的作用:可以让不在前台运行的app通知app发生了改变 iOS中得推送通知种类 远程推送通知(Remot ...
- IOS 远程推送通知(UIRemoteNotification)
● 什么是远程推送通知 ● 顾名思义,就是从远程服务器推送给客户端的通知(需要联网) ● 远程推送服务,又称为APNs(Apple Push Notification Services) ● ...
- iOS远程推送1
一.APNS 远程推送 1.所有的苹果设备,在联网状态下,都会与苹果服务器建立长连接. 2.长连接:就是只要联网了,就一直建立连接. 3.长连接的作用:时间校准,系统升级,查找我的iPhone. 4. ...
- [置顶] 手把手教你iOS消息推送证书生成以及Push消息
iOS推送消息是许多iOS应用都具备的功能,今天在给应用加推送功能,在生成证书的过程中,发生了各种令人蛋痛的事.下面就把步骤拿出来分享下: iOS消息推送的工作机制可以简单的用下图来概括: Provi ...
随机推荐
- ab压力测试-突破最大线程数
ab压力测试中,发现你一次最多只能启动1024个线程 默认情况下,一个线程的栈要预留1M的内存空间 而一个进程中可用的内存空间只有2G,所以理论上一个进程中最多可以开2048个线程 但是内存当然不可能 ...
- 详解Python的*args和 **kwargs
转自: http://www.python[tab].com/html/2016/pythonhexinbiancheng_0802/1057.html *args表示任何多个无名参数,它是一个tup ...
- js bind es5函数柯里化
绑定函数 bind()最简单的用法是创建一个函数,使这个函数不论怎么调用都有同样的this值.常见的错误就像上面的例子一样,将方法从对象中拿出来,然后调用,并且希望this指向原来的对象. 如果不做特 ...
- bzoj2693
线性筛+莫比乌斯反演 盗波图 来自candy?大神 反演很重要的一条公式就是[gcd(i,j)==1]= 线性筛怎么推呢? 我们分4个步骤,1.先推出f[1],2.推出f[p],p是一个质数,3.由于 ...
- 最小割树Gomory–Hu tree
fanhq666地址:http://fanhq666.blog.163.com/blog/static/8194342620113495335724/ wiki地址(证明):https://en.wi ...
- 小程序 video 层级,原生组件
原生组件的层级是最高的,所以页面中的其他组件无论设置 z-index 为多少,都无法盖在原生组件上. 后插入的原生组件可以覆盖之前的原生组件. 原生组件还无法在 scroll-view.swiper. ...
- Windows服务使用log4net记录日志
该文章是系列文章 基于.NetCore和ABP框架如何让Windows服务执行Quartz定时作业 的其中一篇. 比较流行的日志组件有以下四种,Topshelf都有相应的组件提供 log4net NL ...
- iOS Debug心得 (持续更新)
最近在维护一个内部比较混乱的APP,Debug的时候遇到很多比较痛苦的地方, 因此做一个Debug记录,对以后的开发会有比较大的帮助: 这样,在开发新项目的时候就可以争取把一些BUG扼杀在襁褓中. & ...
- CAD中的相对坐标和绝对坐标
绝对坐标就是你作图的整个界限的原点,也就是CAD系统默认的原点坐标. 相对坐标就是相对于当前的点的坐标. 这两种坐标都有,可以根据习惯和需要自己看使用哪种. 一.绝对坐标 ①笛卡尔坐标(X,Y,Z) ...
- linux 重名名、删除文件操作
linux下重命名文件或文件夹的命令mv既可以重命名,又可以移动文件或文件夹. 例子:将目录A重命名为B mv A B 例子:将/a目录移动到/b下,并重命名为c mv /a /b/c 删除文件夹 r ...