详解APNS苹果消息推送通知
来源:互联网 发布:java观察者模式demo 编辑:程序博客网 时间:2024/05/18 04:01
苹果消息通知什么?
如下图如示
就是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 *)appdidRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {const void *devTokenBytes = [devToken bytes];self.registered = YES;[self sendProviderDeviceToken:devTokenBytes]; // custom method}- (void)application:(UIApplication *)appdidFailToRegisterForRemoteNotificationsWithError:(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); // expiremessage if not delivered in 1 dayuint16_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)是什么?
还有一个重要的概念是角标,如下:
这个角标是推送消息里传的,可以指定,这个要看具体的业务怎么定了,用于提醒用户未读消息个数。
结尾
- 详解APNS苹果消息推送通知
- 【.NET向APNS苹果消息推送通知】
- 苹果远程推送通知 APNs 详解,官方,iOS | Swift | UNNotification
- 苹果推送通知服务(APNs)编程
- 苹果推送通知服务(APNs)编程
- 苹果推送通知服务(APNs)编程
- 苹果推送通知服务(APNs)编程
- 苹果推送通知服务(APNs)编程
- 苹果推送通知服务(APNs)编程
- 苹果推送通知服务(APNs)编程
- 苹果推送通知服务(APNs)编程
- 苹果推送通知服务(APNs)编程
- 苹果推送通知服务(APNs)编程
- 苹果推送通知服务(APNs)编程
- 苹果的推送通知服务(APNs)
- 向苹果APNS推送消息开发库 APNS-Sharp
- Apple Push Notification Services (APNS)苹果推送通知服务
- iPhone开发之 - 苹果推送通知服务(APNs)编程
- 错误代码: 1111 Invalid use of group function
- 4-h-Median of Two Sorted Arrays
- Ubuntu下更改网卡名称
- 数字滤波技术
- LeetCode Valid Parentheses
- 详解APNS苹果消息推送通知
- Intel VMCS学习总结
- python多线程与线程同步
- 145.Binary Tree Postorder Traversal
- NVIDIA 的深度学习工具箱NVIDIA DIGITS:可视化训练
- 在JAVA中目录列表器file的应用及Matcher对象与Pattern对象的使用
- VMware11安装OS X10.10和xcode整理
- Leetcode Valid Palindrome
- [转]学JS必看