现在APLLE的应用越来越广泛,对于开发者来说APPLE应用开发也多少会接触到,笔者也通过这周APLLE推送服务器的搭建慢慢有所体会
笔者是使用python2.5+django1.4+apache2.2+mysql4.0所搭建的服务器,网页设计部分用的DREAMWEAVER,python的一些小插件更新的太慢所以不得不用2.5版本了,
首先应该对PUSH服务器有所了解,建议参考以下文章:
http://www.cnblogs.com/menghe/archive/2012/02/20/2359278.html 证书的创建
http://hb.qq.com/a/20111128/000536.htm iOS开发如何实现消息推送机制
django和mysql的配置部分就不详细介绍了,可参考我另一边博文:http://blog.csdn.net/wulei202/article/details/7667473
准备工作做完后即可着手搭建服务器了
首先应在winxp 环境为python2.5加上ssl库:
该过程中可能有些步骤可以发生变动
1 在http://pypi.python.org/pypi/ssl/下载的 ssl-1.15.tat.gz 只能下载到source包需要自己编译,解压该文件目录为SSL-1.15
2 下载mingw32 在http://sourceforge.net/projects/mingw/files/点击mingw-get-inst-20110530.exe
3 下载Oenssl 在http://gnuwin32.sourceforge.net/packages/openssl.htm选择Developer files
4 下载libgw32c 在http://gnuwin32.sourceforge.net/packages/libgw32c.htm选择Developer files
5这是个在线安装程序、后面的日期灵活变动。我安装时全选安装所有功能、貌似选择g++编译器和mingw make环境即可
然后新建批处理abc.bat内容如下:
set PATH=%PATH%;D:\MinGW\bin
set LIBRARY_PATH=D:\MinGW\lib
set C_INCLUDE_PATH=D:\MinGW\include
在MinGW下新建文件夹abc解压Oenssl和libgw32c到D:\MinGW\abc,后解压的哪个若提示是否替换原有的文件、点全部。
abc下的目录为abc\include,abc\lib,abc\manifest
在SSL-1.15目录下修改setup.py搜索gnuwin32_dir 将其改为
gnuwin32_dir = os.environ.get("GNUWIN32_DIR", r"D:\MinGW\abc")
在命令提示符中切换到SSL-1.15目录输入
python setup.py build -c mingw32 install即可完成PYTHONT 2.5的ssl库添加
6 测试SSL
在命令提示符中输入python打开python的CLI
然后输入import ssl若提示No module named _ssl2
进入C:\Python25\Lib\site-packages\SSL,删除__init__.pyc
然后再在命令提示符中切换到SSL-1.15目录输入
python setup.py build -c mingw32 install
重新再测试应该会不再报错
笔者在sourceforge上下载时出了问题,居然打不开(原因我想都懂的,不得不抱怨下国内的技术环境了怪不得赶不上国外)得亏公司有VPN才得以解决问题
完成ssl库导入之后就要导入json库了,这个在网上搜下就有
ssl及json库导入完成之后就剩下APNs with python 了
APNs 可以参考 http://mobiforge.com/developing/story/programming-apple-push-notification-services
代码可参考:
import socket, ssl, json
deviceToken = "11111111 22222222 aaaaaaaa bbbbbbbb cccccccc dddddddd eeeeeeee ffffffff" #换成你的deviceToken
data = json.dumps({"aps":{"alert":"Hello!"}})
ssl_sock = ssl.wrap_socket(socket.socket(socket.AF_INET, socket.SOCK_STREAM), certfile="certDist.pem") #换成你上面生成的pem
ssl_sock.connect(("gateway.push.apple.com", 2195)) #测试版本用gateway.sandbox.push.apple.com
data = data.decode('gbk').encode('utf-8') #因为你发送的数据有可能是中文,故而需要转换
ssl_sock.write(chr(0)+chr(0)+chr(32)+deviceToken.replace(' ','').decode('hex')+chr(0)+chr(len(data))+data)
ssl_sock.close()
除了发送消息我们应该还有个注册页面来得到令牌ID号
python代码部分:
# encoding: utf-8
import binascii,socket
import ctypes
from MySQLdb.constants.CLIENT import SSL
import ssl,json
from encodings import hex_codec
from django.http import HttpResponseRedirect
from django.http import HttpResponse
from ssl._ssl2 import *
from iospushapp.models import *
from django.shortcuts import render_to_response
def iospost(request):
TextOut = request.POST.get('textfield1', None)
TextPush = unicode(TextOut)#变为unicode版字符
TextPush = TextPush.replace(' ','')
TextPush = TextPush.replace('\r\n','')
if TextPush:
if len(TextPush.decode('gbk').encode('utf-8')) > 255:
return render_to_response('iospush.html', {'result':'发送字符数超出!'})
else:
nId = iospushId.objects.count()
strFull = 'id='
iRet = 0
iCount = 0
mode = iospushId.objects.all()
#mode.iterator()
while iCount < nId:
#strMode = iospushId.objects.get(id=iCount+1)
strMode = mode[iCount]
deviceToken = str(strMode.PushId)
#deviceToken.decode('gbk').encode('utf-8')
ibadge = strMode.PushNum + 1
#data = json.dumps({"aps":{"alert":TextPush}})
data = json.write({"aps":{"alert":TextPush,"badge":ibadge,"sound":"default"}})
ssl_sock = ssl.wrap_socket(socket.socket(socket.AF_INET, socket.SOCK_STREAM), certfile="yftechpushck_unencrypted.pem")
#ssl_sock = ssl.wrap_socket(socket.socket(socket.AF_INET, socket.SOCK_STREAM),ca_certs="yftechpushck.pem",cert_reqs=ssl.CERT_REQUIRED)
#ssl_sock = ssl.wrap_socket(socket.socket(socket.AF_INET, socket.SOCK_STREAM),certfile='cer.pem',keyfile='key.pem',\
# ssl_version = PROTOCOL_SSLv23, ca_certs="yftechpushck.pem",cert_reqs=ssl.CERT_REQUIRED,\
# do_handshake_on_connect = False)
ssl_sock.connect(("gateway.sandbox.push.apple.com", 2195)) #测试版本用gateway.sandbox.push.apple.com
data = data.decode('gbk').encode('utf-8')
strSend = chr(0)+chr(0)+chr(32)+deviceToken.replace(' ','').decode('hex')+chr(0)+chr(len(data))+data
nNum = ssl_sock.write(strSend)
if nNum == len(strSend):
strMode.PushNum+=1
strMode.save()
else:
strFull+=unicode(strMode.id) +';'
iRet = 1
ssl_sock.close()
iCount+=1
#str = TextPush + binascii.a2b_hex('967360565f') + strID.replace(' ','').decode("hex")
#str = str.encode('utf-8')
if 0 == iRet:
return render_to_response('iospush.html', {'result':'发送成功','textare':''})#,'textare':str
else:
strFull+=u'发送失败!'
return render_to_response('iospush.html', {'result':strFull ,'textare':''})#,'textare':str
else:
return render_to_response('iospush.html', {'result':'发送内容不得为空!'})
def initpost(request):
return render_to_response('iospush.html',{'result':'请输入发送字符(小于85)'})
网页部分:
<form method="post" action="/loginid/">
<p class="STYLE1" style="text-align:center"> </p>
<p class="STYLE1" style="text-align:center"> </p>
<p class="STYLE1" style="text-align:center"> </p>
<p class="STYLE1" style="text-align:center">IOS令牌登记</p>
<p class="STYLE1" style="text-align:center">
<input name="textfieldlogin" type="text" size="74" maxlength="100" height="20">
</p>
<p class="STYLE1" style="text-align:center"> </p>
<p class="STYLE1" style="text-align:center">
<input type="submit" name="Submit" value="提交" width="30" height="66">
</p>
<p class="STYLE1" style="text-align:center"> </p>
<p class="STYLE1" style="text-align:center">{{result}}</p>
<p> </p>
</form>
点击提交即可保存令牌ID