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

作者: fulen | 来源:发表于2016-10-24 13:39 被阅读12108次
    好凉一个秋

    好久没有发动态了,今天介绍一下极光推送,关于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 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];
            }
        }
        
    }
    
     注意:这里的跳转方法可能不适用所有项目,大家可以看一下下面的链接,或许能够找到适合你工程的跳转方法
    

    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给自己推送消息

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

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

    相关文章

      网友评论

      • writeSpace:为什么在极光后台根据设备别名推送收不到消息?你们都交钱了吗?还是用的免费的
        fulen:@lessfish 免费
      • coderxjl:大神,我做的极光推送,杀死APP后,点击收到的离线推送崩溃,在线推送没有问题,求指导
        fulen:你点击推送做了什么事,加个断点看看
        fulen:这个要看代码
      • Mister_H:您好,关于推送的文本如何支持国际化么? 我想的是在文本中就同时包含多国语言,然后收到后再根据当前语言取,但是在哪处理这个过程呢?楼主知道么?
        fulen:@Mister_H 之前项目木有做国际化,具体怎么方便没有搞过,:joy:
      • 热血足球2016:tag怎么推送涉及到交集,极光后台应该怎么填
      • Zszen:ExtrasOfNotificationWithUserInfo 绑定的哪个事件没有说
        fulen:用来点击跳转到对应的页面,[rootTabBarC enterToElectronicInvoice]这个方法是跳转的页面对应的方法
        fulen:哦哦,这个只是一个自定义的方法
        // 传入字段,根据字段改变需求
        - (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];
        }
        }

        }
      • pinglife:那个角标和自定义声音怎么弄啊?
        pinglife:@fulen 哈哈哈!已经解决了,感觉好久之前的问题了
        fulen:不好意思,最近比较忙,一直没登录账号,角标极光的文档有说到,声音自定义我之前也没做,不过极光文档应该有
      • 24c8ed9123cf:刚开始做 ios,这个看的一知半解,我可以加你 QQ 向你请教么?
        1、极光推送跳转
        (1).社区活动的推送分为两种:type:0:跳到我的活动 type:1 跳到活动列表
        (2).极光接收自定义消息,收到消息提示账号在另外设备登录或者账号被锁定,变为非登录状态并显示登录界面
        要做这两个功能,但是我完全不知道如何下手
        fulen: 1.NSString *customizeField1 = [userInfo valueForKey:@"key"]; 根据这个key也就是你说的type判断并进行跳转
        2.互踢的这个需求应该也是需要判断type的,然后alert一个弹框,提示账号在异地登录(这个提示建议代码写死),点击确定调用退出登录的方法同时present出登录界面,个人认为应该这么做,也许还有更好的办法
      • assassinate:不走 代理 方法 啊
        fulen:在代理方法里面alert一下,别用打印
      • assassinate:不走代理方法 啊 JIGUANG | W - [JIGUANGClientController] Not get deviceToken yet. Maybe: your certificate not configured APNs? or current network is not so good so APNs registration failed? or there is no APNs register code? Please refer to JPush docs.
      • 7c91ae2f8077:楼主,我集成可以接收到通知,但是没有弹出系统询问窗口啊,遇到过这种情况吗?
        fulen:@ai张小张 你手机是不是设置了,你进设置里面看看
      • 雷仔:楼主您好, 我集成了极光以后, 为什么项目进不去 黑屏了呢 , 但是欢迎页可以进
        fulen:@雷仔 没发现这种情况过,你确定是集成极光推送导致的黑屏吗,你可以把极光推送的代码注释掉,逐个排查原因
      • e57593639e22:楼主,请问 我用的的代码极光的demo上的代码粘下来的 但是我就是接收不到通知 注册是成功了的 我发推送的时候用的是所有人
        fulen:@很着急 appkey有没有导入呢
        fulen:@很着急 appkey呢,加到项目了吗
      • 世界辣么大233:楼主 为什么我app在后台 ,收到通知时不会进- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {}方法
        fulen:@世界辣么大233 忘了说了// Required, iOS 7 Support
        世界辣么大233:@fulen 没有 不知道为什么在后台收到通知会不进任何方法
        fulen:刚看到你的消息,问题解决了吗
      • a90a147abe6d:如果用户把推送权限关闭了,还能用jpush进行服务器消息交互吗?
        fulen:@摩西摩西和辛 能交互,但是关闭了推送权限之后,用户收不到消息
      • 扣肉快快跑:写的很详细, 虽然极光有版本又改了一个,不过用上了,谢谢分享
        fulen:@扣肉快快跑 :grin: 不客气
      • 成长路上多迷惑:楼主,我用的xcode7。 没有最新的notifications包 是不是就不能在项目里部署iOS10的通知了?
        fulen:@成长路上多迷惑 你看看xcode里有- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0);

        // The method will be called on the delegate when the user responded to the notification by opening the application, dismissing the notification or choosing a UNNotificationAction. The delegate must be set before the application returns from applicationDidFinishLaunching:.
        - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler __IOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0) __TVOS_PROHIBITED;
        这两个方法吗,极光的那两个ios 10专用的方法,是对系统的方法的封装
        成长路上多迷惑:@fulen 最新版本的, 低版本的Xcode 是配不了10以上系统。 它们接收通知的方法不一样
        fulen:@成长路上多迷惑 你用的极光sdk是几点几的
      • 12bfadcbeb60:请问楼主有推送消息时,点击app的icon如何获取到推送内容
        fulen:@LEE木子李 从后台获取,不然没办法
      • 程序媛vivid:请问楼主,如果info里面不配置NSExceptionDomains等会如何呢?我们没配置也可以收到推送。会不会被拒什么的。
        程序媛vivid:@fulen 好的,谢谢
        fulen:@依拉 如果你用的是极光2.1.9及以上的版本则不需要配置NSExceptionDomains等
      • zcaaron:我也是用极光推送集成的,也能接受到消息,但是点击推送的消息没有调用相关的代理方法?求解!!!
        zcaaron:@fulen 多谢多谢!
        fulen:@zcaaron 之前的代码我少复制了一句话
        fulen:@zcaaron 你是复制的我的代码吗,如果是的话少了一句话,在- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        方法里少了一句话[JPUSHService setupWithOption:launchOptions appKey:appKey
        channel:channel
        apsForProduction:isProduction
        advertisingIdentifier:nil];
      • Dely:不错
        fulen:@Dely 不行不行

      本文标题:ios 极光推送的集成及注意事项

      本文链接:https://www.haomeiwen.com/subject/twcluttx.html