ios 极光推送的集成及注意事项

好凉一个秋

好久没有发动态了,今天介绍一下极光推送,关于apple通知的一些原理,这里就不做细致的介绍了,想要了解内部推送的原理,大家可以在简书搜索iOS开发知识汇总专题,点击链接http://www.jianshu.com/collection/b9235769faa3 可直接进入,或者搜索微信公众号iOS开发知识汇总

Snip20161024_2.png

now,我们从创建好极光应用开始,获得appkey之后,打开xcode,进入项目,如图,可以看到有个开关,push notifications

通知开关

打开开关之后,会生成一个项目名.entitlements的文件
entitlements.png

but在这之前,很多人没有push notificaitons开关,don't worry,进入极光主页,你会发现,需要导入各种依赖库

依赖库.png

我们在xcode下的Build Phases逐个添加依赖库,如图

Build Phases

导入依赖库之后,在这里最关键的依赖库是UserNotificationcations.framework(xcode8及以上),关闭程序,重新启动,开关就会出现,然后打开开关,如图

Push Notifications

在开关下面,steps有两个项目,第一个如果爆红,说明没有导入项目所需的证书及配置文件(即在apple developer 生成的证书及配置文件) ,导入即可;如果第二个爆红,可能是因为你不小心删除了项目名.entitlements文件,解决方法是,关闭push Notifications开关之后再打开即可生成,如果不行的话,关闭程序,在关闭打开开关即可,如果 如果再不行,去你的废纸篓里面找被你删除的项目名.entitlements文件,重新拖到项目中重启项目即可

Build Settings
如果你的工程需要支持小于7.0的iOS系统,请到Build Settings 关闭 bitCode 选项,否则将无法正常编译通过。
设置 Search Paths 下的 User Header Search Paths 和 Library Search Paths,比如SDK文件夹(默认为lib)与工程文件在同一级目录下,则都设置为"$(SRCROOT)/{静态库所在文件夹名称}"即可 。《来自极光文档》

2.允许Xcode7支持Http传输方法

如果您使用的是2.1.9及以上的版本则不需要配置此步骤
如果用的是Xcode7或更新版本,需要在App项目的plist手动配置下key和值以支持http传输:
选择1:根据域名配置
在项目的info.plist中添加一个Key:NSAppTransportSecurity,类型为字典类型。
然后给它添加一个NSExceptionDomains,类型为字典类型;
把需要的支持的域添加給NSExceptionDomains。其中jpush.cn作为Key,类型为字典类型。
每个域下面需要设置2个属性:NSIncludesSubdomains、NSExceptionAllowsInsecureHTTPLoads。 两个属性均为Boolean类型,值分别为YES、YES。《来自极光文档》 。如图

Snip20161024_10.png

配置完以上之后,进入项目的appdelegate里面,首先导入头文件和遵循代理

#import "AppDelegate.h"
#import "JPUSHService.h"
#ifdef NSFoundationVersionNumber_iOS_9_x_Max
#import <UserNotifications/UserNotifications.h>
#endif

@interface AppDelegate ()<JPUSHRegisterDelegate>

在系统方法里面申请通知权限,这里最高只适用到xcode8.1(iOS10.1.2),以后如果出现iOS11在做更新改变

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
   if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
        JPUSHRegisterEntity * entity = [[JPUSHRegisterEntity alloc] init];
        entity.types = UNAuthorizationOptionAlert|UNAuthorizationOptionBadge|UNAuthorizationOptionSound;
        [JPUSHService registerForRemoteNotificationConfig:entity delegate:self];
    }
    else if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
        //可以添加自定义categories
        [JPUSHService registerForRemoteNotificationTypes:(UIUserNotificationTypeBadge |
                                                          UIUserNotificationTypeSound |
                                                          UIUserNotificationTypeAlert)
                                              categories:nil];
    }
    else {
        //categories 必须为nil
        [JPUSHService registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge |
                                                          UIRemoteNotificationTypeSound |
                                                          UIRemoteNotificationTypeAlert)
                                              categories:nil];
    }
[JPUSHService setupWithOption:launchOptions appKey:appKey
                          channel:channel
                 apsForProduction:isProduction
            advertisingIdentifier:nil];  // 这里是没有advertisingIdentifier的情况,有的话,大家在自行添加
    //注册远端消息通知获取device token
    [application registerForRemoteNotifications];
}

注意:appkey一定不要忘了从极光复制过来

获取deviceToken

// 获取deviceToken
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    [JPUSHService registerDeviceToken:deviceToken];
}
// 注意 :此方法在ios 3 以后可以使用,但是在很多朋友可能会遇到不调用此方法的情况,也就无法获取deviceToke,这里提供一种解决方案
-(void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
    [application registerForRemoteNotifications];
}    
关于这个deviceToken,iOS10系统上,每次卸载重装将产生新的app,如果没有卸载重装,每次请求获得的device token是不变的。
另外官网也对device token的变化进行了说明:

To protect user privacy, do not use device tokens to identify user devices. Device tokens change when the user updates the operating system and when a device’s data and settings are erased. As a result, apps should always request the current device token at launch time.

// ios 10 support 处于前台时接收到通知

// ios 10 support 处于前台时接收到通知
- (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); 
// 处于前台时,添加需求,一般是弹出alert跟用户进行交互,这时候completionHandler(UNNotificationPresentationOptionAlert)这句话就可以注释掉了,这句话是系统的alert,显示在app的顶部,
}
    */ 如果处于前台时需要自定义弹框或者弹出alert,可以看一下http://www.jianshu.com/p/d2a42072fad9 这篇文章

// iOS 10 Support 点击处理事件

// iOS 10 Support  点击处理事件
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
    // Required
    
    NSDictionary * userInfo = response.notification.request.content.userInfo;
    if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        [JPUSHService handleRemoteNotification:userInfo];
        //推送打开
        if (userInfo)
        {
            // 取得 APNs 标准信息内容
//            NSDictionary *aps = [userInfo valueForKey:@"aps"];
//            NSString *content = [aps valueForKey:@"alert"]; //推送显示的内容
//            NSInteger badge = [[aps valueForKey:@"badge"] integerValue]; //badge数量
//            NSString *sound = [aps valueForKey:@"sound"]; //播放的声音
            
           // 添加各种需求。。。。。
        
        [JPUSHService handleRemoteNotification:userInfo];
        completionHandler(UIBackgroundFetchResultNewData);
    }
    completionHandler();  // 系统要求执行这个方法
}

// iOS7 及以上接收到通知

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    
    // Required, iOS 7 Support
    [JPUSHService handleRemoteNotification:userInfo];
    completionHandler(UIBackgroundFetchResultNewData);
}

这里在iOS7及以上系统的方法中,如果需要在前台和后台做不同的处理的时候,需要判断一下app 的状态,判断方式如下

 if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
        
        // 处于前台时 ,添加各种需求代码。。。。

    }else if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground)
    {
        // app 处于后台 ,添加各种需求
    }

那么问题来了,前台后台收到推送的方法都有了,还有一种情况。。。。。程序完全退出的时候,这种情况下,点击通知会走下面这个方法(即注册通知时的方法,程序的入口)

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
}

在这个方法里,我们需要判断一下程序是否处于完全退出状态,判断方法如下

 NSDictionary *remoteNotification = [launchOptions objectForKey: UIApplicationLaunchOptionsRemoteNotificationKey];
   
    if (remoteNotification)
    {

   // 程序完全退出时,点击通知,添加需求。。。

  }
# 需要注意的地方:
有可能有些小伙伴在集成过程中用ios10的手机测试的时候,
在推送通知的时候ios10和ios7的两个代理方法都走了,具体原因具体对待,如果实在找
不到问题所在,这里提供两个方法,one:在ios10的两个代理方法的首尾加入以下语句
#ifdef NSFoundationVersionNumber_iOS_9_x_Max 
#endif      // ios10中加入这两句话
在ios7的代理方法首尾加入以下语句
#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_7_1  
#endif   // ios7中加入这两句话
第二种方法是直接在ios7的代理方法中加入判断:
if ([[UIDevice currentDevice].systemVersion floatValue] < 10.0)

// 基于iOS 6 及以下的系统版本 接收到通知

// 基于iOS 6 及以下的系统版本,如果 App状态为正在前台或者点击通知栏的通知消息,那么此函数将被调用,并且可通过AppDelegate的applicationState是否为UIApplicationStateActive判断程序是否在前台运行。此种情况在此函数中处理:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    // Required,For systems with less than or equal to iOS6
    
    // iOS 10 以下 Required
     [JPUSHService handleRemoteNotification:userInfo];
}

//最后清除角标

- (void)applicationDidEnterBackground:(UIApplication *)application {
    [[UIApplication alloc] setApplicationIconBadgeNumber:0];
}

// 点击之后badge清零
- (void)applicationWillEnterForeground:(UIApplication *)application {
    
    [application setApplicationIconBadgeNumber:0];
    [[UNUserNotificationCenter alloc] removeAllPendingNotificationRequests];
}

其他功能:

1 . 后台传入不同的值,点击通知进入不同的界面,可以在极光的官网发送通知界面,展开可选设置,使用附加字段,这里我加了一个键值对key和值可以自行设置,然后在工程中需要进行判断,

设置附加字段

代码如下:大家可以在点击通知会走的方法中调用此方法

// 传入字段,根据字段改变需求
- (void)ExtrasOfNotificationWithUserInfo:(NSDictionary *)userInfo
{
    if (userInfo)
    {
        // 取得 APNs 标准信息内容
//        NSDictionary *aps = [userInfo valueForKey:@"aps"];
//        NSString *content = [aps valueForKey:@"alert"]; //推送显示的内容
//        NSInteger badge = [[aps valueForKey:@"badge"] integerValue]; //badge数量
//        NSString *sound = [aps valueForKey:@"sound"]; //播放的声音
        // 取得Extras字段内容
        NSString *customizeField1 = [userInfo valueForKey:@"key"]; //服务端中Extras字段,key是自己定义的,需要与极光的附加字段一致
        // 若传入字段的值为1,进入相应的页面
        if ([customizeField1 integerValue] == 1){
            //是推送打开
            UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
            MainTabbarVC *rootTabBarC = [sb instantiateViewControllerWithIdentifier:@"MainTabbarVC"];
            [UIApplication sharedApplication].delegate.window.rootViewController = rootTabBarC;
// 下面的方法是自己封装的
            [rootTabBarC enterToElectronicInvoice];
        }
    }
    
}
 注意:这里的跳转方法可能不适用所有项目,大家可以看一下下面的链接,或许能够找到适合你工程的跳转方法

1.2 极光的点击通知的方法- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler 是对系统方法的封装,他的userInfo中含有自定义添加的key,但是其他三方库例如AWS的推送机制中就不包含自定义添加的key,这时候只能通过aps中的默认userInfo传递特定的值,aps的结构如下

iOS 10 之前
{  
   "aps":{  
      "alert":"内容",
      "badge":1,
      "sound":"default",
      "userinfo":{"username":"tom"}
   }
}


iOS 10及之后(iOS7、iOS8、iOS9可通用此模板)
{  
   "aps":{  
      "alert":{  
         "title":"标题", // 
         "subtitle":"子标题", // 一般使用title就能满足需求
         "body":"内容"
      },
      "badge":1, //角标数
      "sound":"default", //声音
      "userinfo":{ //通知内容信息
           "playid":"123",
           "username":"tom",
           "sex":1
      }
   }
}

如果只传递一串字符串或者不是按照上述格式发送通知消息,那么会默认把你传递的字符串全部转化成alert的内容,全部弹出来,所以在aws中我们可以这样定义

APNS_SANDBOX : "{"aps":{"alert":" title message", "userInfo":"username"}}"

这样在app中收到的弹出消息仅仅为title message ,而userInfo可以用来做其他的用处

2 . 指定用户发送远程通知,这里指定用户不能只根据DeviceToken来进行发送,在极光的官网也没有可以使用DeviceToken发送的选项,如下图

极光发送消息针对的人群

这里的Registration ID 并不是DeviceToken,话不多说,下面我们介绍一种使用别名Alias的方法,我们知道指定用户发送,无非是已经注册了本公司账号的人群,你想给不同的人推不同的消息,那么我们指定用户的时候,实际上是根据用户在我们公司注册的账号进行发送特定消息,例如用户的账单状态等等,所以我们可以在用户登陆账号之后,给用户分配一个id用做唯一标示,绑定极光的别名或者tag,当然这里绑定别名还是tag可以和后台商量一下,用什么其实都是可以的,代码如下

[JPUSHService setTags:nil alias:USER_INFO.userID fetchCompletionHandle:^(int iResCode, NSSet *iTags, NSString *iAlias) {
                NSLog(@"设置结果:%i 用户别名:%@",iResCode,USER_INFO.userID);
            }];
// 这是极光提供的方法,USER_INFO.userID是用户的id,你可以根据账号或者其他来设置,只要保证唯一便可


// 不要忘了在登出之后将别名置空
[JPUSHService setTags:nil alias:@"" fetchCompletionHandle:^(int iResCode, NSSet *iTags, NSString *iAlias) {
        NSLog(@"设置结果:%i 用户别名:%@",iResCode,USER_INFO.userID);
    }];

绑定完别名之后,指定用户发送消息的任务就可以交给后台了。如果你想自己测试一下,那就打印一下USER_INFO.userID ,然后自己用极光给自己推送,如图

根据自己的Alias给自己推送消息

有些朋友问我为啥收到通知有些方法就是不调用,这里要细心一点,有些方法是需要点击alert才会走,如果发送通知没有走进你想调试的方法里注意一下,是不是需要点击一下alert

至此,ios极光推送的集成就简单说到这里,未完。。。待续。。。觉得好的,就点个赞,有问题的可以私信我,或者加我qq:1162719523,同不同意那就不知道了

ios 收到远程通知,弹出提示框,点击确定跳转到消息界面:http://www.jianshu.com/p/d2a42072fad9

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容