河狸家APP如何滿足產品的任意頁面跳轉需求(runtime)

weixin_33850890發表於2016-07-06

一 跳轉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如圖:

2384088-2b45ec3de717b7ea.png

制定完協議結構,下面來看看過程核心程式碼結構:

核心管理類ScManager,負責接收openUrl協議,校驗協議,解析json,定向跳轉;

工程師在開發過程只需要注意在openurl中填寫跳轉目的頁面,以及model丟出資料即可,其他則不用關注;

第一步

首先校驗跳轉協議,必須要遵循HLJ://才可進入跳轉邏輯,否則認為非法;

再解析jsondata,並解碼son串;

2384088-0625225a0b0c6a60.png

第二步

將json解析成字典,利用MJ將資料轉成SceneBaseEntity物件

2384088-8c55d6ca56121865.png

第三步,通過列舉對映表對應跳轉類,並拼接model

2384088-9482bc19316311ca.png
再利用

再通過

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

2384088-7391b33cbed9b17a.png

而我們的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建立喚起的目標頁面物件;

2384088-5e9e29f790be3752.png

第二步,

通過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)

註冊你建立的這個類,使其可用;

2384088-84d8ae0e1df33b47.png

第三步,

遍歷外部傳入的引數data的key;

利用kvc對model物件每個屬性進行賦值;

虛擬碼表現model.key = obj;//大致是這樣一個形式

且要注意一定要去判斷key所對應的model中的屬性(名字與key一致)是否存在;(方法在最後程式碼片段裡)

這樣就得到一個完整資料的model;

2384088-6c302cc6c48f937a.png

第四步,

model也是一個page頁面的屬性,則可以同樣的方式將model賦值給pageclass

2384088-8a57362254a73452.png

最後為檢查屬性是否存在的程式碼片段:

2384088-985a008bccf845eb.png

這樣就愉快的做到了在不釋出版本的前提下實現任意跳轉;

五 技術上總結

協議跨平臺相容性:安卓也是走的同樣的一套設計協議,這樣安卓iOS都不需要釋出版本則可以做到實現任意頁面跳轉;

架構提升:對團隊工程師的模組化/封裝性的要求比較高,提升app的架構設計;

開發工程師開發成本:不需要關注如何跳轉,只需要呼叫一段程式碼,將想要到達的目的頁面class以及傳遞的資料model告知給訊息中心即可;

解除模組間的耦合;

相關文章