设为首页 收藏本站
查看: 1228|回复: 0

[经验分享] ios远程推送和python版push server相关笔记

[复制链接]

尚未签到

发表于 2015-4-23 05:25:41 | 显示全部楼层 |阅读模式
  今天研究了下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




  这个关键的东西就拿到了,一个手机对一个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命令(打开强制命令行属性后)),找了半天发现代码是命令后加上,于是乎找这个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这个推送推过来的速度真心不确定,在单位的时候瞬间收到,回到宿舍的时候就过了半分钟才收到,测试时候还得耐心等等。还有真心希望网上的筒子们不要死转一篇文章,怎么也加上点亲测之后遇到的问题,多一点有价值的内容而不是无限重复的内容。
  
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-59670-1-1.html 上篇帖子: Python的SimpleHTTPServer 下篇帖子: Python Twisted 框架中 socket通信
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表