前言
iOS10下,远程推送发生了变化,新增的UserNotifications.framework将本地推送和远程推送整合在一起。 最近刚刚更新了Xcode8,自动创建证书和配置文件确实方便许多。琰君分享下以开发环境为例(非生产环境)在Xcode8下,快速集成极光推送并兼顾iOS10。
注意:极光推送的远程推送是免费的,但相应的用户统计,终端统计等功能是不免费。如果你需要用户统计,终端统计这些功能意味着需要付费才能使用。
参考链接
开发证书配置
APNs 推送原理及问题
iOS 推送全解析,你不可不知的所有 Tips!
接下来假设你都了解证书相关的,推送的一些概念和极光推送的知识。那么相信你应该知道需要一台iOS设备和一个苹果开发者帐号才能去体验远程推送。如果你清楚远程推送的原理,那可以直接从以下第2步开始。
集成步骤
- 远程推送原理
- Xcode8创建项目,配置自动创建
App ID/证书/配置文件 - 创建APNs 推送证书
- 在极光推送后台创建应用,并上传APNs 推送证书
- 项目中集成极光推送SDK
- 获取 APNs(通知) 推送内容
- 极光推送后台发送远程推送测试
1. 远程推送原理
当iOS设备联网的情况下,苹果服务器和iOS设备建立了一个长链接,即便应用处于挂起和后台的状态,苹果可以给iOS设备中的应用发送通知。

远程推送原理
概念
- iOS:iOS设备
- APNS Server:苹果服务器
- Your App: 自己的应用,例如咕咚
- Your Server:自己的服务器,例如咕咚服务器
推送流程
- iOS 应用注册推送通知,iOS设备将设备的
UDID和应用的Bundle ID到苹果服务器。 - 苹果服务器将接收到的
UDID和Bundle ID加密生成一个deviceToken,并返回给对应iOS应用。 - iOS应用将接收到的
deviceToken发送到自己的服务器,服务器并保存。 - 自己的服务器需配置APNs 推送证书,当需要推送时,去后台查询推送目标设备的
deviceToken,将消息和deviceToken一起发送给苹果服务器。 - 苹果服务器通过
deviceToken找到对应设备下的对应应用,推送消息。
说明
- 我们的应用真机测试需要创建对应App ID/证书/配置文件, 这步可以用Xcode8 自动创建,而不需要到苹果开发者平台去创建。如果不是Xcode8,则需要去开发者平台申请,并且在Xcode配置,保证真机测试即可。
- 我们自己的服务器需要配置 APNs 推送证书,同样的分为开发证书和生产证书。需要到苹果开发者平台去申请。
- 如果不借助第三方推送平台,我们需要完成推送流程中的1,3,4步。借助极光推送,那么我们只需要完成推送流程中的1,3步,但同样需要我们申请APNs 推送证书,并且上传到极光推送平台。
2. Xcode8配置自动创建App ID/证书/配置文件
- 在Xcode8下,确保已经登录付费苹果开发者帐号。请开启Application Target的Capabilities->Push Notifications选项。

开启远程推送
2.勾选自动管理App ID/证书/配置文件

勾选自动管理
3.检查Xcode生产的App ID/证书/配置文件这步配置好了就可以真机运行了。

检查Xcode生产的App ID/证书/配置文件
3. 创建APNs 推送证书
- 登录开发者网站,并点击按钮创建证书

点击按钮创建证书
2.选择开发环境APNs 推送证书点击右下角按钮创建

创建开发环境APNs 推送证书
3.选择工程的App ID

选择工程的App ID
4.上传证书请求文件,不知道的童鞋可参照开发证书配置

上传证书请求文件
5.点击下载证书,并双击安装到钥匙串.

安装APNs 推送证书
6.打开钥匙串,并参照下图指示,找到对应的APNs 推送证书,并选择右键导出.

钥匙串导出证书
7.设置证书名字,并选择证书存放位置。

设置证书名字
8.设置证书密码,可不填。极光推送支持证书设置密码,但像leanCloud推送不支持证书设置密码,各位童鞋可按照实际情况来。最后输入电脑开密码,导出证书。

设置证书密码

输入电脑开机密码导出证书
4. 在极光推送后台创建应用,并上传APNs 推送证书
1.登录极光推送平台,切换到控制台,并创建应用。接下来在应用信息中上传开发APNs 推送证书。生产环境APNs 推送证书配置类似,不做赘述.

上传开发APNs 推送证书
- 核对应用的
Bundle ID等信息是否正确.
核对Bundle ID 等信息
5. 项目中集成极光推送SDK
- 导入极光推送SDK
jpush-ios-2.1.9.a JPUSHService.h - 导入系统依赖库
CFNetwork.framework CoreFoundation.framework CoreTelephony.framework SystemConfiguration.framework CoreGraphics.framework Foundation.framework UIKit.framework Security.framework libz.tbd Adsupport.framework (获取IDFA需要;如果不使用IDFA,请不要添加) UserNotifications.framework(Xcode8及以上) -
AppDelegate.m 配置
导入以下头文件#import "JPUSHService.h" #import <AdSupport/AdSupport.h> #ifdef NSFoundationVersionNumber_iOS_9_x_Max #import <UserNotifications/UserNotifications.h> #endif并且遵守
<JPUSHRegisterDelegate>协议@interface AppDelegate ()<JPUSHRegisterDelegate> @end注册远程推送
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) { //iOS10以上 JPUSHRegisterEntity * entity = [[JPUSHRegisterEntity alloc] init]; entity.types = UNAuthorizationOptionAlert|UNAuthorizationOptionBadge|UNAuthorizationOptionSound; [JPUSHService registerForRemoteNotificationConfig:entity delegate:self]; }else if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) { //iOS8以上可以添加自定义categories [JPUSHService registerForRemoteNotificationTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert) categories:nil]; } else { //iOS8以下categories 必须为nil [JPUSHService registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert) categories:nil]; } BOOL isProduction = NO;// NO为开发环境,YES为生产环境 //广告标识符 NSString *advertisingId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString]; //Required(2.1.5版本的SDK新增的注册方法,改成可上报IDFA,如果没有使用IDFA直接传nil [JPUSHService setupWithOption:launchOptions appKey:@"极光推送AppKey" channel:nil apsForProduction:isProduction advertisingIdentifier:advertisingId]; return YES; }得到苹果服务器返回的
deviceToken,上传到极光推送服务器。-(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{ [JPUSHService registerDeviceToken:deviceToken]; }注册远程通知失败,比如没有联网的状态下。
-(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{ NSLog(@"did Fail To Register For Remote Notifications With Error: %@", error); }6.获取 APNs(通知) 推送内容
iOS 设备收到一条推送(APNs),用户点击推送通知打开应用时,应用程序根据状态不同进行处理需在 AppDelegate 中的以下方法中添加代码以获取apn内容
1.如果 App 状态为未运行,此函数将被调用,如果launchOptions包含UIApplicationLaunchOptionsRemoteNotificationKey表示用户点击apn 通知导致app被启动运行;如果不含有对应键值则表示 App 不是因点击apn而被启动,可能为直接点击icon被启动或其他。-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ // apn 内容获取: NSDictionary *remoteNotification = [launchOptions objectForKey: UIApplicationLaunchOptionsRemoteNotificationKey] }2.基于iOS 6 及以下的系统版本,如果 App状态为正在前台或者点击通知栏的通知消息,那么此函数将被调用,并且可通过AppDelegate的applicationState是否为UIApplicationStateActive判断程序是否在前台运行。
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{ }3.基于iOS 7 及以上的系统版本,如果是使用 iOS 7 的 Remote Notification 特性那么此函数将被调用
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler: (void (^)(UIBackgroundFetchResult))completionHandler { [JPUSHService handleRemoteNotification:userInfo]; NSLog(@"iOS7及以上系统,收到通知:%@", [self logDic:userInfo]); completionHandler(UIBackgroundFetchResultNewData); } -(NSString *)logDic:(NSDictionary *)dic { if (![dic count]) { return nil; } NSString *tempStr1 = [[dic description] stringByReplacingOccurrencesOfString:@"\\u" withString:@"\\U"]; NSString *tempStr2 = [tempStr1 stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]; NSString *tempStr3 = [[@"\"" stringByAppendingString:tempStr2] stringByAppendingString:@"\""]; NSData *tempData = [tempStr3 dataUsingEncoding:NSUTF8StringEncoding]; NSString *str = [NSPropertyListSerialization propertyListFromData:tempData mutabilityOption:NSPropertyListImmutable format:NULL errorDescription:NULL]; return str; }4.基于iOS 10及以上的系统版本,
原[application: didReceiveRemoteNotification:]将会被系统废弃,
由新增UserNotifications.framework中的以下两个方法替代。[UNUserNotificationCenterDelegate willPresentNotification:withCompletionHandler:] [UNUserNotificationCenterDelegate didReceiveNotificationResponse:withCompletionHandler:]
在极光推送SDK2.1.9版本以后可实现SDK封装的JPUSHRegisterDelegate协议方法,适配iOS10新增的delegate协议方法。
即以下两个方法:
#ifdef NSFoundationVersionNumber_iOS_9_x_Max
#pragma mark- JPUSHRegisterDelegate
-(void)jpushNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger))completionHandler {
NSDictionary * userInfo = notification.request.content.userInfo;
UNNotificationRequest *request = notification.request; // 收到推送的请求
UNNotificationContent *content = request.content; // 收到推送的消息内容
NSNumber *badge = content.badge; // 推送消息的角标
NSString *body = content.body; // 推送消息体
UNNotificationSound *sound = content.sound; // 推送消息的声音
NSString *subtitle = content.subtitle; // 推送消息的副标题
NSString *title = content.title; // 推送消息的标题
if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
[JPUSHService handleRemoteNotification:userInfo];
NSLog(@"iOS10 前台收到远程通知:%@", [self logDic:userInfo]);
}
// 需要执行这个方法,选择是否提醒用户,有Badge、Sound、Alert三种类型可以设置
completionHandler(UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionSound|UNNotificationPresentationOptionAlert);
}
//
-(void)jpushNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
NSDictionary * userInfo = response.notification.request.content.userInfo;
UNNotificationRequest *request = response.notification.request; // 收到推送的请求
UNNotificationContent *content = request.content; // 收到推送的消息内容
NSNumber *badge = content.badge; // 推送消息的角标
NSString *body = content.body; // 推送消息体
UNNotificationSound *sound = content.sound; // 推送消息的声音
NSString *subtitle = content.subtitle; // 推送消息的副标题
NSString *title = content.title; // 推送消息的标题
if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
[JPUSHService handleRemoteNotification:userInfo];
NSLog(@"iOS10 收到远程通知:%@", [self logDic:userInfo]);
}
completionHandler(); // 系统要求执行这个方法
}
#endif
7. 极光推送后台发送远程推送测试
1.登录极光推送,切换到控制台,并点击对应的应用,点击推送按钮

点击推送按钮

点击发送通知
2.设置推送内容

设置推送内容
选择推送环境iOS开发环境,目标人群,发送时间。再点击可选设置设置消息的具体内容。

屏幕快照
3.设置消息具体内容。远程推送分为普通推送/后台推送/静默推送3种类型,并且类型由推送消息设置来决定。关于如何设置请参考iOS 推送全解析,你不可不知的所有 Tips!

屏幕快照 2016-09-26 上午10.54.59.png
4.iOS设备接收到远程推送

接收到远程推送
5.推送历史可以在这里看得到,但有延迟,可能远程推送已接收到,推送历史数据还没有更新到最新。

屏幕快照 2016-09-28 上午10.23.16.png
关于Xcode8下集成极光远程推送的简单介绍,到这里就结束了。
文/赵先生Try(简书作者)
原文链接:http://www.jianshu.com/p/53e0244e6081
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
来源:oschina
链接:https://my.oschina.net/u/2524932/blog/776356
