推送后传

带我飞.jpg

前言:推送功能为了提醒用户或者提高应用留活率。关于推送有很多第三方,比如极光,融云,信鸽,其原理也是相同利用APNS推送机制 。今天写这篇文章的主要目的是为了推送,但是关于推送的文章、博客很多,所以重点还是讲推送后续-------推送后的页面跳转功能。

主要以极光推送为例
准备条件:极光账号、苹果开发账号、一部手机、一个xcode
虽然使用的第三方推送我们也要明白其原理啦
苹果APNS推送原理:


苹果APNS推送原理.jpg

Provider就是我们自己程序的后台服务器,APNS是Apple Push Notification Service的缩写,也就是苹果的推送服务器。
上图可以分为三个阶段:
第一阶段:应用程序的服务器端把要发送的消息、目的iPhone的标识打包,发给APNS。
第二阶段:APNS在自身的已注册Push服务的iPhone列表中,查找有相应标识的iPhone,并把消息发送到iPhone。
第三阶段:iPhone把发来的消息传递给相应的应用程序,并且按照设定弹出Push通知。

而使用极光,极光代替了应用的服务器,极光推送原理
jpush_ios.png

从上图可以看出,JPush iOS Push 包括 2 个部分,APNs 推送(代理),与 JPush 应用内消息。红色部分是 APNs 推送,JPush 代理开发者的应用(需要基于开发者提供的应用证书),向苹果 APNs 服务器推送。由 APNs Server 推送到 iOS 设备上。蓝色部分是 JPush 应用内推送部分,即 App 启动时,内嵌的 JPush SDK 会开启长连接到 JPush Server,从而 JPush Server 可以推送消息到 App 里。

第一步:申请一个极光账号;https://www.jiguang.cn/
第二步:创建推送证书:https://docs.jiguang.cn/jpush/client/iOS/ios_cer_guide/
第三步:在极光推送后台创建一个应用,并将自己创建的推送证书放上去。
第四步:导入极光推送的SDK并配置环境https://docs.jiguang.cn/jpush/client/iOS/ios_guide_new/
如果后期发现自己收不到推送消息,检查2、3、4步是否证书有效、证书的bundleid是否与程序配置一样、是否开启Application Target的Capabilities->Push Notifications选项、是否支持Http传输方法

<key>NSAppTransportSecurity</key>
  <dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
  </dict>

第五步:代码时刻
1.在 AppDelegate.m 引用头文件

// 引入JPush功能所需头文件
#import "JPUSHService.h"
// iOS10注册APNs所需头文件
#ifdef NSFoundationVersionNumber_iOS_9_x_Max
#import <UserNotifications/UserNotifications.h>
#endif

2.添加Delegate

@interface AppDelegate ()<JPUSHRegisterDelegate>

@end

3.添加初始化APNs代码、JPush代码

 -(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
//初始化APNs代码
 JPUSHRegisterEntity * entity = [[JPUSHRegisterEntity alloc] init];
  entity.types = JPAuthorizationOptionAlert|JPAuthorizationOptionBadge|JPAuthorizationOptionSound;
  if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
    // 可以添加自定义categories
    // NSSet<UNNotificationCategory *> *categories for iOS10 or later
    // NSSet<UIUserNotificationCategory *> *categories for iOS8 and iOS9
  }
  [JPUSHService registerForRemoteNotificationConfig:entity delegate:self];
//JPush代码
// 如需继续使用pushConfig.plist文件声明appKey等配置内容,请依旧使用[JPUSHService setupWithOption:launchOptions]方式初始化。

  [JPUSHService setupWithOption:launchOptions appKey:appKey
                        channel:channel
               apsForProduction:isProduction
          advertisingIdentifier:advertisingId];
//初始化控制器代码
//...
   return;
}
  • appKey
    • 选择 Web Portal上 的应用 ,点击“设置” 获取其 appkey 值。请确保应用内配置的 appkey 与 Portal 上创建应用后生成的 appkey 一致。
  • channel
    • 指明应用程序包的下载渠道,为方便分渠道统计,具体值由你自行定义,如:App Store。
  • apsForProduction
    • 1.3.1版本新增,用于标识当前应用所使用的APNs证书环境。
    • 0 (默认值)表示采用的是开发证书,1 表示采用生产证书发布应用。
    • 注:此字段的值要与Build Settings的Code Signing配置的证书环境一致。
  • advertisingIdentifier

4.请在AppDelegate.m实现该回调方法并添加回调方法中的代码

//注册APNs成功并上报DeviceToken
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {

  /// Required - 注册 DeviceToken
  [JPUSHService registerDeviceToken:deviceToken];
}
//实现注册APNs失败接口
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
  //Optional
  NSLog(@"did Fail To Register For Remote Notifications With Error: %@", error);
}

#pragma mark- JPUSHRegisterDelegate

// iOS 10 Support
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger))completionHandler {
  // Required
  NSDictionary * userInfo = notification.request.content.userInfo;
  if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
    [JPUSHService handleRemoteNotification:userInfo];
  }
  completionHandler(UNNotificationPresentationOptionAlert); // 需要执行这个方法,选择是否提醒用户,有Badge、Sound、Alert三种类型可以选择设置
}

// 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];
  }
  completionHandler();  // 系统要求执行这个方法
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {

  // Required, iOS 7 Support
  [JPUSHService handleRemoteNotification:userInfo];
  completionHandler(UIBackgroundFetchResultNewData);
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {

  // Required,For systems with less than or equal to iOS6
  [JPUSHService handleRemoteNotification:userInfo];
}
//清除角标
- (void)applicationWillEnterForeground:(UIApplication *)application {
   [application setApplicationIconBadgeNumber:0];
    //设置服务器角标为0
    [JPUSHService setBadge:0];
    
}

5.根据不同参数进行页面跳转。关于这个跳转有很多方法,自己也尝试过很多种,以前通常在AppDelegate跳转,但推送页面返回时候效果不够好,所以我现在基本上在AppDelegate接受推送消息后以通知方式传给TabBarViewController,TabBarViewController(如果页面中没有用到TabBarViewController,也可以使用其他ViewController作为过度跳转)监听到通知后进行页面跳转和交互。
例如:一个APP有启动页面、有推送、有登录操作


应用流程图.png

主要代码片段
AppDelegate.m内收到推送消息时发送出通知

//用户点击了通知进入app
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler NS_AVAILABLE_IOS(10.0){
    NSDictionary * userInfo = response.notification.request.content.userInfo;

    if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        [JPUSHService handleRemoteNotification:userInfo];
        [[NSNotificationCenter defaultCenter] postNotificationName:@"PresentView" object:self userInfo:userInfo];
        
    } else {
        // 判断为本地通知
    }
}

//基于iOS 7 及以上的系统版本,如果是使用 iOS 7 的 Remote Notification 特性那么处理函数需要使用
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    
    // Required, iOS 7 Support
    [JPUSHService handleRemoteNotification:userInfo];
    completionHandler(UIBackgroundFetchResultNewData);
    if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive) {
        //应用不属于前台
        [[NSNotificationCenter defaultCenter] postNotificationName:@"PresentView" object:self userInfo:userInfo];
    }else{
        //应用属于前台
    }
    
}

BaseTabBarViewController.h内监听通知

- (void)viewDidLoad {
    [super viewDidLoad];
    [self addChildViewControllerWithClassname:[HomeViewController description] imagename:@"home_noselect" selectedimagename:@"home_select" title:@"主页"];
    [self addChildViewControllerWithClassname:[NewViewController description] imagename:@"new_noselect" selectedimagename:@"new_select"title:@"资讯"];
    [self addChildViewControllerWithClassname:[MeViewController description] imagename:@"me_noselect" selectedimagename:@"me_select" title:@"我的"];
    //消息推送通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(presentView:) name:@"PresentView" object:nil];
}
- (void)presentView:(NSNotification *)notification{
    NSLog(@"推送--------------%@", notification.userInfo);
    if ([notification.userInfo[@"push_id"] isEqualToString:@"1"]) {
        PushDetailOneViewController *oneVC = [[PushDetailOneViewController alloc] init];
        oneVC.idStr = notification.userInfo[@"push_id"];
        UINavigationController *nav = self.viewControllers[self.selectedIndex];
        [nav pushViewController:oneVC animated:YES];
        
    }else if ([notification.userInfo[@"push_id"] isEqualToString:@"2"]){
        PushDetailTwoViewController *twoVC = [[PushDetailTwoViewController alloc] init];
        twoVC.idStr = notification.userInfo[@"push_id"];
        UINavigationController *nav = self.viewControllers[self.selectedIndex];
        [nav pushViewController:twoVC animated:YES];
    }else if ([notification.userInfo[@"push_id"] isEqualToString:@"3"]){
        PushDetailThressViewController *thressVC = [[PushDetailThressViewController alloc] init];
        thressVC.idStr = notification.userInfo[@"push_id"];
        UINavigationController *nav = self.viewControllers[self.selectedIndex];
        [nav pushViewController:thressVC animated:YES];
    }
}

demo:https://github.com/guofeifeifei/jpush
推送原理参考文章:https://blog.csdn.net/yuxiang19876021/article/details/52217187

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

推荐阅读更多精彩内容