关于iOS APNS的server provider 一直没有看到关于c++版本的,不过现在的各种第三方APNS已经很成熟了,比如百度的云推送SDK等等,这里简单总结一下如何实现iOS原生的APNS server provider.
第一步,生成证书,如何生成.p12证书这里就不细说了,如果不清楚的请查阅其他文档,或者评论里留言,如果问的多的话我再加上
openssl pkcs12 -clcerts -nokeys -out cert.pem -in Certificate.p12
provide new password if asked.
openssl pkcs12 -nocerts -out key.pem -in Certificate.p12
provide new password if asked.
cat cert.pem key.unencrypted.pem > ck.pem
测试版本要生成developer 证书,发布的要对应的生成发布版本的。
生成.pem证书之后,把pem证书放到你的server provider工程中去。
第二步:server provider实现(c++版本)
要实现server provider, 需要先编译安装openssl, 因为Apple 的APNS是基于openssl实现的。
先来看头文件实现
/*
* Auth The Croods
*/
#pragma once
#include
#include
#include
#include
#include
#include
#include
#include
#include
// certificate
#define CERTFILE "./apns_dev.pem"
#define SSL_CTX_LOAD_VERIFY_LOCATIONS_FAILED -1
#define BIO_DO_CONNECT_FAILED -2
#define SSL_GET_VERIFY_RESULT_FAILED -3
class APNS_Croods
{
private:
SSL_CTX *m_pctx;
SSL *m_pssl;
const SSL_METHOD *m_pmeth;
X509 *m_pserver_cert;
EVP_PKEY *m_pkey;
BIO *bio;
public:
APNS_Croods(void);
~APNS_Croods(void);
int APNS_protal();
void Reset();
int pushmessage(const char *token, const char *payload);
void token2bytes(const char *token, char *bytes);
};
接下来看类实现:
#include "APNS_Croods.h"
APNS_Croods::APNS_Croods(void)
{
m_pctx = NULL;
m_pssl = NULL;
m_pmeth = NULL;
m_pserver_cert = NULL;
m_pkey = NULL;
bio = NULL;
}
APNS_Croods::APNS_Croods(void)
{
Reset();
}
int APNS_Croods::pushmessage(const char *token, const char *payload){
char tokenBytes[32];
char message[293];
int msgLength;
token2bytes(token, tokenBytes);
unsigned char command = 0;
size_t payloadLength = strlen(payload);
char *pointer = message;
unsigned short networkTokenLength = htons((u_short)32);
unsigned short networkPayloadLength = htons((unsigned short)payloadLength);
memcpy(pointer, &command, sizeof(unsigned char));
pointer +=sizeof(unsigned char);
memcpy(pointer, &networkTokenLength, sizeof(unsigned short));
pointer += sizeof(unsigned short);
memcpy(pointer, tokenBytes, 32);
pointer += 32;
memcpy(pointer, &networkPayloadLength, sizeof(unsigned short));
pointer += sizeof(unsigned short);
memcpy(pointer, payload, payloadLength);
pointer += payloadLength;
msgLength = (int)(pointer - message);
int ret = SSL_write(m_pssl, message, msgLength);
return ret;
}
int APNS_Croods::APNS_protal()
{
//
char token[] = "8da412ec d60b4a8d ea08a8f5 31f0e832 ba87c072 8920cf7d 2e436f40 c367205b";
char payload[] = "{\"aps\":{\"alert\":\"Hello world!!! message from c++\",\"badge\":1}}";
char host[] = "gateway.sandbox.push.apple.com:2195";
/*
* Lets get nice error messages
*/
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
/*
* Setup all the global SSL stuff
*/
SSL_library_init();
m_pctx = SSL_CTX_new(SSLv23_client_method());
if (SSL_CTX_use_certificate_chain_file(m_pctx, CERTFILE) != 1) {
printf("Error loading certificate from file\n");
return -1;
}
if (SSL_CTX_use_PrivateKey_file(m_pctx, CERTFILE, SSL_FILETYPE_PEM) != 1) {
printf("Error loading private key from file\n");
return -2;
}
bio = BIO_new_connect(host);
if (!bio) {
printf("Error creating connection BIO\n");
return -3;
}
if (BIO_do_connect(bio) <= 0) {
printf("Error connection to remote machine\n");
return -4;
}
if (!(m_pssl = SSL_new(m_pctx))) {
printf("Error creating an SSL contexxt\n");
return -5;
}
SSL_set_bio(m_pssl, bio, bio);
int slRc = SSL_connect(m_pssl);
if (slRc <= 0) {
printf("Error connecting SSL object>>%d\n", slRc);
return -6;
}
int ret = pushmessage(token,payload);
printf("push ret[%d]\n", ret);
Reset();
return 0;
}
// change deviceToken string to binary bytes
void APNS_Croods::token2bytes(const char *token, char *bytes){
int val;
while (*token) {
sscanf_s(token, "%2x", &val);
*(bytes++) = (char)val;
token += 2;
while (*token == ' ') {
// skip space
++token;
}
}
}
void APNS_Croods::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;
}
}
char host[] = "gateway.sandbox.push.apple.com:2195";
这是apple APNS的developer 接口,如果是发布的话,要改成相应的发布接口,具体官网查询一下吧
下边接着来看,iOS客户端应用如何实现程序启动时读取通知内容:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSDictionary * remoteNotification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
NSLog(@">>>>remoteNotification>>%@>>>>>launchOptions>>>%@", remoteNotification,launchOptions);
if (remoteNotification!=nil) {
NSLog(@">>>>remoteNotification.userInfo>>%@", [[remoteNotification objectForKey:@"aps"]objectForKey:@"alert"]);
NSString *alertBody = [[remoteNotification objectForKey:@"aps"]objectForKey:@"alert"];
}
}
简单罗列了一下,但具体思路应该大家都能看懂了,如有不明白的,请留言