河狸家APP如何满足产品的任意页面跳转需求(runtime)

一 跳转native页面需求入口来源分析

跳转native页面的源头分五类:

1.第三方app唤起跳转,包含短信;这类多用于第三方市场商务合作以及运营活动;

2.推送消息指令跳转;这类可帮助运营提高老用户活跃,提高转化;

3.服务器下发指令跳转;(长链接场景服务端主动推消息)

4.App native内部跳转;iOS自身技术设计需要;

5.native与h5的交互跳转;在电商app中,十分广泛,可帮助产品更快试错,更快速的迭代更新;

分析了来源和意义,我们来看看电商app实现任意入口的任意跳转到底有什么好处呢?

二 电商app实现任意跳转app页面的好处

1.从产品上:服务端即可灵活的控制app,满足产品天马行空的跳转想象,更灵活的满足产品需求;

2.从运营支持上:我们要明白任何没有着落页的短信及推送消息,都是耍流氓,否则对点击了消息而没有看到着落的用户就是一种伤害;而它能解决点击每个活动消息都可以自定义着落页面;

3.从技术上:当两位领导意见分歧,一个要跳a页面,一个要跳转到b页面,此时则可搞a/b test,再结合BI数据分析,分析转化;最终帮助公司沉淀最优方案,提高转化,最终实现理想IPO上市;这就是技术的力量(哈哈平和领导的关系,维护了公司的团结稳定#共勉#)

估计大部分技术都没有意识到自己还有这种力量,以上对话勿让领导听到#奸笑#

这样看起来无论哪个入口要跳转哪个页面,技术上去做好它都变得十分有意义!

三 河狸家app早期协议

(因安全原因,由于苹果可通过class-dump命令,反编译处理,若直接暴露类名/方法/对象会引来安全问题,故以下代码的方法和类名都经过处理,命名也不规范,请谅解,注意思路)

背景:

设计理念,如同http://访问一样,只需要一个知道Url抛给底层服务,即可访问想要到达的页面,而上层工程师不需要关注中间如何访问及如何跳转;

由此,河狸家app定义了一个openUrl,来控制所有的页面跳转访问;

下面来看openUrl结构:

首先要建立协议:

1.协议头定义:考虑到第三方app唤起的原因,我们将协议头定义为URL Schemes(如微信的weixin://),这里考虑到安全问题,则隐藏河狸家app URL Schemes;用“HLJ://”代替

~urlString 形如 @"HLJ://page?jsonData={json}";

~1、区分事件类型 如"page"

~2、获取json

json对象结构形如

{

     "hljType” : enum, //跳转页面标示   建立一个页面映射表来对应enum

    “hljPageN” : “作品详情”,//页面名称

    “jData” : {

            “proId” : “sldkjf3l2”

      }

}

json对应的model对象ScEntity如图:

河狸家APP如何满足产品的任意页面跳转需求(runtime)_第1张图片

制定完协议结构,下面来看看过程核心代码结构:

核心管理类ScManager,负责接收openUrl协议,校验协议,解析json,定向跳转;

工程师在开发过程只需要注意在openurl中填写跳转目的页面,以及model丢出数据即可,其他则不用关注;

第一步

首先校验跳转协议,必须要遵循HLJ://才可进入跳转逻辑,否则认为非法;

再解析jsondata,并解码son串;

河狸家APP如何满足产品的任意页面跳转需求(runtime)_第2张图片

第二步

将json解析成字典,利用MJ将数据转成SceneBaseEntity对象

河狸家APP如何满足产品的任意页面跳转需求(runtime)_第3张图片

第三步,通过枚举映射表对应跳转类,并拼接model

河狸家APP如何满足产品的任意页面跳转需求(runtime)_第4张图片
再利用

再通过

TabBarController *rootNav = (TabBarController *) kWindow.rootViewController;

[[rootNav.viewControllers objectAtIndex:rootNav.selectedIndex] pushViewController:controller animated:YES];

实现了跳转;

优点:

1.直观;

2.工程师编码只关注目的,和对应的唯一model。

缺点:

1.它还是不够灵活,每个页面都需要在枚举表中对应上映射,无法做到不发版本即可跳转无映射的页面;

2.当项目逐渐扩大,页面无穷多个时,产品的野心也在膨胀后,要写一堆的switch判断;

那还是不完全满足啊~~~~

别急!!!!来看第四段~~~~~

四  如何设计一套协议另app能够自由任意的跳转呢?

核心:runtime运行时机制+组件化

(这里插个题外话,无论老人代码写的怎么样,都是带动的创业公司走过风雨,尊重与感谢,勿吐槽多敬重!!!)

注意:由于旧工程需要兼容,还考虑这套设计中的openurl协议涉及安卓/iOS /前端/后端,考虑团队,则需要一个过渡方案。于是只能在旧工程上switch case,并且为了兼容旧版本,最新的运行时动态跳转设计中添加了一个enum为PgType_Runtime=100;来判断走新的跳转机制;

并且我们的ScEntity增加了三个属性 cname/mcname/moname

河狸家APP如何满足产品的任意页面跳转需求(runtime)_第5张图片

而我们的openUrl所对应json结构也发生了如下变化;

~1、区分事件类型 如"page"

~2、获取json

json对象结构形如

{

     “type” : enum, //跳转页面标示   建立一个页面映射表来对应enum

     “pgName” : “作品详情”,//页面名称

     “cName” : “ViewController”,//页面class名

     “mCName” : “Model”,//model class名

     “mOName” : “model”,//model对象名

     “jdata” : {

              “proId” : “sldkjf3l2”

       }

}

例如要跳转作品列表:

"openUrl": "hlj://pg?jData={\"hljtype\":100,\"cName\":\"SearchtResultController\",\"mCName\":\"SeachCModel\",\"mObjName\":\"searchC\",\"pgN\":\"作品列表\",\"data\":{\"artType\":1,\"cate\":\"tag_m\"}}}"}"

第一步,

通过cName,获取cName所对应的类名pageclass,通过pageclass创建唤起的目标页面对象;

河狸家APP如何满足产品的任意页面跳转需求(runtime)_第6张图片

第二步,

通过mcName去获取mcName所对应的类名modelclass;

再通过objc_getClass(modelclass)获取modelclass的isa指针指向(唤起的目标页面)所对应的modelc类对象;

假如不存在modelc类,就去创建一个nsobject类,nsobject是对象的root类;([NSObject class]只是返回一个NSobject类),那么superClass为一个NSobject类;

使用objc_allocateClassPair为"class pair"分配空间,来创建一个NSobject子类;

(什么是“class pair"? objc_allocateClassPair只返回一个值:Class。)

(拓展:如果想要为类添加方法可使用class_addMethod添加了一个方法,如class_addMethod(superClass, @selector(report), (IMP)ReportFunction, "v@:");

@selector(report)获取一个SEL类型,IMP是oc实现代码块的地址,类时函数指针,通过他可以直接访问人意一个方法,免去发送消息的代价;imp(对象自己(self),方法标示SEL,第三个是方法的参数);通过IMP直接调用方法 等效调用:[self SEL:参数];   //另外增加实 例变量用class_addIvar)

注册你创建的这个类,使其可用;

河狸家APP如何满足产品的任意页面跳转需求(runtime)_第7张图片

第三步,

遍历外部传入的参数data的key;

利用kvc对model对象每个属性进行赋值;

伪代码表现model.key = obj;//大致是这样一个形式

且要注意一定要去判断key所对应的model中的属性(名字与key一致)是否存在;(方法在最后代码片段里)

这样就得到一个完整数据的model;

河狸家APP如何满足产品的任意页面跳转需求(runtime)_第8张图片

第四步,

model也是一个page页面的属性,则可以同样的方式将model赋值给pageclass

河狸家APP如何满足产品的任意页面跳转需求(runtime)_第9张图片

最后为检查属性是否存在的代码片段:

河狸家APP如何满足产品的任意页面跳转需求(runtime)_第10张图片

这样就愉快的做到了在不发布版本的前提下实现任意跳转;

五 技术上总结

协议跨平台兼容性:安卓也是走的同样的一套设计协议,这样安卓iOS都不需要发布版本则可以做到实现任意页面跳转;

架构提升:对团队工程师的模块化/封装性的要求比较高,提升app的架构设计;

开发工程师开发成本:不需要关注如何跳转,只需要调用一段代码,将想要到达的目的页面class以及传递的数据model告知给消息中心即可;

解除模块间的耦合;

你可能感兴趣的