当前位置: 首页 > 编程日记 > 正文

[译] iOS 开发之新版 APNs 搭建必备知识

本文的大部分内容是对苹果关于APNs官方文档的翻译以及整理。

一、设备token和消息的生命周期

关于设备token以及推送消息的生命周期需要注意下面几点:

  • Token会在iOS系统更新或者设备数据、设置被擦除的时候改变。
  • 当设备离线的时候,APNS会将消息数据存储一段时间,等设备上线后重发。如果设备在离线期间,向APNS发送了多条推送消息,APNS将会丢弃掉前面的一些消息,只保留后面的消息,要是设备长时间离线,则会将所有的消息丢弃掉。
  • 可以通过设置http/2头中的apns-collapse-id键值对来合并消息,比如:apns-collapse-id : 2,那么value为2的消息将被APNS合并成一条消息推送给设备。

二、Provider(后台)与APNs的交互

Provider(即,APP的后台)与APNS有两种安全的交互方式,都必须采用TLS以保证可靠性,更详细的内容继续往下看。

TLS的简单理解是,为了保证数据传输安全,在HTTP层与TCP层之间插入的一个安全校验层,它所做的事情简单来说就是:“通过CA申请的证书验证client与server是可靠的之后,通过相应的公私钥加密一个协商的公钥,之后的真实数据传输就使用这个公钥进行加密,以保证数据的安全可靠性”,关于TLS的更详细的介绍,可以参考这篇文章

基于Token的方式(Token-Based Provider-to-APNs Trust)

1、流程概述

这种方式适合在基于HTTP/2协议的Provider使用,它与APNs之间的连接通过JWT(JSON web tokens)来验证。在这种方式下不需要使用证书+私钥的方式来建立可靠连接。Provider只需要提供一对公私钥(私钥给APNs保存,公钥Provider自己保存),并使用其中的私钥生成并加密JWT Token,每次向APNs请求推送的时候带上这个Token即可。

具体步骤如下:

  1. Provider通过TLS向APNs发起请求。
  2. APNs返回一个证书给Provider。
  3. Provier验证这个证书。通过后,发送push数据并带上JWT token。
  4. APNs验证token,并返回请求的结果。

Establishing and using token-based connection trust between a provider and APNs

建立TLS连接必须要有一个GeoTrust Global CA root certificate,在macOS中,这个证书已经安装在keychain中,如果是其他操作系统则可以在GeoTrust Root Certificates website下载。

2、Provider Authentication Tokens

关于JWT(JSON Web Token)的详细资料可以通过这里了解。同时也可以从这里找到一些现成可用的库。

下面对JWT进行详细的介绍,一个JWT实际上是一个JSON对象,它的头部必须包含:

  • 用以加密token的加密算法(alg) ,比如:ES256。
  • 10个字符长度的标识符(kid),(登入苹果开发者账号后,进入到Certificates, Identifiers & Profiles,然后点击APNs Auth Key,最后在右侧找到Apple Push Notification Authentication Key (Sandbox & Production)选项,点击创建后可以创建一个p8文件。)

同时他的claims payload部分必须包含:

  • issuer(iss) registered claim key,其值就是10个字符长的Team ID。
  • issued at (iat) registered claim key,其值是一个秒级的UTC时间戳。

比如:

{"alg": "ES256","kid": "ABC123DEFG"
}
{"iss": "DEF123GHIJ","iat": 1437179036}

创建完这个token后,必须使用自己的私钥对其进行加密,然后再采用基于P-256曲线和SHA-256哈希算法的椭圆曲线数字签名算法(ECDSA)进行签名,并将alg键的值设置为ES256。(注意:APNs只支持ES256签名的JWT,否则会返回InvalidProviderToken(403)错误)

为了保证安全,APNs要求定期更新token,时间间隔为1小时,如果APNs发现当前的时间戳与iat值中的时间戳相比,大于一个小时,那么APNs会拒绝推送消息,并返回ExpiredProviderToken (403)错误。

基于证书的方式(Certificate-based connection trust)

流程概述

这种方式是指Provider可以采用一个唯一的证书以及一个加密的私钥来与APNs交互,其中证书是由苹果产生的(通过苹果账号登录到developer account配置创建)。整个交互过程如下:

  1. Provider通过TLS向APNs请求连接。
  2. APNs向Provider返回一个APNs证书。
  3. Provider验证这个APNs证书,并将从苹果官网获取的证书返回给APNs。
  4. APNs验证通过后,这个链接就算是建立了。

Establishing certificate-based connection trust between a provider and APNs

APNs Provider Certificates

创建步骤可以参考Configure push notifications中的Generate a universal APNs client SSL certificate章节。

三、APNs连接

连接的管理

苹果的两个APNs server分别为:

  • Development server: api.development.push.apple.com:443
  • Production server: api.push.apple.com:443

要与APNs交互要求server必须支持1.2及上版本的TLS协议。通过上面的介绍我们已经知道,server跟APNs交互有两种方式:基于JWT的方式以及基于证书的方式。为了保证高质量的使用APNs应该注意如下几点:

  • 对于基于JWT的方式,应该定时更新token,token的有效期为1小时。
  • 对于基于JWT的方式,能每次请求都创建新的token,尽量在一小时内使用同一个token。
  • 不能频繁的建立、关闭连接,否则APNs会把这当做是黑客攻击,拒绝访问。应该尽量将连接保活,直到你认为这个连接接下来会长时间不使用为止。
  • 当需要发送大量的推送数据的时候,可以同时创建多个连接,以改善性能。
  • 当吊销证书或者token时,应该关闭所有相关的连接。

HTTP/2的请求与响应

详情可参见苹果官方文档HTTP/2 Request to APNs。这里介绍了接口的请求参数返回结果错误码以及示例代码。下面仅截取了其中的例子,以加深对APNs的使用的理解:

  • 基于证书的方式的request:

      HEADERS- END_STREAM+ END_HEADERS:method = POST:scheme = https:path = /3/device/00fc13adff785122b4ad28809a3420982341241421348097878e577c991de8f0host = api.development.push.apple.comapns-id = eabeae54-14a8-11e5-b60b-1697f925ec7b //可以不填,如果不填APNs会自己创建一个UUID并在response中返回apns-expiration = 0apns-priority = 10DATA+ END_STREAM{ "aps" : { "alert" : "Hello" } }
  • 基于token方式的request:

      HEADERS- END_STREAM+ END_HEADERS:method = POST:scheme = https:path = /3/device/00fc13adff785122b4ad28809a3420982341241421348097878e577c991de8f0host = api.development.push.apple.comauthorization = bearer eyAia2lkIjogIjhZTDNHM1JSWDciIH0.eyAiaXNzIjogIkM4Nk5WOUpYM0QiLCAiaWF0IjogIjE0NTkxNDM1ODA2NTAiIH0.MEYCIQDzqyahmH1rz1s-LFNkylXEa2lZ_aOCX4daxxTZkVEGzwIhALvkClnx5m5eAT6Lxw7LZtEQcH6JENhJTMArwLf3sXwiapns-id = eabeae54-14a8-11e5-b60b-1697f925ec7bapns-expiration = 0apns-priority = 10apns-topic = <MyAppTopic>DATA+ END_STREAM{ "aps" : { "alert" : "Hello" } }
  • 失败后的response:

      HEADERS- END_STREAM+ END_HEADERS:status = 400content-type = application/jsonapns-id: <a_UUID>DATA+ END_STREAM{ "reason" : "BadDeviceToken" }
  • 成功后的response:

      HEADERS- END_STREAM+ END_HEADERSapns-id = eabeae54-14a8-11e5-b60b-1697f925ec7b:status = 200

四、设备token的生成与分发

在app启动的时候,必须向iOS系统注册远程推送,成功后,苹果将会返回一个设备token给app,此时app就可以将这个token上报给自己的后台。

如果有必要产生一个新的token,APNs会使用设备证书生成一个token(其中包含了一个设备ID),并使用token key加密后返回给设备。同时设备会将这个token以NSData对象的形式返回给app,app获取到该token之后应该将其发送到自己后台,后台之后就可以通过这个token来发送推送数据。过程如下图:


Managing the device token

最后

通过苹果的官方文档我们可以知道provider与APNs的交互过程中,需要注意一下几点:

  • 推荐使用HTTP/2协议。
  • 必须加入TLS层。
  • 基于JWT的方式,token的最大有效期为1小时,并且不能频繁更换token。
  • 不能频繁创建、关闭连接,应该尽量少开连接,如果过于频繁,APNs将把其当做是黑客攻击,但是如果数据量大,可以同时多个连接向APNs发送消息。
  • 吊销token或者证书的时候,应该及时关闭老的连接。

参考文献

  1. APNs Overview
  2. Communicating with APNs

相关文章:

使用Application.GetResourceStream从XAP安装包加载任意资源

不得不说&#xff0c;WP7开发的资料真的是太少了&#xff0c;国内有句话叫“天下文章一大抄”&#xff0c;查Application.GetResourceStream的用法&#xff0c;找遍了整个网络&#xff0c;无非就那一两篇&#xff0c;而且写得还不完整&#xff0c;包括微软官方的例子。在花了近…

c语言知道算法写不出代码,这个代码怎么写算法啊,求教,我真的不会写算法怎么办#incl...

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼这个代码怎么写算法啊&#xff0c;求教&#xff0c;我真的不会写算法怎么办#include "stdio.h"#define N 3 //学生数3。struct Student //建立结构体。{int num;char name[20];float score[3];float aver;};int main(){v…

猎豹MFC--列表控件ListControl

ListControl添加变量&#xff1a;关联控件变量&#xff1a;初始化&#xff1a;设置样式 添加列标题&#xff1a;添加位图资源&#xff1a;添加位图变量&#xff1a;创建图像列表&#xff1a;并把图像列表 给 列表控件使用&#xff1a;双击添加行按钮&#xff1a;添加第2列时 不…

iOS 命令行自动打包 (archive)

原文链接&#xff1a;http://www.jianshu.com/p/2247f76404ebiOS 开发工程师在测试修复 bug 的过程中&#xff0c;一般会存在频繁打包的情况&#xff0c;如果一步步在 xcode 中点击 archive&#xff0c;下一步&#xff0c;下一步。。。这样太浪费我们的时间了。下面我们来介绍在…

看看现在大型网站都是用什么语言写的 ?

看看现在大型网站都是用什么语言写的 &#xff1f; 不排除一个网站用多种技术&#xff01;如淘宝是Java php&#xff0c;底层是java&#xff0c;表现层是php。新浪&#xff0c;网易&#xff0c;腾讯应该也是用了多种技术。 据说是这样的&#xff1a;php&#xff0c;新浪&#…

数据结构 算法与应用C 语言描述第六章,数据结构算法与应用-C语言描述002.pdf

下载下载第2 章 程 序 性 能以下是本章中所介绍的有关程序性能分析与测量的概念&#xff1a;• 确定一个程序对内存及时间的需求。• 使用操作数和执行步数来测量一个程序的时间需求。• 采用渐进符号描述复杂性&#xff0c;如 O、 、 、o 。• 利用计时函数测量一个程序的实际…

GCD 容易让人迷惑的几个小问题

来源&#xff1a;涂耀辉 链接&#xff1a;http://www.jianshu.com/p/ff444d664e51 写在开头&#xff1a; 本文旨在阐述一些大家容易产生迷惑的GCD相关内容&#xff0c;如果是需要了解一些GCD概念或者基础用法&#xff0c;可以看看这两篇文章&#xff1a;GCD 扫盲篇、巧谈GCD 。…

【贪心】【codevs】1214 线段覆盖

http://codevs.cn/problem/1214/ 我去这个题。。。wa的我都没脾气了。。。 我写while&#xff08;~scanf&#xff08;“%d”&#xff0c; &n&#xff09;&#xff09;竟然是不对的。。。 这个程序你妹多次输入是不能结束的&#xff1f;&#xff1f;&#xff1f;&#xff1f…

虚函数表剖析,网上转的,呵呵

http://www.cppblog.com/xczhang/archive/2008/01/20/41508.html C虚函数表解析(转)C中的虚函数的作用主要是实现了多态的机制。关于多态&#xff0c;简而言之就是用父类型别的指针指向其子类的实例&#xff0c;然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的…

c++语言文件流,C++ IO类、文件输入输出、string流详细讲解

新的C标准中有三分之二的内容都是描述标准库。接下来重点学习其中几种核心库设施&#xff0c;这些是应该熟练掌握的。标准库的核心是很多容器类(顺序容器和关联容器等)和一簇泛型算法(该类算法通常在顺序容器一定范围内的元素上或其他类型的序列上进行操作)。该篇主要学习IO库。…

iOS 走近商城 APP(三 WKWebView 商品规格选择框架封装)

原文链接&#xff1a;http://www.jianshu.com/p/293ee1bfe104商城 —— 由 3033 分享开篇 忽然发现最近也只有值班才能写东西了&#xff0c;中间更新了两篇其他的断了下商城相关的文章&#xff0c;仔细看了看之前觉得干货太少&#xff0c;今天写点实际的吧&#xff0c;闲说少说…

c语言如何不产生僵尸进程,第三章 九析带你处理 zombie(defunct) 进程

目录1 前言2 僵尸进程2.1 进程简介2.2 僵尸进程例子2.3 僵尸进程危害3 处理僵尸进程3.1 kill 命令3.2 kill 父进程3.3 reboot3.4 magic sysrq key 方法1 前言在 centos7 跑 Docker 和 k8s 时&#xff0c;偶尔会出现 systemctl 失效的情况&#xff0c;现象如下&#xff1a;Faile…

音视频开发学习笔记

http://www.jianshu.com/notebooks/6409162/top

VS2010 MFC中改变static字体颜色、大小、背景颜色(自定义类),及手动关联变量的方法...

在MFC的Dialog工程中生成一个CStatic的自定义类&#xff0c;类名例如为&#xff1a;CColorStatic 定义必要的变量&#xff1a; protected:COLORREF m_crText; // 字体颜色COLORREF m_crBackColor; // 背景颜色HBRUSH m_hBrush; // 画刷LOGFONT m_lf; // 字体…

android 上传字符串,Android中发送Http请求(包括文件上传、servlet接收)的实例代码...

/*** 通过拼接的方式构造请求内容&#xff0c;实现参数传输以及文件传输* param actionUrl* param params* param files* return* throws IOException*/public static String post(String actionUrl, Map params,Map files) throws IOException {String BOUNDARY java.util.UU…

JavaScript最全编码规范

转载: JavaScript最全编码规范 类型 ●基本类型&#xff1a;访问基本类型时&#xff0c;应该直接操作类型值 ●string ●number ●boolean ●null ●undefined var foo 1; var bar foo; bar 9; console.log(foo, bar); // > 1, 9 ●复合类型&#xff1a;访问复合类型时&a…

源码推荐:collectionView拖拽,仿凤凰FM iOS 局部监听键盘再也不会挡住输入框

UICollectionView拖拽移动单元以及本地保存&#xff08;上传者&#xff1a;dengqi&#xff09; UICollectionView拖拽移动单元以及本地保存&#xff0c;可以保存你上次移动的位置。 仿映客直播导航条&#xff08;上传者&#xff1a;Coolcool&#xff09; 仿映客直播自定义TabBa…

采集练习(一) php 获得全国的小学(数据来自腾讯朋友网)

注&#xff1a;发现腾讯朋友网已经改版&#xff0c;部分参数需要自己获得修改 &#xff01;&#xff01;&#xff01; 年前有个需求获得某省的小学数据&#xff0c;分析了下朋友网的小学学校发现可以获得相关数据。 如获得 湖南省郴州市宜章县的全部小学 发现网页请求的地址…

android 模板方法模式,安卓设计模式(七)模板方法模式

模板方法模式用于固定相关操作的执行流程,将具体实现延迟到子类中该系列其他文章:定义: 定义一个操作中算法的框架,而降一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤.使用场景:代码重构时,模板方法是经常被用到的,将固定部分提取到父…

solr单机版的搭建

一、solr单机版的搭建 1.运行环境 solr 需要运行在一个Servlet容器中&#xff0c;Solr4.10.3要求jdk使用1.7以上&#xff0c;Solr默认提供Jetty&#xff08;ja&#xff09;&#xff0c;本教va写的Servlet容器程使用Tocmat作为Servlet容器&#xff0c;环境如下&#xff1a; Solr…

android5.0后新特性修改标题头,Android5.0中Material Design的新特性

Material Design简介Material Design是谷歌新的设计语言&#xff0c;谷歌希望寄由此来统一各种平台上的用户体验&#xff0c;Material Design的特点是干净的排版和简单的布局&#xff0c;以此来突出内容。Material Design对排版、材质、配色、光效、间距、文字大小、交互方式、…

MFCard:易用的信用卡支付集成类库

原文链接&#xff1a;https://github.com/MobileFirstInc/MFCardMFCard&#xff1a;易用的信用卡支付集成类库。# 为开源点赞# —— 由 SwiftLanguage 分享MFCard is an awesome looking Credit Card input & validation control. Written in Swift 3. Demo Usage First St…

Castle ActiveRecord学习(四)延迟加载、分页查询、where条件

一、延迟加载 //用户发布的主题&#xff0c;一对多&#xff1b;Table&#xff1a;外键表&#xff1b;ColumnKey&#xff1a;外键&#xff1b;Lazy&#xff1a;延迟加载&#xff1b;Cascade&#xff1a;级联操作&#xff08;级联删除&#xff09;[HasMany(typeof(ThemeInfo), Ta…

系统吞吐量(TPS)、用户并发量、性能测试概念和公式(转载)

原文地址&#xff1a;http://www.ha97.com/5095.html PS&#xff1a;下面是性能测试的主要概念和计算公式&#xff0c;记录下&#xff1a; 一&#xff0e;系统吞度量要素&#xff1a; 一个系统的吞度量&#xff08;承压能力&#xff09;与request对CPU的消耗、外部接口、IO等等…

android layout后还原位置,Android图片框架photoview如何记住所有状态并还原,包括缩放度,缩放后的移动的距离等等...

Android图片框架photoview如何记住状态并还原&#xff0c;包括缩放度&#xff0c;缩放后的移动的距离等等,尝试了好多方法都没有作用。private void generateImages() {for (int i 0; i < imagesEntities.size(); i) {// PhotoViewAttacher attacher;final ImagesEntity en…

Shiro安全登录框架

环境准备 本文使用Maven构建&#xff0c;因此需要一点Maven知识。首先准备环境依赖&#xff1a; Java代码 <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <…

iOS自动签名打包(xcodebuild)----常用

iOS自动打包主要用xcodebuild命令, 在终端输入xcodebuild --help可以查看xcodebuild的参数。 xcodebuild具体语法&#xff1a; 无workspace的工程 xcodebuild [-project name.xcodeproj] [[-target targetname] … | -alltargets] [-configuration configurationname] [-sdk [s…

设计模式解析(五)——几种设计模式之Facade和Adapter

由于个人时间原因&#xff0c;无法详细描述这些模式&#xff0c;暂且记录下来以后慢慢补充详细。 Facade模式 Facade模式&#xff1a;关键特征 意图希望简化原有系统的使用方式。需要定义自己的接口。问题只需使用某个复杂系统的子集&#xff0c;或者&#xff0c;需要以一种特殊…

android level list,Android Drawable (levle List selector layer List)

8种机械键盘轴体对比本人程序员&#xff0c;要买一个写代码的键盘&#xff0c;请问红轴和茶轴怎么选&#xff1f;管理大量备选可绘制对象的可绘制对象&#xff0c;每个可绘制对象都分配有最大的备选数量。使用 setLevel() 设置可绘制对象的级别值会加载级别列表中 android:maxL…

人脸检测流程及正负样本下载

源地址&#xff1a;http://www.thinkface.cn/thread-146-1-4.html 人脸检测做训练当然可以用OpenCV训练好的xml&#xff0c;但是岂止于此。我们也要动手做&#xff01;~首先是样本的选取。样本的选取很重要&#xff0c;找了很久才发现几个靠谱的。人脸样本&#xff1a;http://w…