一 跳轉(zhuǎn)native頁面需求入口來源分析
跳轉(zhuǎn)native頁面的源頭分五類:
1.第三方app喚起跳轉(zhuǎn)晚胡,包含短信;這類多用于第三方市場商務(wù)合作以及運營活動;
2.推送消息指令跳轉(zhuǎn);這類可幫助運營提高老用戶活躍,提高轉(zhuǎn)化扩淀;
3.服務(wù)器下發(fā)指令跳轉(zhuǎn);(長鏈接場景服務(wù)端主動推消息)
4.App native內(nèi)部跳轉(zhuǎn)啤挎;iOS自身技術(shù)設(shè)計需要驻谆;
5.native與h5的交互跳轉(zhuǎn);在電商app中庆聘,十分廣泛胜臊,可幫助產(chǎn)品更快試錯,更快速的迭代更新伙判;
分析了來源和意義象对,我們來看看電商app實現(xiàn)任意入口的任意跳轉(zhuǎn)到底有什么好處呢?
二 電商app實現(xiàn)任意跳轉(zhuǎn)app頁面的好處
1.從產(chǎn)品上:服務(wù)端即可靈活的控制app宴抚,滿足產(chǎn)品天馬行空的跳轉(zhuǎn)想象勒魔,更靈活的滿足產(chǎn)品需求;
2.從運營支持上:我們要明白任何沒有著落頁的短信及推送消息菇曲,都是耍流氓冠绢,否則對點擊了消息而沒有看到著落的用戶就是一種傷害;而它能解決點擊每個活動消息都可以自定義著落頁面常潮;
3.從技術(shù)上:當(dāng)兩位領(lǐng)導(dǎo)意見分歧弟胀,一個要跳a頁面,一個要跳轉(zhuǎn)到b頁面喊式,此時則可搞a/b test邮利,再結(jié)合BI數(shù)據(jù)分析,分析轉(zhuǎn)化垃帅;最終幫助公司沉淀最優(yōu)方案,提高轉(zhuǎn)化剪勿,最終實現(xiàn)理想IPO上市贸诚;這就是技術(shù)的力量(哈哈平和領(lǐng)導(dǎo)的關(guān)系,維護了公司的團結(jié)穩(wěn)定#共勉#)
估計大部分技術(shù)都沒有意識到自己還有這種力量厕吉,以上對話勿讓領(lǐng)導(dǎo)聽到#奸笑#
這樣看起來無論哪個入口要跳轉(zhuǎn)哪個頁面酱固,技術(shù)上去做好它都變得十分有意義!
三 河貍家app早期協(xié)議
(因安全原因头朱,由于蘋果可通過class-dump命令运悲,反編譯處理,若直接暴露類名/方法/對象會引來安全問題项钮,故以下代碼的方法和類名都經(jīng)過處理班眯,命名也不規(guī)范希停,請諒解,注意思路)
背景:
設(shè)計理念署隘,如同http://訪問一樣宠能,只需要一個知道Url拋給底層服務(wù),即可訪問想要到達的頁面磁餐,而上層工程師不需要關(guān)注中間如何訪問及如何跳轉(zhuǎn)违崇;
由此,河貍家app定義了一個openUrl诊霹,來控制所有的頁面跳轉(zhuǎn)訪問羞延;
下面來看openUrl結(jié)構(gòu):
首先要建立協(xié)議:
1.協(xié)議頭定義:考慮到第三方app喚起的原因,我們將協(xié)議頭定義為URL Schemes(如微信的weixin://),這里考慮到安全問題脾还,則隱藏河貍家app URL Schemes伴箩;用“HLJ://”代替
~urlString 形如 @"HLJ://page?jsonData={json}";
~1、區(qū)分事件類型 如"page"
~2荠呐、獲取json
json對象結(jié)構(gòu)形如
{
? ? ?"hljType” : enum, //跳轉(zhuǎn)頁面標(biāo)示 ? 建立一個頁面映射表來對應(yīng)enum
? ? “hljPageN” : “作品詳情”,//頁面名稱
? ? “jData” : {
? ? ? ? ? ? “proId” : “sldkjf3l2”
? ? ? }
}
json對應(yīng)的model對象ScEntity如圖:
制定完協(xié)議結(jié)構(gòu)赛蔫,下面來看看過程核心代碼結(jié)構(gòu):
核心管理類ScManager,負(fù)責(zé)接收openUrl協(xié)議泥张,校驗協(xié)議呵恢,解析json,定向跳轉(zhuǎn)媚创;
工程師在開發(fā)過程只需要注意在openurl中填寫跳轉(zhuǎn)目的頁面渗钉,以及model丟出數(shù)據(jù)即可,其他則不用關(guān)注钞钙;
第一步
首先校驗跳轉(zhuǎn)協(xié)議鳄橘,必須要遵循HLJ://才可進入跳轉(zhuǎn)邏輯,否則認(rèn)為非法芒炼;
再解析jsondata瘫怜,并解碼son串;
第二步
將json解析成字典本刽,利用MJ將數(shù)據(jù)轉(zhuǎn)成SceneBaseEntity對象
第三步鲸湃,通過枚舉映射表對應(yīng)跳轉(zhuǎn)類,并拼接model
再通過
TabBarController *rootNav = (TabBarController *) kWindow.rootViewController;
[[rootNav.viewControllers objectAtIndex:rootNav.selectedIndex] pushViewController:controller animated:YES];
實現(xiàn)了跳轉(zhuǎn)子寓;
優(yōu)點:
1.直觀暗挑;
2.工程師編碼只關(guān)注目的,和對應(yīng)的唯一model斜友。
缺點:
1.它還是不夠靈活炸裆,每個頁面都需要在枚舉表中對應(yīng)上映射,無法做到不發(fā)版本即可跳轉(zhuǎn)無映射的頁面鲜屏;
2.當(dāng)項目逐漸擴大烹看,頁面無窮多個時国拇,產(chǎn)品的野心也在膨脹后,要寫一堆的switch判斷听系;
那還是不完全滿足啊~~~~
別急1雌妗!?渴ぁ掉瞳!來看第四段~~~~~
四 ?如何設(shè)計一套協(xié)議另app能夠自由任意的跳轉(zhuǎn)呢?
核心:runtime運行時機制+組件化
(這里插個題外話浪漠,無論老人代碼寫的怎么樣陕习,都是帶動的創(chuàng)業(yè)公司走過風(fēng)雨,尊重與感謝址愿,勿吐槽多敬重8昧汀!O煳健)
注意:由于舊工程需要兼容损合,還考慮這套設(shè)計中的openurl協(xié)議涉及安卓/iOS /前端/后端,考慮團隊娘纷,則需要一個過渡方案嫁审。于是只能在舊工程上switch case,并且為了兼容舊版本赖晶,最新的運行時動態(tài)跳轉(zhuǎn)設(shè)計中添加了一個enum為PgType_Runtime=100律适;來判斷走新的跳轉(zhuǎn)機制;
并且我們的ScEntity增加了三個屬性 cname/mcname/moname
而我們的openUrl所對應(yīng)json結(jié)構(gòu)也發(fā)生了如下變化遏插;
~1捂贿、區(qū)分事件類型 如"page"
~2、獲取json
json對象結(jié)構(gòu)形如
{
? ? ?“type” : enum, //跳轉(zhuǎn)頁面標(biāo)示 ? 建立一個頁面映射表來對應(yīng)enum
? ? ?“pgName” : “作品詳情”,//頁面名稱
? ? ?“cName” : “ViewController”,//頁面class名
? ? ?“mCName” : “Model”,//model class名
? ? ?“mOName” : “model”,//model對象名
? ? ?“jdata” : {
? ? ? ? ? ? ? “proId” : “sldkjf3l2”
? ? ? ?}
}
例如要跳轉(zhuǎn)作品列表:
"openUrl": "hlj://pg?jData={\"hljtype\":100,\"cName\":\"SearchtResultController\",\"mCName\":\"SeachCModel\",\"mObjName\":\"searchC\",\"pgN\":\"作品列表\",\"data\":{\"artType\":1,\"cate\":\"tag_m\"}}}"}"
第一步胳嘲,
通過cName厂僧,獲取cName所對應(yīng)的類名pageclass,通過pageclass創(chuàng)建喚起的目標(biāo)頁面對象了牛;
第二步吁系,
通過mcName去獲取mcName所對應(yīng)的類名modelclass;
再通過objc_getClass(modelclass)獲取modelclass的isa指針指向(喚起的目標(biāo)頁面)所對應(yīng)的modelc類對象白魂;
假如不存在modelc類,就去創(chuàng)建一個nsobject類上岗,nsobject是對象的root類福荸;([NSObject class]只是返回一個NSobject類),那么superClass為一個NSobject類;
使用objc_allocateClassPair為"class pair"分配空間肴掷,來創(chuàng)建一個NSobject子類敬锐;
(什么是“class pair"? objc_allocateClassPair只返回一個值:Class背传。)
(拓展:如果想要為類添加方法可使用class_addMethod添加了一個方法,如class_addMethod(superClass, @selector(report), (IMP)ReportFunction, "v@:");
@selector(report)獲取一個SEL類型台夺,IMP是oc實現(xiàn)代碼塊的地址径玖,類時函數(shù)指針,通過他可以直接訪問人意一個方法颤介,免去發(fā)送消息的代價梳星;imp(對象自己(self),方法標(biāo)示SEL,第三個是方法的參數(shù));通過IMP直接調(diào)用方法 等效調(diào)用:[self SEL:參數(shù)]; ? //另外增加實 例變量用class_addIvar)
注冊你創(chuàng)建的這個類,使其可用滚朵;
第三步冤灾,
遍歷外部傳入的參數(shù)data的key;
利用kvc對model對象每個屬性進行賦值辕近;
偽代碼表現(xiàn)model.key = obj韵吨;//大致是這樣一個形式
且要注意一定要去判斷key所對應(yīng)的model中的屬性(名字與key一致)是否存在;(方法在最后代碼片段里)
這樣就得到一個完整數(shù)據(jù)的model移宅;
第四步归粉,
model也是一個page頁面的屬性,則可以同樣的方式將model賦值給pageclass
最后為檢查屬性是否存在的代碼片段:
這樣就愉快的做到了在不發(fā)布版本的前提下實現(xiàn)任意跳轉(zhuǎn)漏峰;
五 技術(shù)上總結(jié)
協(xié)議跨平臺兼容性:安卓也是走的同樣的一套設(shè)計協(xié)議糠悼,這樣安卓iOS都不需要發(fā)布版本則可以做到實現(xiàn)任意頁面跳轉(zhuǎn);
架構(gòu)提升:對團隊工程師的模塊化/封裝性的要求比較高芽狗,提升app的架構(gòu)設(shè)計绢掰;
開發(fā)工程師開發(fā)成本:不需要關(guān)注如何跳轉(zhuǎn),只需要調(diào)用一段代碼童擎,將想要到達的目的頁面class以及傳遞的數(shù)據(jù)model告知給消息中心即可滴劲;
解除模塊間的耦合;