iOS推送消息启动页面,URL启动App并跳转页面设计

来源:互联网 发布:网络唤醒有什么用 编辑:程序博客网 时间:2024/06/16 18:43

需求描述:

App里经常使用推送消息通知用户,如果不做任何操作,只给将App启动起来,这样没有任何效果,最佳实践是启动起来App后,自动拉起指定的页面,最好再有参数传递,通过参数来将数据加载到该页面上。

使用场景:

1. App推送订单消息后,点击消息,启动App,跳转到订单详情页

2. App推送聊天信息,点击消息后,启动App,跳转到聊天页面

3. 分享出去的页面里带有链接,点击该链接后,启动App,跳转到目标页面。


设计原理:

1. App启动数据传递

iOS里方法application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 里的launchOptions表示是的App启动时传递的数据。如果App后台已经死掉,推送消息过来后,会先拉起App,推送消息里的数据会通过launchOptions传递过来。

2. 后台App接收推送后数据传递

iOS AppDelegate里的application didReceiveRemoteNotification:(NSDictionary *)userInfo方法表示App在后台运行时,如果有推送,点击推送消息拉起App后通过userInfo传递数据。

3. NSURL启动App传递数据

AppDeletage中的application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation方法表示,当系统里打开某URL后,系统查询该URL是否有App注册,如果发现有App注册该URL的Scheme,则拉起该App,并将url传递过去。


# 通过上述三个delegate可以实现前面的需求场景。



实现:

通过上述三种方法可以将推送数据或URL数据拿到,但是拿到后我们需要跳转到指定页面。
假如我们将要做的跳转操作称为Action,我们定义Aciton的格式如下:
action:
   wenxiaoyou://ACTION_NAME?param1=value1&param2=value2

上述wenxiaoyou表示该操作的scheme用来区分其它的App注册的模式,一定要保证该scheme和别的App不一样,否则会拉错App。推荐使用App的包名。
ACTION_NAME:表示你做的操作,一般我们打开App有很多操作,比如我们的App做留学一对一名校导师咨询的,有打开订单,导师首页,导师服务首页,导师评论页===
param1=value1:表示要传递的参数,如果是订单,可以使用类似:wenxiaoyou://order_detail?order_id=1234,表示要打开订单详情页,该页面显示的是订单号为1234的内容。

如果将App的scheme注册到系统中呢?
打开Info.plist里添加scheme注册项:
URL types
   > URL Schemes
      > Document Role : Editor
      > URL identifier : com.wenxiaoyou.com
      > URL Schemes:    wenxiaoyou

通过上面的操作即可添加scheme项。


// 实现App启动数据传递处理

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

...

#pragma mark- 处理启动时的推送通知

    NSDictionary* pushInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];

    if(pushInfo){//推送信息

        [self parsePushNotifaction:pushInfo];

    }

...

}


// 后台推送数据传递处理

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

{

    NSLog(@"后台推送消息");

    [self parsePushNotifaction:userInfo];

}


// Web跳转处理一并处理

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString*)sourceApplication annotation:(id)annotation{

        NSString* action = [NSString stringWithFormat:@"%@://%@?%@", url.sheme, url.host, url.query];

        NSMutableDictionary* dic = [[NSMutableDictionary alloc]init];

        [dic setObject:action forKey:KEY_ACTION];

        // 保存起来要执行的任务

        SAVE_TO_USER_DEFAULT(dic, KEY_BOOT_TASK);

        [[NSNotificationCenter defaultCenterpostNotificationName:PUSH_MSG_BOOT_TASK_NOTIFICATION object:niluserInfo:dic];

}


// 推送消息处理

-(void)parsePushNotifaction:(NSDictionary *)pushInfo

{

    SAVE_TO_USER_DEFAULT(pushInfo, KEY_BOOT_TASK);

    [[NSNotificationCenter defaultCenterpostNotificationName:PUSH_MSG_BOOT_TASK_NOTIFICATION object:niluserInfo:pushInfo];


}


# SAVE_TO_USER_DEFAULT表示将推送内容及Web跳转信息保存到沙盒里。为什么要这么做???

因为App收到推送时无非两种情况下:1. App未启动 2. App已经启动

如果App未启动,当收到推送并点击推送信息时,会打开App,通过didFinishLaunchingWithOptions方法获得到推送内容。但是我们无法执行页面的跳转,因为在AppDelegate里还没有启动我们的“首页”,如果你直接打开目标页面也不是不可,但是目标页面如果点击返回,如何处理?所以,个人认为最好的方式就是先打开App的首页,然后再通过首页再push到目标页面,这样用户点击返回时,也会返回App首页。Ok,既然我们需要打开App首页,那我们推送里的跳转操作Action就需要暂时suspend起来,然后等App首页启动起来之后,再将suspend的Action启动起来。所以我们要将Action保存到沙盒里,等待首页启动起来之后,再执行suspend的Action。


#为什么要使用通知Notification??

因为parsePushNotifaction被调用了两次,一次是在App启动时,另外一次是在App已经启动时,当到Push消息后,我们可以直接实现跳转。为什么不直接在parsePushNotifaction里执行跳转呢??因为VC的启动与跳转都需要基于一个NaviController,而我们在AppDelegate里无法确定当前是哪个NaviController,虽然我们可以保存当前的NaviController。但是我还是希望使用下面这种方式,大家可以基于此展开讨论。


我们的项目里所有VC都继承自BaseViewController,这个基类在init的时候,我们注册了PUSH_MSG_BOOT_TASK_NOTIFICATION通知的接收。

这样,当前App里所有的页面都可以接收到要跳转Action的通知,但是,我们设定了,只有当前正在显示的VC才执行跳转,其它压栈的VC不执行跳转。

伪代码如下:


BaseViewController{

 init(){

    // 注册PUSH_MSG_BOOT_TASK_NOTIFICATION通知onBootActionNotify()

 }



 void onBootActionNotify(Notify* notifyInfo){

     // 如果当前VC不是最前端显示的VC,直接返回

     if(!self.isVisiable){

        return ;

     }

     

     // 如果Action已经被消费处理,则删除KEY_BOOT_TASK

     REMOVE_USER_DEFAULT(KEY_BOOT_TASK);


     // 如果当前App在后台运行,则将跳转操作放到Block里,等待App重新回到前台后自动执行该Block

     if(App.isInBackground){

       App.backBootBLock = {

           // 解析notifyInfo,并执行跳转

       };

     }else{

           // 解析notifyInfo,并执行跳转       

     }

 }

}


# 为了实现上述的后台重新唤醒后,自动执行跳转,需要在AppDelegate里添加Delegate

-(void)applicationDidBecomeActive:(UIApplication *)application

{

    APP.isInBackground = NO;

    if(App.backBootBlock){

       App.backBootBlock();

    }

}


-(void)applicationDidEnterBackground:(UIApplication *)application

{

    APP.isInBackground = YES;

}


# OK,上述代码写完,好像没有问题了,仔细看下,好像首页启动后suspendAction的处理还没有添加。

伪代码如下:

HomeViewController{

  init(){

    // 如果因为推送或openURL启动了App,会有挂起的Action处理,这个时候可以处理它了。

    NSDictionary* notifyInfo = GET_OBJ_FROM_USER_DEFAULT(KEY_BOOT_TASK);

    if(notifyInfo != nil){

        [[NSNotificationCenter defaultCenterpostNotificationName:PUSH_MSG_BOOT_TASK_NOTIFICATION object:niluserInfo:notifyInfo];

    }

  }

}



以上



1 1
原创粉丝点击