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 ...
随机推荐
- Activity并行网关和排他网关
说一说activiti中的排他网关和并行网关 activiti工作流中我们经常用到的网关有两种: 1. Exclusive Gateway 排他网关 排他网关.png 排他网关(也叫异或(XOR)网关 ...
- 协议森林02 小喇叭开始广播 (以太网与WiFi协议)
作者:Vamei 出处:http://www.cnblogs.com/vamei 严禁任何形式转载. “小喇叭开始广播啦”,如果你知道这个,你一定是老一辈的人.“小喇叭”是五十年代到八十年代的儿童广播 ...
- 黑客常用WinAPI函数整理
之前的博客写了很多关于Windows编程的内容,在Windows环境下的黑客必须熟练掌握底层API编程.为了使读者对黑客常用的Windows API有个更全面的了解以及方便日后使用API方法的查询,特 ...
- Linux 常用命令十三 kill
一.kill命令 kill命令用来删除执行中的程序或工作.kill可将指定的信息送至程序.预设的信息为SIGTERM(15),可将指定程序终止.若仍无法终止该程序,可使用SIGKILL(9)信息尝试强 ...
- bzoj 303: [CQOI2009]中位数图【前缀和+瞎搞】
处理出一个序列c,a[i]>b,c[i]=1;a[i]==b,c[i]=0;a[i]<b,c[i]=-1,然后s为c的前缀和,设w为b在a序列里的下标 注意到子序列一定横跨w,并且一个符合 ...
- bzoj 4071: [Apio2015]巴邻旁之桥【splay】
用权值线段树会容易一些并快一些,但是想复健一下splay所以打了splay 然后果然不会打了. 解题思路: 首先把家和办公室在同一侧的提出来直接加进答案里: 对于k=1,直接选所有办公室和家的中位数即 ...
- bzoj3118: Orz the MST(线性规划+单纯形法)
传送门 不难发现,对于每一条树边肯定要减小它的权值,对于每一条非树边要增加它的权值 对于每一条非树边\(j\),他肯定与某些树边构成了一个环,那么它的边权必须大于等于这个环上的所有边 设其中一条边为\ ...
- python的安装教学
1.首先登陆到python的官方网站 https://www.python.org/ 2.鼠标放在Download上,点击下面对应的型号,我的是Windows 3.点击Windows到此页面,点击3. ...
- golang——关于for循环的学习
1.for循环的用法 (1)常规用法 func main() { slice := []int{1, 2, 3, 4, 5, 6} //方式1 for i := 0; i < len(slice ...
- LightOj 1197 Help Hanzo (区间素数筛选)
题目大意: 给出T个实例,T<=200,给出[a,b]区间,问这个区间里面有多少个素数?(1 ≤ a ≤ b < 231, b - a ≤ 100000) 解题思路: 由于a,b的取值范围 ...