[转]宝文!Apple Push Notification Service (APNS)原理与实现方案

原理

简单的说,app要单独实现消息动态更新,一种是轮询,这对用户来说会带来额外的流量。另一种方案是push,app client和server直接保持一个长连接,有新的消息时server push给app client。

这两种通过app自身实现的“push”都会面临以下问题:

  1. 进程被关闭后无法在发送请求
  2. 大量app开启网络连接对用户的流量和电池都会带来大量消耗
  3. 通讯安全问题需要app自己提供解决方案

APNS为app开发商提供了一个统一的消息通知平台。apple和每个iOS设备之间保持一个长连接。开发商将消息发送给APNS,APNS将该消息发送到指定的iOS设备,iOS设备展示消息、启动相应的app。


从以上过程可知,为通过APNS实现消息push,一个消息需要标识发送到“哪台iOS设备”的“哪个app”。这两个分别由设备id(deviceToken)和SSL的证书文件(开启消息push的app需要配置一个SSL证书)标识。消息结构体如下:

实现方案

详细过程请参考http://mobiforge.com/developing/story/programming-apple-push-notification-services,一步步来即可。这一过程会生成文件:

  1. CertificateSigningRequest.certSigningRequest 用于生成SSL证书的中间文件,用后可删除
  2. aps_developer_identity.cer SSL证书文件,这一证书会关联app id,利用该证书可将消息发送到对应的app。
  3. [xxx].mobileprovision和上述SSL证书文件绑定的app provision文件,请安装到测试设备。

双击aps_developer_identity.cer将证书文件导入到Keychain Access。

java/php/c++需要的SSL证书和密钥生成如下:

  1. 将keychain access中的aps_developer_identity.cer导出为[xxx].p12
  2. 终端下执行:
    1
    openssl pkcs12 -in [xxx].p12 -out [xxx].pem -nodes

将最终生成的pem文件提供给后台server

后台代码示例

app client请参考上述链接中的示例。

push server:

object c版本 http://stefan.hafeneger.name/download/PushMeBabySource.zip

java版本 http://code.google.com/p/javapns/

php版本 http://code.google.com/p/apns-php/

现在后台技术主要还是c/c++吧,网上一直没找到合适的,自己实现demo,代码如下:

/*** @file main.cpp* @author Maxwin* @description TestPushServer*/#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 <netinet/in.h>// 证书文件 #define CERTFILE "max.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(const char *token, const char *payload) {char tokenBytes[32];char message[293];unsigned long msgLength;token2bytes(token, tokenBytes);msgLength = packMessage(message, 0, tokenBytes, payload);return SSL_write(ssl, message, (int)msgLength); }int main (int argc, const char * argv[]) {char token[] = "2b2474e5 ac7670f3 08fabf3a 9c1d1295 ed50e9aa f11b941a d6e3d213 4f535408";char payload[] = "{\"aps\":{\"alert\":\"Hello world!!!\",\"badge\":1}}";char payload2[] = "{\"aps\":{\"alert\":\"Hello kitty!!!\",\"badge\":12}}";char host[] = "gateway.sandbox.push.apple.com:2195";BIO *conn;// initSSL_library_init();ctx = setup_client_ctx();conn = BIO_new_connect(host);if (!conn) {error("Error creating connection BIO\n");}if (BIO_do_connect(conn) <= 0) {error("Error connection to remote machine");}if (!(ssl = SSL_new(ctx))) {error("Error creating an SSL contexxt");}SSL_set_bio(ssl, conn, conn);if (SSL_connect(ssl) <= 0) {error("Error connecting SSL object");}printf("SSL Connection opened\n");// push messageint ret = push(token, payload);printf("push ret[%d]\n", ret);// push [Hello kitty] after 5ssleep(5);ret = push(token, payload2);printf("push2 ret[%d]\n", ret);printf("Close SSL Connection\n");SSL_shutdown(ssl);SSL_free(ssl);SSL_CTX_free(ctx);return 0; }

编译运行:

g++ main.cpp -o pushServer -lssl -lcrypto

  

 

转载于:https://www.cnblogs.com/lihaozy/archive/2013/02/25/2931860.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/433883.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

if 组件是否存在_UE4 UMG简介+Slate组件问题排查

Slate 组件问题排查总结简介首先是一个工作中遇到的BUG&#xff1a; 用slua添加子节点到父节点上的时候&#xff0c;第二次打开无法显示对应的子节点Widget。对应Lua代码如下local comboBox ui_manager.ShowUI(ui_manager.UI_Config.ui_coupon_combobox,2,price,buyUIInfo.sho…

创业型公司的产品经理应该知道的事情

可能因为最近有一本书叫做<<人人都是产品经理>>&#xff0c;所以产品经理这个词变得很fashion了&#xff0c;产品经理在一些成熟型的公司&#xff0c;确实是一个很重要的职位。因为成熟型的公司产品的开发的流程都已经很完善&#xff0c;所以产品经理是其中一个不可…

设置框开始隐藏状态html5,小猿圈分享HTML5中form如何关闭自动完成功能的方法

WEB前端现在是时下较火的编程语言之一&#xff0c;但是对于怎么学习或者学习哪些内容很多朋友都是不了解的&#xff0c;针对以上内容小猿圈web前端讲师总结了form如何关闭自动完成功能的方法&#xff1f;希望对你的前端学习有一定的帮助。什么是HTML5的form自动完成功能&#x…

浏览器登录_经常用浏览器自动登录忘记了密码?教你一键查看网页星号密码

不知道大家有没有出现这种情况&#xff0c;因为一直用的网页自动填写密码来登录&#xff0c;所以有时候甚至把密码给忘了相信有的小伙伴有可能就会出现这种情况哈&#xff0c;今天小林君来教你个超简单的方法&#xff0c;不用安装任何软件&#xff0c;就可以一键查看网页上隐藏…

控件属性动作

控件应该定义属性而不是公共字段&#xff0c;因为可视化设计器在属性浏览器中显示属性&#xff0c;而不显示字段。属性就像智能字段。属性通常具有带访问函数的专用数据成员&#xff0c;在语法上属性被作为类的字段进行访问。&#xff08;虽然属性可以具有不同的访问级别&#…

python连接数据库并编写调用函数_Python使用pyodbc访问数据库操作方法详解

本文实例讲述了Python使用pyodbc访问数据库操作方法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;1、连接数据库1)直接连接数据库和创建一个游标(cursor)cnxn pyodbc.connect(DRIVER{SQL Server};SERVERlocalhost;DATABASEtestdb;UIDme;PWDpass)cursor cnxn.cursor(…

Mysql 5.5的编译安装 在ubuntu 10平台上面

(一)安装mysql5.5的要求 编译安装mysql5.5与5.1还是有一点不同&#xff0c;因为mysql现在用cmake来作编译工程工具。 这是与mysql5.1最大不同的地方&#xff0c;因此在安装mysql5.5时所要求的工具包也不同。发现用cmake编译mysql比以前的速度还是快了不少。 &#xff08;1&a…

html图片轮播怎么做的,CSS3制作轮播图的一种方法

轮播图&#xff0c;网页上经常能看得见&#xff0c;画面比较精美&#xff0c;下面是纯CSS3的轮播图的一种下面是style部分&#xff1a;这几行都能明白吧*{margin:0;padding:0;}a{text-decoration:none}li{list-style:none;}设计宽度不要超过轮播图片的总宽度再加不到第一张1张图…

怎么让textarea占满整个td高度没用_家里没发现虫子,怎么才能确定是被什么害虫咬了?...

在家里被虫子咬&#xff0c;还发痒&#xff0c;主要有三种可能性。蚊子、跳蚤、臭虫都有可能&#xff0c;那么如何才能确定是被哪种害虫叮咬&#xff1f;接下来带大家了解三种害虫叮咬的区别&#xff01;首先是蚊子&#xff0c;早上起来发现身上有包&#xff0c;先看有几处&…

PLSQL 笔记

oracle的左连接或右连接 以下是解释&#xff0c;自己研究下&#xff1a; ------------------------------------------------------------------- 数据表的连接有: 1、内连接(自然连接): 只有两个表相匹配的行才能在结果集中出现 2、外连接: 包括 &#xff08;1&#xff09;左外…

上位机与1200组态步骤_组态王与 I/O 设备

组态王软件是一种通用的工业监控软件&#xff0c;它将过程控制设计、现场操作以及工厂资源管理融于一体&#xff0c;将一个企业内部的各种生产系统和应用以及信息交流汇集在一起&#xff0c;实现最优化管理。它基于Microsoft Windows XP/Win7/Win8/Win10/WinServer 系列操作系统…

MySQL安装错误: unknown option '--skip-federated'

mysql启动时出现以下错误&#xff1a; [ERROR] /usr/local/mysql/libexec/mysqld: unknown option --skip-federated [ERROR] Aborting [Note] /usr/local/mysql/libexec/mysqld: Shutdown complete 只要将/etc/my.cnf文件中的skip-federated注释掉即可 通过查看/var/log/mysql…

华为鸿蒙发布2.0,华为做到了!鸿蒙2.0正式发布,苹果安卓有危机?

孩子的梦想总是天真烂漫&#xff0c;无论年龄大小&#xff0c;每个人都有属于自己的梦想&#xff0c;儿童节刚过华为天真的梦就照进了现实。6月2日晚间&#xff0c;鸿蒙2.0版本发布会如期而至&#xff0c;余承东正式向全世界宣布这款挑战安卓和 iOS的商用移动操作系统&#xff…

【IE大叔的嘴歪眼斜】之—— 由hasLayout引发的临床CSS Bug表

IE大叔这嘴歪眼斜的毛病不是一天两天了&#xff0c;集体拉出来测试时候&#xff0c;明明大家都在微笑&#xff0c;就丫一副呲牙咧嘴的...... 哎&#xff0c;没办法&#xff0c;谁让咱国内市面上都是这种呲牙咧嘴的浏览器呢.....(关注IE678死亡速度) 查阅&#xff0c;翻读&#…

greenplum 查询出来的数字加减日期_Python实践代码总结第5集(日期相关处理)

英文的月份转数字及数字转英文import calendar# 数字转月份的简写calendar.month_abbr[12]--> Dec# 简写月份转数字list(calendar.month_abbr).index(Dec)--> 12# 数字转月份的全写calendar.month_name[12]--> December# 月份转数字list(calendar.month_name).index(D…

静态代码和动态代码的区别_无代码和低代码有哪些区别

代码是大多数软件程序和应用程序的骨干。代码是大多数软件程序和应用程序的骨干。每行代码充当一条指令&#xff1a;采用一种逐步性的逻辑机制&#xff0c;以便计算机、服务器和其他机器执行操作。想创建那些指令&#xff0c;就要知道如何编写代码&#xff0c;这项宝贵的技能有…

备注html网页代码,备注.html · dengzhao/prd_zhangyao - Gitee.com

&#xfeff;备注$axure.utils.getTransparentGifPath function() { return resources/images/transparent.gif; };$axure.utils.getOtherPath function() { return resources/Other.html; };$axure.utils.getReloadPath function() { return resources/reload.html; };备注…

mysqld与mysqld_safe的区别

直接运行mysqld程序来启动MySQL服务的方法很少见&#xff0c;mysqld_safe脚本会在启动MySQL服务器后继续监控其运行情况&#xff0c;并在其死机时重新启动它。用mysqld_safe脚本来启动MySQL服务器的做法在BSD风格的unix系统上很常见&#xff0c;非BSD风格的UNIX系统中的mysql.s…

python词频统计代码_机器学习必备宝典-《统计学习方法》的python代码实现及课件...

《统计学习方法》可以说是机器学习的入门宝典&#xff0c;许多机器学习培训班、互联网企业的面试、笔试题目&#xff0c;很多都参考这本书。本站根据网上资料用python复现了课程内容&#xff0c;并提供本书的代码实现、课件下载。《统计学习方法》简介《统计学习方法》全面系统…

Oracle中用rownum替代Top函数的方法

今天写一个方法&#xff0c;主要功能是从数据库中根据条件查出第一条信息。以前用sql server的时候&#xff0c;我记得TOP方法还是非常简单实用的。 方法是&#xff1a;select top n [列名] from [表名] where [查询条件] 这个方法想必像我这样的新人也会非常熟悉&#xff0c;所…