前段时间时间写了一篇配置腾讯信鸽推送证书的文章,本来打算在项目内集成一下信鸽推送,但后来看了文档和极光做了对比后,还是打算使用极光推送,现在就项目内添加极光推送做一下总结
这里先不对 APNs 做过多赘述,写一下极光推送的集成。
创建应用并上传对应的证书
关于证书的制作可以参考之前的文章:iOS 推送证书配置并为腾讯信鸽生成pem文件
腾讯信鸽需要制作好 .p12 证书后再生成对应的 .pem 证书,而极光相对简单,只需要导出 .p12 证书后上传并生成对应的 AppKey 即可。
配置工程
导入 SDK
导入极光 SDK 推荐使用 Cocoapods,相对于手动导入更简单便捷。
如果需要安装指定版本则使用以下方式(以3.0.2版本为例):
Build Settings
如果你的工程需要支持小于7.0的iOS系统,请到 Build Settings 关闭 bitCode 选项,否则将无法正常编译通过。
- 设置 Search Paths 下的 User Header Search Paths 和 Library Search Paths,比如SDK文件夹(默认为lib)与工程文件在同一级目录下,则都设置为”$(SRCROOT)/{静态库所在文件夹名称}”即可。
如使用 Xcode8 及以上环境开发,请开启 Application Target的Capabilities->Push Notifications 选项,如图:
允许 Xcode7 支持 Http 传输方法
如果使用的是 2.1.9 及以上的版本则不需要配置此步骤
选择1:根据域名配置
- 在项目的info.plist中添加一个Key:NSAppTransportSecurity,类型为字典类型。
- 然后给它添加一个NSExceptionDomains,类型为字典类型;
- 把需要的支持的域添加給NSExceptionDomains。其中jpush.cn作为Key,类型为字典类型。
- 每个域下面需要设置2个属性:NSIncludesSubdomains、NSExceptionAllowsInsecureHTTPLoads。 两个属性均为Boolean类型,值分别为YES、YES。
如图:
选择2:全局配置
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>
|
添加头文件
AppDelegate.m 引用头文件
#import "JPUSHService.h" #ifdef NSFoundationVersionNumber_iOS_9_x_Max #import <UserNotifications/UserNotifications.h> #endif #import <AdSupport/AdSupport.h>
|
添加Delegate
@interface AppDelegate ()<JPUSHRegisterDelegate> @end
|
添加初始化代码
添加初始化APNs代码
在 -(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
方法内添加如下代码:
JPUSHRegisterEntity * entity = [[JPUSHRegisterEntity alloc] init]; entity.types = JPAuthorizationOptionAlert|JPAuthorizationOptionBadge|JPAuthorizationOptionSound; if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) { } [JPUSHService registerForRemoteNotificationConfig:entity delegate:self];
|
添加初始化JPush代码
在-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
方法内添加如下代码:
NSString *advertisingId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString]; [JPUSHService setupWithOption:launchOptions appKey:appKey channel:channel apsForProduction:isProduction advertisingIdentifier:advertisingId];
|
部分参数说明:
- appKey
- 填写管理Portal上创建应用后自动生成的AppKey值。请确保应用内配置的 AppKey 与 Portal 上创建应用后生成的 AppKey 一致。
- channel
- 指明应用程序包的下载渠道,为方便分渠道统计,具体值由你自行定义,如:App Store。
- apsForProduction
- 1.3.1版本新增,用于标识当前应用所使用的APNs证书环境。
- 0 (默认值)表示采用的是开发证书,1 表示采用生产证书发布应用。
- 注:此字段的值要与Build Settings的Code Signing配置的证书环境一致。
注册APNs成功并上报DeviceToken
在AppDelegate.m 实现该回调方法并添加回调方法中的代码
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { [JPUSHService registerDeviceToken:deviceToken]; }
|
实现注册APNs失败接口(可选)
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { NSLog(@"did Fail To Register For Remote Notifications With Error: %@", error); }
|
添加处理APNs通知回调方法
在AppDelegate.m 实现该回调方法并添加回调方法中的代码
系统是 iOS 10 应用在前台运行时候的处理方法
#pragma mark- JPUSHRegisterDelegate - (void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger))completionHandler { NSDictionary * userInfo = notification.request.content.userInfo; if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) { [JPUSHService handleRemoteNotification:userInfo]; } completionHandler(UNNotificationPresentationOptionAlert); }
|
系统是 iOS 10 应用在后台运行并没有完全并杀死进程时候的处理方法
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler { NSDictionary * userInfo = response.notification.request.content.userInfo; if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) { [JPUSHService handleRemoteNotification:userInfo]; } completionHandler(); }
|
iOS 7 系统之后的处理方法
#pragma mark -- #pragma mark -- iOS7之后 - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { [JPUSHService handleRemoteNotification:userInfo]; completionHandler(UIBackgroundFetchResultNewData); if (application.applicationState == UIApplicationStateActive || application.applicationState == UIApplicationStateBackground) { }else if(application.applicationState == UIApplicationStateInactive) { NSLog(@"inactive"); } }
|
iOS 7 系统之前的处理方法
#pragma mark -- #pragma mark -- iOS7.0之前 - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { [JPUSHService handleRemoteNotification:userInfo]; application.applicationIconBadgeNumber = 0; if (application.applicationState == UIApplicationStateActive || application.applicationState == UIApplicationStateBackground) { }else { [self goToMssageViewControllerWith:userInfo]; } XZMLog(@"收到的推送信息 == %@",userInfo); }
|
大家可能会比较疑惑,现在 App 大部分系统都是 iOS 10,但是 iOS 10 的应用进程被完全杀死以后的推送处理在哪里进行呢?
其实,对于 iOS 10 系统,如果用户几天没有打开 App,进程已经完全被杀死的情况下,用户点击推送消息之后直接在系统的- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
方法里进行处理,可以增加以下代码:
NSDictionary *remoteNotification = [launchOptions objectForKey: UIApplicationLaunchOptionsRemoteNotificationKey]; if (remoteNotification) { }else{ }
|
本地的 badge 设置
[application setApplicationIconBadgeNumber:0]; [application cancelAllLocalNotifications];
|
JPush SDK 相关事件监听
extern NSString *const kJPFNetworkIsConnectingNotification; extern NSString * const kJPFNetworkDidSetupNotification; extern NSString * const kJPFNetworkDidCloseNotification; extern NSString * const kJPFNetworkDidRegisterNotification; extern NSString *const kJPFNetworkFailedRegisterNotification; extern NSString * const kJPFNetworkDidLoginNotification;
|
- Registration id 需要添加注册kJPFNetworkDidLoginNotification通知的方法里获取,也可以调用[registrationIDCompletionHandler:]方法,通过completionHandler获取
小结
1、通知内容可以按照系统方法或者自定义通知或者富媒体消息进行。
系统方法有对应的格式,推送消息的展示只需要在对应格式上添加字段即可(需要根据推送的内容和后台商定相关的字段)。
自定义通知和富媒体消息的推送可以参考极光官方文档进行配置。
2、大部分 iOS 端通知都是涉及到 badge 的,具体 手机上的展示以及后台推送时该怎么传参,需要移动端和后台配合,并把推送消息的是否已读的状态传到后端做对应的处理,才能达到好的用户体验。
根据这几天的观察,大部分 App 存在一个问题:当我 App 已经接受到了多条推送消息时,当我点击某一条推送进入到 App 后 badge 直接清除,通知栏也随之清除,我看了一条推送消息后想再查看其他不错的推送时已经找不到了。
当然也有部分 App 做的比较好,就是有多条推送消息时,点击某一条推送消息后,badge 对应的 -1,看完以后可以继续查看其他推送消息,后台 badge 也会对应更新,再有新的推送时 badge 对应 +1。所以,在做推送时,这些小的细节还需要完善,提升用户体验也要根据实际情况做对应的处理。这里不再过多赘述。
3、当在开发环境想要转到生产环境时,务必修改apsForProduction
为生产环境。我在本地配置时,因为是第一版我想转到生产环境进行测试,但是试了几次之后都没有成功。后来我直接改了 apsForProduction
参数然后打包上传到 App Store,当审核通过后下载下来的 App 对应的就是生产环境。
[JPUSHService setupWithOption:launchOptions appKey:appKey channel:channel apsForProduction:isProduction advertisingIdentifier:advertisingId];
|
查了这个问题,官方说不仅要修改字段,还需要更改本地的证书为生产证书,尝试无果后搁置,不过没有影响开发环境和生产环境。
4、通篇看来,整个推送的集成分为以下步骤
- SDK 的导入和编译设置
- 添加头文件并初始化 APNs 和 JPush
- 初始化成功后实现对应的代理方法并对通知的情况做对应的处理
整体步骤相对不是很复杂,但是对于推送消息的处理,用户体验的处理还是比较难的。这就需要考量整个产品的设计和程序员对产品的理解,有时候产品可能也考虑不到诸如 badge 如何变化的细节,这就需要程序员在集成时多从产品角度思考,多优化细节了。
「04.17 更新」别名的设置
某些时候,我们需要推送给信息给个别用户。今天下午设置了一下别名,更新总结下:
首先注册通知,等待 JPush 登录成功后再去设置别名:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkDidLogin:) name:kJPFNetworkDidLoginNotification object:nil];
|
再实现别名设置的方法
* 登录成功,设置别名,移除监听 * * @param notification <#notification description#> */ - (void)networkDidLogin:(NSNotification *)notification { NSLog(@"已登录"); [JPUSHService setTags:nil alias:@"123" fetchCompletionHandle:^(int iResCode,NSSet *iTags,NSString *iAlias) { XZMLog(@"rescode: %d, \ntags: %@, \nalias: %@\n", iResCode, iTags , iAlias); }]; [[NSNotificationCenter defaultCenter] removeObserver:self name:kJPFNetworkDidLoginNotification object:nil]; }
|
注意:iResCode == 0 时代表注册别名成功,在注册别名时可能会出现连接超时或者别名格式不正确的情况,错误状态参考『极光 SDK API 文档』
关于推送别名、标签详细的理解在『推送人群的选择-技术篇』有详细的说明。
微信扫一扫,向我赞赏
支付宝扫一扫,向我赞赏