一. push原理
iOS push工作机制可以使用下图概括:
- Provider:应用自己的服务器;
- APNS:Apple Push Notification Service的简称,苹果Push服务器.
可以简化为:
二. push执行时序可由下图示意:
三. push for iOS客户端-deviceToken
.关于客户端获取deviceToken
服务端要发送push消息给某一设备还必须知道该设备的deviceToken。应用运行后获取到deviceToken,然后上传给服务器.
下面介绍如何获取deviceToken?
1
2
3
4
|
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeBadge)];
}
|
- 2.在AppDelegate中添加下面方法来获取deviceToken:
1
2
3
4
5
6
7
8
9
10
|
// 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);
}
|
应用获取到deviceToken后,上传给Provider,Provider就可以用这个deviceToken给这个设备push消息了。
通常情况下,deviceToken是不会改变的;有时同一台设备可能有不同的deviceToken。关于该主题可以搜索相关内容
所以,当deviceToken改变时一定要通知服务器更新。
四.push for provider
服务器配置好证书并拿到deviceToken后就可以向APNS发送消息了. 发送消息的格式有两种:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
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;
}
|
- 2.增强型消息格式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
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;
}
|
五. push for iOS客户端-处理push消息
iOS系统收到push消息后,如果用户点击查看,
- 1.如果应用已经启动,将调用application:didReceiveRemoteNotification的方法:
1
2
3
4
|
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
// userInfo 就是push消息Payload
}
|
- 2.如果应用还没有启动,通过push冷启动后,仍然能在启动后获取Payload:
1
2
3
4
5
6
|
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
NSDictionary* userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
}
|
六.关于消息控制方面
可以在application:didReceiveRemoteNotification控制消息的显示,消失。
例如:
1
|
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
|
详情可参考苹果开发文档Apple Push Notification Service
文章作者
梵梵爸
上次更新
2014-10-21
许可协议
原创文章,如需转载请注明文章作者和出处。谢谢