苹果提供了一堆服务器,每个ios设备和这些服务器保持了一个长连接,ios版本更新提示、手机时钟校准等操作都是通过这个连接实现。消息推送服务简称为APNS(Apple Push Notification Service),是该长连接中的一个服务,如果要向用户发消息,必须通过APNS进行中转。消息推送不支持群发,只能一个一个发,消息包一般由两部分组成:标示用户手机的id(32个字节)+消息体(<=256Bytes),消息体是json字符串,传输过程使用SSL加密。
消息推送关系图:
关于DeviceToken:
每台机器的Device Token都不一样,但不是硬件编码(UDID),如果重新安装操作系统,Device Token可能会发生变化。它是在用户手机发起请求时由ASPN生成的。
AppDelegate的代理方法- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
可以获取到用户设备的Device Token。
注意:DeviceToken的生成机制可能随时变化,最好方法每次获取到deviceToken后,与之前(如果有)的deviceToken进行比较,如果发生变化,及时更新自己数据服务器上的记录
DeviceToken的处理流程图:
消息推送的实现步骤:
在苹果开发者中心注册并下载一份cer文件
新建并下载一个Provisioning Profile
代码示例:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// 需要告诉苹果的服务器,当前应用程序需要接收远程通知
[application registerForRemoteNotificationTypes:UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound];
return YES;
}
#pragma mark - 获取到设备的代号(令牌)
// 接收到苹果返回的设备代号
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
// 第一次运行获取到DeviceToken时间会比较长!
NSLog(@"%@", deviceToken);
// 将deviceToken转换成字符串,以便后续使用
NSString *token = [deviceToken description];
NSLog(@"description %@", token);
// =======================================================
// 如果DeviceToken发生变化,需要通知服务器
// 每次都记录住从服务器获取到得DeviceToken
// 再次获取时进行比对
// 从偏好设置取出当前保存的Token
NSString *oldToken = [[NSUserDefaults standardUserDefaults] objectForKey:@"DeviceToken"];
//当Token发生变化时,提交给服务器保存新的Token
if (![oldToken isEqualToString:token]) {
// 将deviceToken通过Post请求,提交给自己的服务器即可!
// 发送Post请求
NSURL *url = [NSURL URLWithString:@"公司后台服务器的网址"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.f];
request.HTTPMethod = @"POST";
request.HTTPBody = @"转换后的设备ID以及其他信息[之前的Token]";
// SQL: update t_deviceTable set token = newToken where token = oldToken;
// 同步:必须执行完才能继续
// 异步:直接交给其他线程工作,不干扰主线程工作,用户也感觉不到延迟
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
// 偷偷的将用户信息传送到公司的服务器
}];
}
// 将Token保存至系统偏好
[[NSUserDefaults standardUserDefaults] setObject:token forKey:@"DeviceToken"];
}
在-(void)application:didReceiveRemoteNotification:fetchCompletionHandler: 方法中 接收到远程通知处理方法
发送通知消息的工作由后台服务器完成,客户端开发不需要考虑