http://www.cocoachina.com/industry/20130321/5862.html
原文太常了,就不转了。可以去原文看。写的很全面。
ios8中的推送,看下文
http://blog.youkuaiyun.com/apple_app/article/details/39228221
上边的文章讲的是使用php的,下边这个是使用pyhton的一个第三方库实现的。
另一个python推送,applepush:http://python.jobbole.com/86847/
pip install applepush
http://www.tuicool.com/articles/aqYBna
pip install pyapns
或者使用
easy_install pyapns
如果上边两个下载twistd有问题,可以从下边的地址下载twistd
或者直接在服务器终端里输入:
curl -O https://pypi.python.org/packages/18/85/eb7af503356e933061bf1220033c3a85bad0dbc5035dfd9a97f1e900dfcb/Twisted-16.2.0.tar.bz2
下载好之后,使用
tar -xvjf Twisted-16.2.0.tar.bz2
解压后,进入目录,使用sudo python setup.py install安装
启动twisted
#linux twistd -r epoll web --class=pyapns.server.APNSServer --port=7077 #mac os twistd -r kqueue web --class=pyapns.server.APNSServer --port=7077
我在运行这个的时候出了些问题,在mac上运行时发现少了一个叫libffi的库,要安装上这个才能运行。安装之后一,又少service-identity,再后来说openssl的库找不到.使用下边方法
sudo ln -s /Users/username/anaconda/lib/libssl.1.0.0.dylib /usr/lib/libssl.1.0.0.dylib
sudo ln -s /Users/username/anaconda/lib/libcrypto.1.0.0.dylib /usr/lib/libcrypto.1.0.0.dylib
在ubuntu linux上发现用pip安装的twistd没有web的这个命令,后来使用
sudo apt-get install python-twisted python-libxml2 python-simplejson
使用上边的命令安装好了twistd之后运行web命令又说少了service-identity,使用pip install service-identity进行安装时又说pyopenssl的版本不对。
再使用sudo pip install openssl进行openssl安装,接着运行twistd,发现已经有一个进程在运行了。这时找到twistd进程,使用。
kill pid
终止进程后,再运行
#linux twistd -r epoll web --class=pyapns.server.APNSServer --port=7077 #mac os twistd -r kqueue web --class=pyapns.server.APNSServer --port=7077
没有报错,这时就可以新建下边的push.py文件了,如果运气好,你的手机应该会收到推送消息。但是也有可能你在生成pem文件时使用了密码。而pyapns默认是不使用密码的。这个时候用下边的方法重新生成一个没有安装密码的ck.pem文件。
openssl rsa -in PushChatKey.pem -out PushChatKey-noenc.pem。
cat PushChatCert.pem PushChatKey-noenc.pem > ck.pem
新建push.py文件输入下面内容
#!/usr/bin/python # -*- coding: utf-8 -* # Filename: push.py from pyapns import configure, provision, notify tokens = ["token1" , "token2"] notifications = [ {'aps' :{'alert': 'Hello token 1', 'badge': 0, 'sound': 'flynn.caf'}}, ] configure({'HOST': 'http://localhost:7077/'}) provision('myapp', open('developent.pem').read(), 'sandbox') notify('myapp', tokens, notifications)
pyapns推送消息 需要一个pem格式的证书文件,跟 Parse 里要求一个.p12文件不同啊。我看看怎么搞到这文件。从苹果下载的证书是.cer格式的,在苹果的KeyChain程序中,选择导出,可是,只能选择导出成.cer和.p12文件,.pem的选项被禁用了,好桑心。通过搜索export pem from keychain找到 Creating .pem file for APNS? ,简单说,就是在KeyChain里导出.p12格式的,再通过下面的命令转换成.pem的。搞定。
openssl pkcs12 -in Development.p12 -out developent.pem -nodes -clcerts
python push.py
推送成功
完成
pyapns源码:
https://github.com/samuraisam/pyapns
具体的.pem文件生成:
处理证书
打开终端.
cd到桌面,我们那三个文件所在的位置
三个文件:
一个是CSR请求文件,一个是aps_development .cer的SSL证书文件,还有一个刚才生成的Push.p12秘钥文件
1、把.cer的SSL证书转换为.pem文件,执行命令:
openssl x509 -in aps_development.cer -inform der -out PushChatCert.pem
在桌面上会生成一个PushChatCert.pem文件
localhost:Desktop oukoumine$ openssl x509 -in ps_development.cer -inform der -out PushChatCert.pem
localhost:Desktop oukoumine$
2、把私钥Push.p12文件转化为.pem文件:
openssl pkcs12 -nocerts -out PushChatKey.pem -in Push.p12
这里需要我们输入密码,这个密码也就是我们导出p12文件时的密码,也就是我们上面设置的abcabc。然后,需要我们对生成的pem文件设置一个密语,这里我们推荐还是用上面这个abcabc,防止混乱(当然你也可以设置成别的更有意义的密语),这里的密语是要告诉我们服务器的。这样,桌面上又会生成一个PushChatKey.pem文件

3、对生成的这两个pem文件再生成一个pem文件,来把证书和私钥整合到一个文件里:
cat PushChatCert.pem PushChatKey.pem > ck.pem
生成ck.pem文件

这样,我们的文件就制作完了
项目测试
建立我们的推送的项目(注意BundleIdentifier必须和我们推送应用的App id一致)
在AppDelegate里didFinishLaunchingWithOptions函数里写
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
……
//推送的形式:标记,声音,提示
[[UIApplication sharedApplication] registerForRemoteNotificationTypes: UIRemoteNotificationTypeBadge |UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert];
//上边的方法在ios8以上的版本不能用了。ios8以后要使用新的方法

return YES;
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)pToken {
NSLog(@"regisger success:%@",pToken);
//注册成功,将deviceToken保存到应用服务器数据库中
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
// 处理推送消息
NSLog(@"userinfo:%@",userInfo);
NSLog(@"收到推送消息:%@",[[userInfo objectForKey:@"aps"] objectForKey:@"alert"]);
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(@"Registfail%@",error);
}
我们运行程序的时候会有提示,说我们的程序要发送推送通知。
C++推送服务器端:
转自:http://www.cocoachina.com/bbs/read.php?tid=74676
SSLCOMM_H文件
#ifndef SSLCOMM_H
#define SSLCOMM_H
#ifdef linux
#include <assert.h>
#include "openssl/pem.h"
#include "openssl/rsa.h"
#include "openssl/crypto.h"
#include "openssl/x509.h"
#include "openssl/ssl.h"
#include "openssl/err.h"
#include "openssl/rand.h"
#include "errno.h"
#include "sys/socket.h"
#include "netinet/in.h"
#include "unistd.h"
#include <arpa/inet.h>
#include <netdb.h>
#include "Utility.h"
#define APNS_DEV
#if defined(APNS_DEV)
#define CA_CERT_PATH "./pem"
#define RSA_CLIENT_CERT "./pem/a.pem"
#define RSA_CLIENT_KEY "./pem/a.pem"
/* Development Connection Infos */
#define APPLE_HOST "gateway.sandbox.push.apple.com"
#define APPLE_PORT 2195
#define APPLE_FEEDBACK_HOST "feedback.sandbox.push.apple.com"
#define APPLE_FEEDBACK_PORT 2196
#else
#define CA_CERT_PATH "./pem"
#define RSA_CLIENT_CERT "./pem/b.pem"
#define RSA_CLIENT_KEY "./pem/b.pem"
#define APPLE_HOST "gateway.push.apple.com"
#define APPLE_PORT 2195
#define APPLE_FEEDBACK_HOST "feedback.push.apple.com"
#define APPLE_FEEDBACK_PORT 2196
#endif
class CSSLComm
{
public:
CSSLComm();
~CSSLComm();
bool connected();
bool ssl_connect(const char *host, int port, const char *certfile, const char *keyfile, const char* capath);
void PushNotification(const char *pToken,const char *pMsg);
void GenPushData(const char *pToken);
int GenPayloadData(int badgeNum,const char *pMsg = NULL);
private:
void Reset();
private:
SSL_CTX *m_pctx;
SSL *m_pssl;
const SSL_METHOD *m_pmeth;
X509 *m_pserver_cert;
EVP_PKEY *m_pkey;
/* Socket Communications */
struct sockaddr_in m_server_addr;
struct hostent *m_phost_info;
int m_sockfd;
uint16 m_tokenLen;
struct PUSHDATA
{
char szToken[1+2+32];
char szPayload[2+256];
}m_data;
CSyncCritical m_lock;
};
#endif
#endif // SSLCOMM_H
SSLComm.cpp
#ifdef linux
#include "SSLComm.h"
CSSLComm::CSSLComm()
{
//ctor
m_sockfd = -1;
m_pctx = NULL;
m_pssl = NULL;
m_pmeth = NULL;
m_pserver_cert = NULL;
m_pkey = NULL;
m_tokenLen = htons(32);
memset((void*)&m_data,0,sizeof(m_data));
}
CSSLComm::~CSSLComm()
{
//dtor
Reset();
}
void CSSLComm::Reset()
{
if(m_pssl)
{
SSL_shutdown(m_pssl);
SSL_free(m_pssl);
m_pssl = NULL;
}
if(m_pctx)
{
SSL_CTX_free(m_pctx);
m_pctx = NULL;
}
if(m_sockfd > 2)
{
close(m_sockfd);
m_sockfd = -1;
}
}
bool CSSLComm::connected()
{
if(m_sockfd < 2) return false;
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
fd_set fdwrite;
fd_set fdexcept;
FD_ZERO(&fdwrite);
FD_ZERO(&fdexcept);
FD_SET(m_sockfd,&fdwrite);
FD_SET(m_sockfd,&fdexcept);
int ret = select(m_sockfd+1,NULL,&fdwrite,&fdexcept,&timeout);
if(ret == -1)
return false;
if(ret > 0)
{
if(FD_ISSET(m_sockfd,&fdexcept))
return false;
else if(FD_ISSET(m_sockfd,&fdwrite))
{
int err = 0;
socklen_t len = sizeof(err);
int result = getsockopt(m_sockfd,SOL_SOCKET,SO_ERROR,(char*)&err,&len);
if(result < 0 || err != 0)
return false;
return true;
}
}
return false;
}
bool CSSLComm::ssl_connect(const char *host, int port, const char *certfile, const char *keyfile, const char* capath)
{
Reset();
int err;
/* Load encryption & hashing algorithms for the SSL program */
SSL_library_init();
/* Load the error strings for SSL & CRYPTO APIs */
SSL_load_error_strings();
/* Create an SSL_METHOD structure (choose an SSL/TLS protocol version) */
m_pmeth = SSLv3_method();
/* Create an SSL_CTX structure */
m_pctx = SSL_CTX_new(m_pmeth);
if(!m_pctx)
{
printf("Could not get SSL Context\n");
return false;
}
/* Load the CA from the Path */
if(SSL_CTX_load_verify_locations(m_pctx, NULL, capath) <= 0)
{
/* Handle failed load here */
printf("Failed to set CA location...\n");
ERR_print_errors_fp(stderr);
return false;
}
/* Load the client certificate into the SSL_CTX structure */
if (SSL_CTX_use_certificate_file(m_pctx, certfile, SSL_FILETYPE_PEM) <= 0)
{
printf("Cannot use Certificate File\n");
ERR_print_errors_fp(stderr);
return false;
}
/* Load the private-key corresponding to the client certificate */
if (SSL_CTX_use_PrivateKey_file(m_pctx, keyfile, SSL_FILETYPE_PEM) <= 0)
{
printf("Cannot use Private Key\n");
ERR_print_errors_fp(stderr);
return false;
}
/* Check if the client certificate and private-key matches */
if (!SSL_CTX_check_private_key(m_pctx))
{
printf("Private key does not match the certificate public key\n");
return false;
}
/* Set up a TCP socket */
m_sockfd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
if(m_sockfd == -1)
{
printf("Could not get Socket\n");
return false;
}
memset (&m_server_addr, '\0', sizeof(m_server_addr));
m_server_addr.sin_family = AF_INET;
m_server_addr.sin_port = htons(port); /* Server Port number */
m_phost_info = gethostbyname(host);
if(m_phost_info)
{
/* Take the first IP */
struct in_addr *address = (struct in_addr*)m_phost_info->h_addr_list[0];
m_server_addr.sin_addr.s_addr = inet_addr(inet_ntoa(*address)); /* Server IP */
}
else
{
printf("Could not resolve hostname %s\n", host);
return false;
}
/* Establish a TCP/IP connection to the SSL client */
err = connect(m_sockfd, (struct sockaddr*) &m_server_addr, sizeof(m_server_addr));
if(err == -1)
{
printf("Could not connect\n");
return false;
}
/* An SSL structure is created */
m_pssl = SSL_new(m_pctx);
if(!m_pssl)
{
printf("Could not get SSL Socket\n");
return false;
}
/* Assign the socket into the SSL structure (SSL and socket without BIO) */
SSL_set_fd(m_pssl, m_sockfd);
/* Perform SSL Handshake on the SSL client */
err = SSL_connect(m_pssl);
if(err == -1)
{
printf("Could not connect to SSL Server\n");
return false;
}
return true;
}
void CSSLComm::PushNotification(const char *pToken,const char *pMsg)
{
CMyLock lock(&m_lock);
if(!connected())
{
ssl_connect(APPLE_HOST, APPLE_PORT, RSA_CLIENT_CERT, RSA_CLIENT_KEY, CA_CERT_PATH);
}
int paylen = GenPayloadData(1,pMsg);
GenPushData(pToken);
int ret = SSL_write(m_pssl, (void*)&m_data, 35 + paylen);
//printf("ret = %d \n",ret);
}
void CSSLComm::GenPushData(const char *pToken)
{
char *ptr = m_data.szToken;
*ptr++ = 0;
memcpy(ptr,&m_tokenLen,2);
ptr += 2;
memcpy(ptr,pToken,32);
}
int CSSLComm::GenPayloadData(int badgeNum,const char *pMsg)
{
char buf[256] = {0};
char badgeBuf[3] = {0};
strcpy(&m_data.szPayload[2], "{\"aps\":{");
if(pMsg != NULL)
{
strcat(&m_data.szPayload[2], "\"alert\":");
snprintf(buf, sizeof(buf)-1,"\"%s\",", pMsg);
strcat(&m_data.szPayload[2],buf);
}
if(badgeNum > 99 || badgeNum < 0) badgeNum = 1;
snprintf(badgeBuf, sizeof(badgeBuf)-1,"%d", badgeNum);
strcat(&m_data.szPayload[2], "\"badge\":");
strcat(&m_data.szPayload[2], badgeBuf);
strcat(&m_data.szPayload[2], ",\"sound\":\"msg.wav\"}");
/*
int i = 0;
while(payload->dictKey<i> != NULL && i < 5)
{
sprintf(tmpBuff, "\"%s\":\"%s\"", payload->dictKey<i>, payload->dictValue<i>);
strcat(messageBuff, tmpBuff);
if(i < 4 && payload->dictKey[i + 1] != NULL)
{
strcat(messageBuff, ",");
}
i++;
}
*/
snprintf(buf, sizeof(buf)-1,",\"%s\":\"%d\"", "forum_id",88);
strcat(&m_data.szPayload[2],buf);
snprintf(buf, sizeof(buf)-1,",\"%s\":\"%d\"", "topic_id",999);
strcat(&m_data.szPayload[2],buf);
strcat(&m_data.szPayload[2],"}");
int len = strlen(&m_data.szPayload[2]);
assert(len <= 256);
uint16_t payload_len = htons(len);
memcpy(m_data.szPayload,&payload_len,sizeof(payload_len));
return len + 2;
}
#endif