iOS 进阶开发— 原生APNS配置以及server实现(c++版本)

关于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"];
    }

}


简单罗列了一下,但具体思路应该大家都能看懂了,如有不明白的,请留言


你可能感兴趣的:(iOS应用开发)