详解APNS苹果消息推送通知

简介: 苹果消息通知什么?如下图如示就是APP的服务端在用户未打开APP进程时,还能发通知给用户APP的服务技术相关概念Provider:提供推送的第三方服务系统Device:苹果设备,...

苹果消息通知什么?

如下图如示


就是APP的服务端在用户未打开APP进程时,还能发通知给用户APP的服务技术

相关概念

Provider:提供推送的第三方服务系统

Device:苹果设备,例如iphone和ipad等

APNS:苹果推送消息服务,属于苹果的服务

APP:安装在苹果设备上的应用程序

DeviceToken:设备的标识,用于确定接收通知的设备及APP

Payload:推送消息的传输形式

总体示意图

从上图可以看出Provider与APNS之间是要建立连接的,APNS和Device之间也是要建立连接的,这两个连接都是加密的,采用的TLS的方式,加密用的证书是在苹果官方网站上购买生成的,这个证书分两种,一种是“开发者证书”,使用开发者证书的APP可以发布在APPSTORE上面,开发者证书的使用费是每年99美元,另一种是“企业证书”,使用企业证书的APP只能发在企业内部市场,不能发在APPSTORE上,企业证书的年费是299美元,企业证书对安装人数是没有限制的,但开发者证书对APP的安装人数是有限制的,但从APPSTORE上安装则没有限制。

安全连接的建立方式如图:


如何获取确定接收者的DeviceToken?

Provider如何取得DeviceToken呢?具体如图所示:



获取是由APP通过注册服务后取得DeviceToken,然后传给Provider。由于这个DeviceToken是会变的,所以最好是APP在每次启动时都能注册一下,获取最新的DeviceToken

IOS下的注册获取DeviceToken的代码官方给出如下:

- (void)applicationDidFinishLaunching:(UIApplication *)app {// other setup tasks here....
[[UIApplication sharedApplication]
registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge |
UIRemoteNotificationTypeSound)];
}
// Delegation methods
- (void)application:(UIApplication *)app
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {
const void *devTokenBytes = [devToken bytes];
self.registered = YES;
[self sendProviderDeviceToken:devTokenBytes]; // custom method
}
- (void)application:(UIApplication *)app
didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
NSLog(@"Error in registration. Error: %@", err);
}

如何发送通知消息?

Provider和APNS之间是一个安全的Socket连接,传输的是规定格式的二进制数据,如下形式


当然,这个就是TCP报文,然而具体的报文又有好几种,有发送普通消息的传输形式,有获取错误响应的传输形式,还有获取反馈的报文形式等,对于普通的发消息的报文格式如图如示:


最前面1个字节是命令类型,2-3字节是DeviceToken的长度,后面是DeviceToken的具体值,后面是消息的长度和消息的具体内容。发完消息后,在关闭Socket前还可以查看错误的响应,以便确认消息是否成功地发给APNS,错误响应的报文如下:


命令为8的表示是错误响应的报文,Status是错误码,Identifier是用于定位具体的哪条推送消息,这个是增强型通知里的传入的值,首先看下苹果都有哪些返回错误码:


再看下Identifier传入使用的增强型的通知报文格式:



官方给出发送普通消息的C++代码如下:

static bool sendPayload(SSL *sslPtr, char *deviceTokenBinary, char *payloadBuff, size_t payloadLength){
    bool rtn = false;
    if (sslPtr && deviceTokenBinary && payloadBuff && payloadLength){
	uint8_t command = 0; /* command number */
	char binaryMessageBuff[sizeof(uint8_t) + sizeof(uint16_t) +
	DEVICE_BINARY_SIZE + sizeof(uint16_t) + MAXPAYLOAD_SIZE];
	/* message format is, |COMMAND|TOKENLEN|TOKEN|PAYLOADLEN|PAYLOAD| */
	char *binaryMessagePt = binaryMessageBuff;
	uint16_t networkOrderTokenLength = htons(DEVICE_BINARY_SIZE);
	uint16_t networkOrderPayloadLength = htons(payloadLength);
	/* command */
	*binaryMessagePt++ = command;
	/* token length network order */
	memcpy(binaryMessagePt, &networkOrderTokenLength, sizeof(uint16_t));
	binaryMessagePt += sizeof(uint16_t);
	/* device token */
	memcpy(binaryMessagePt, deviceTokenBinary, DEVICE_BINARY_SIZE);
	binaryMessagePt += DEVICE_BINARY_SIZE;
	/* payload length network order */
	memcpy(binaryMessagePt, &networkOrderPayloadLength, sizeof(uint16_t));
	binaryMessagePt += sizeof(uint16_t);
	/* payload */
	memcpy(binaryMessagePt, payloadBuff, payloadLength);
	binaryMessagePt += payloadLength;
	if (SSL_write(sslPtr, binaryMessageBuff, (binaryMessagePt - binaryMessageBuff)) > 0)
            rtn = true;
    }
    return rtn;
}

发送增强的通知消息的代码:

static bool sendPayload(SSL *sslPtr, char *deviceTokenBinary, char *payloadBuff, size_t payloadLength){
    bool rtn = false;
    if (sslPtr && deviceTokenBinary && payloadBuff && payloadLength){
	uint8_t command = 1; /* command number */
	char binaryMessageBuff[sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint16_t) + DEVICE_BINARY_SIZE + sizeof(uint16_t) + MAXPAYLOAD_SIZE];
	/* message format is, |COMMAND|ID|EXPIRY|TOKENLEN|TOKEN|PAYLOADLEN|PAYLOAD|*/
	char *binaryMessagePt = binaryMessageBuff;
	uint32_t whicheverOrderIWantToGetBackInAErrorResponse_ID = 1234;
	uint32_t networkOrderExpiryEpochUTC = htonl(time(NULL)+86400); // expire
	message if not delivered in 1 day
	uint16_t networkOrderTokenLength = htons(DEVICE_BINARY_SIZE);
	uint16_t networkOrderPayloadLength = htons(payloadLength);
	/* command */
	*binaryMessagePt++ = command;
	/* provider preference ordered ID */
	memcpy(binaryMessagePt, &whicheverOrderIWantToGetBackInAErrorResponse_ID,
	sizeof(uint32_t));
	binaryMessagePt += sizeof(uint32_t);
	/* expiry date network order */
	memcpy(binaryMessagePt, &networkOrderExpiryEpochUTC, sizeof(uint32_t));
	binaryMessagePt += sizeof(uint32_t);
	/* token length network order */
	memcpy(binaryMessagePt, &networkOrderTokenLength, sizeof(uint16_t));
	binaryMessagePt += sizeof(uint16_t);
	/* device token */
	memcpy(binaryMessagePt, deviceTokenBinary, DEVICE_BINARY_SIZE);
	binaryMessagePt += DEVICE_BINARY_SIZE;
	/* payload length network order */
	memcpy(binaryMessagePt, &networkOrderPayloadLength, sizeof(uint16_t));
	binaryMessagePt += sizeof(uint16_t);
	/* payload */
	memcpy(binaryMessagePt, payloadBuff, payloadLength);
	binaryMessagePt += payloadLength;
	if (SSL_write(sslPtr, binaryMessageBuff, (binaryMessagePt - binaryMessageBuff)) > 0)
	    rtn = true;
  }
  return rtn;
}

角标(Badge)是什么?

还有一个重要的概念是角标,如下:


这个角标是推送消息里传的,可以指定,这个要看具体的业务怎么定了,用于提醒用户未读消息个数。

结尾

了解了以上原理和过程,相信用什么语言都可以写Provider程序了,本人基于java语言也简单写了个demo,可以支持多个应用的推送,等完善了就可以放github了
目录
相关文章
|
JSON 数据格式 iOS开发
APNS IOS 消息推送JSON格式介绍
在开发向苹果Apns推送消息服务功能,我们需要根据Apns接受的数据格式进行推送。下面积累了我在进行apns推送时候总结的 apns服务接受的Json数据格式 示例 1: 以下负载包含哦一个简单的 aps 字典。
3425 0
|
Android开发 数据安全/隐私保护 iOS开发
APNS IOS 消息推送
一.Apns简介: Apns是苹果推送通知服务。 二.原理: APNs会对用户进行物理连接认证,和设备令牌认证(简言之就是苹果的服务器检查设备里的证书以确定其为苹果设备);然后,将服务器的信息接收并且保存在APNs当中,APNs从其中注册的列表中查找该IOS设备(设备可以为iPhone、iPad、iPod Touch,版本是iOS3.
1691 0
|
测试技术 iOS开发
APNS IOS 消息推送沙盒模式和发布模式
在做.NET向IOS设备的App进行消息推送时候,采用的是PushSharp开源类库进行消息的推送,而在开发过程中,采用的是测试版本的app,使用的是测试的p12证书采用的是ApnsConfiguration.ApnsServerEnvironment.Sandbox模式,而在项目发布之后,现在使用的是发布版的证书进行推送,发现不能推送成功,最后才发现在使用PushSharp进行发布后的项目的推送需要使用ApnsConfiguration.ApnsServerEnvironment.Production模式。
1405 0
|
iOS开发
APNS IOS 消息推送处理失效的Token
在开发苹果推送服务时候,要合理的控制ios设备的Token,而这个Token是由苹果服务器Apns产生的,就是每次app问Apns要Token,由苹果服务器产生的Token会记录到Apns里面,我们需要根据该Token进行制定设备的消息推送,所有Token需要我们自己去记录和管理,每个设备对应唯一的Token,而app的用户登录会有自己约束的别名,与该tokne进行关系绑定,这样按该别名进行推送,就可以找到对应的Token,进而推送到该iso设备上,对应失效的Token我们需要访问苹果的feedbackServer,拿取失效的Token,然后把本地记录的失效token进行移除。
2013 0
|
网络协议 安全 Java
基于APNs最新HTTP/2接口实现iOS的高性能消息推送(服务端篇)
本文原作者:liuyan731,原文地址:liuyan731.github.io/2017/12/05/How-To-Use-APNs-Pushy,内容有改动。
3536 0
|
网络协议 网络安全 iOS开发
|
Java 测试技术 网络安全
IOS 基于APNS消息推送原理与实现(JAVA后台)
IOS 基于APNS消息推送原理与实现(JAVA后台) Push的原理: Push 的工作机制可以简单的概括为下图   图中,Provider是指某个iPhone软件的Push服务器,这篇文章我将使用.net作为Provider。
2088 0
|
Java iOS开发
java ,apns, javapns ios消息推送 吐槽
  apple server 检测的token 有问题 (如下图)   如图显示, 我在每1000 个消息的时候 发送一个错误的token,而实际出现了75923处 有个错误的token ,很疑惑,这是apple的问题吗?                                               捐助开发者 在兴趣的驱动下,写一个免费的东西,有欣喜,也还有汗水,希望你喜欢我的作品,同时也能支持一下。
905 0
|
iOS开发
IOS消息推送
IOS消息推送
131 0
|
Android开发 iOS开发
了解iOS消息推送一文就够:史上最全iOS Push技术详解
本文作者:陈裕发, 腾讯系统测试工程师,由腾讯WeTest整理发表。 1、引言 开发iOS系统中的Push推送,通常有以下3种情况: 1)在线Push:比如QQ、微信等IM界面处于前台时,聊天消息和指令都会通过IM自建的网络长连接通道推送过来,这种Pu...
3398 0