IOS 的 PUSH 封装

服务器端的主要工作是:从客户端获取到deviceToken,随同需要发送的内容,按IOS规定格式打包发送。

1.先获得证书(从客户端开发人员要来的)Certificates.p12 通过输入命令生成 PEM 格式

openssl pkcs12 -clcerts -nokeys -out cert.pem -in aps_development.p12
//会要求提供密码,密码为空,直接回车即可    
openssl pkcs12 -nocerts -out key.pem -in aps_development.p12 
//会要求设置密码和确认设置密码。这里我们用是的是123456    
openssl rsa -in key.pem -out key.unencrypted.pem     
//会要求输入之前设置的密码
cat cert.pem key.unencrypted.pem > iostest_push_dev.pem

2. deviceToken 是一个字符串。形如:<304eb5c5 5b8a36ba a072a5ff b6e9ada9 9d5a1b8c 89f9f1c1 ac8cc3dd fe9a86fd>

注意:ios要求token的格式是binary,所以发送前需要转换下,且要跳过 空格 和 "<", ">"

3、代码实现:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <openssl/ssl.h>
#include <openssl/rand.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/x509.h>
#include <arpa/inet.h>
#include <string>
using namespace std;
// 证书文件
#define CERTFILE "cert/aps_developer_identity.pem"
SSL *ssl;
SSL_CTX *ctx;
void error(const char *msg)
{
 printf("[ERROR]:%s\n", msg);
 exit(1);
}
 
SSL_CTX *setup_client_ctx()
{
 ctx = SSL_CTX_new(SSLv23_method());
 if (SSL_CTX_use_certificate_chain_file(ctx, CERTFILE) != 1) {
  error("Error loading certificate from file\n");
 }
 if (SSL_CTX_use_PrivateKey_file(ctx, CERTFILE, SSL_FILETYPE_PEM) != 1) {
  error("Error loading private key from file\n");
 }
 return ctx;
}
 
// 将deviceToken字符串转成对应的binary bytes
void token2bytes(const char *token, char *bytes)
{
 int val;
 while (*token) {
  sscanf(token, "%2x", &val);
  *(bytes++) = (char)val;
  token += 2;
  while (*token == ' ') { // skip space
   ++token;
  }
 }
}
 
// 打包消息
unsigned long packMessage(char *message, const unsigned char command, const char *tokenBytes, const char *payload)
{
 unsigned long payloadLength = strlen(payload);
 unsigned short networkTokenLength = htons(32);
 unsigned short networkPayloadLength = htons(payloadLength);
 memcpy(message, &command, sizeof(unsigned char));
 message += sizeof(unsigned char);
 memcpy(message, &networkTokenLength, sizeof(unsigned short));
 message += sizeof(unsigned short);
 memcpy(message, tokenBytes, 32);
 message += 32;
 memcpy(message, &networkPayloadLength, sizeof(unsigned short));
 message += sizeof(unsigned short);
 memcpy(message, payload, payloadLength);
 return payloadLength + 37;
}
 
int push(string _token, string _payload)
{
 const char *token = _token.c_str();
 string payloadstr =  "{\"aps\":{\"alert\":\"";
 payloadstr += string(_payload);
 payloadstr +=  "\"}}";
 cout<<"pushStr: "<< payloadstr;
 const char *payload = payloadstr.c_str();
 char host[] = "gateway.sandbox.push.apple.com:2195";
 BIO *conn;
 // init
 SSL_library_init();
 ctx = setup_client_ctx();
 conn = BIO_new_connect(host);
 if (!conn) {
  error("Error creating connection BIO\n");
  return -1;
 }
 if (BIO_do_connect(conn) <= 0) {
  error("Error connection to remote machine");
  return -1;
 }
 if (!(ssl = SSL_new(ctx))) {
  error("Error creating an SSL contexxt");
  return -1;
 }
 SSL_set_bio(ssl, conn, conn);
 if (SSL_connect(ssl) <= 0) {
  error("Error connecting SSL object");
  return -1;
 }
 printf("SSL Connection opened\n");
 char tokenBytes[32];
 char message[293];
 unsigned long msgLength;
 token2bytes(token, tokenBytes);
 msgLength = packMessage(message, 0, tokenBytes, payload);
 int reValue = SSL_write(ssl, message, (int)msgLength);
 SSL_shutdown(ssl);
 SSL_free(ssl);
 SSL_CTX_free(ctx);
 return reValue;
}

参考:http://blog.csdn.net/bingwen0210/article/details/6622238

原文地址:https://www.cnblogs.com/tianyajuanke/p/2523888.html