經(jīng)過(guò)文檔一的描述,我們已經(jīng)可以把a(bǔ)pp的生命周期傳遞到j(luò)s。只要app在調(diào)用js橋的方法的時(shí)候,傳了name屬性,對(duì)應(yīng)的方法就可以通過(guò)js的map正確的傳遞到對(duì)應(yīng)js頁(yè)面。這里我們?cè)敿?xì)描述一下,app的生命周期是如何精準(zhǔn)的傳遞到j(luò)s的,了解后我們就能明白js是如何傳遞到app對(duì)應(yīng)的頁(yè)面的。
name頁(yè)面的名字屬性是核心:
首先,一個(gè)原生頁(yè)面就一定有一個(gè)對(duì)應(yīng)的js頁(yè)面。比如有注冊(cè)zhuce.activity這個(gè)原生頁(yè)面,就有一個(gè)zhuce.js頁(yè)面與之對(duì)應(yīng)。他們之間的橋梁是name這個(gè)屬性。
zhuce.activity 注冊(cè)頁(yè)面在頁(yè)面加載后,立馬調(diào)用了js的onLoad屬性,然后js在全局收到了onLoad這個(gè)action,此時(shí)js取出name = zhuce,發(fā)現(xiàn)在原生有一個(gè)叫zhuce的頁(yè)面onLoad了,此時(shí)js會(huì)立馬找到一個(gè)叫Zhuce的js的頁(yè)面類立馬實(shí)例化,實(shí)例化后得到zhuce的js對(duì)象,先放到j(luò)s的pageMaps中,以下是js的核心代碼:
let action = json.action ?//因?yàn)檫@里action=zhuce,我下面就簡(jiǎn)單的按zhuce頁(yè)面來(lái)寫(xiě)
let page_name = json.name // 這里得到zhuce
let PageClassStr = ?page_name.upper() //首字母大寫(xiě),轉(zhuǎn)為Zhuce
if(action == "onLoad"){
????let page_obj = eval('new?PageClassStr()') //根據(jù)Zhuce動(dòng)態(tài)運(yùn)算得到Zhuce頁(yè)面的對(duì)象實(shí)例
? ? window.pageMaps[page_name] = ?page_obj ?//注冊(cè)頁(yè)面放到全局的map中,key就是zhuce
}
好了,現(xiàn)在可以把a(bǔ)pp傳遞過(guò)來(lái)的生命周期全部轉(zhuǎn)接到注冊(cè)頁(yè)面了。
if(page_obj[action] != null){
? ??page_obj[action] (json) ?//如果page_obj 這個(gè)頁(yè)面實(shí)現(xiàn)了action方法,就傳json參數(shù)并調(diào)用
}
生命周期封裝:
很明顯,頁(yè)面會(huì)創(chuàng)建就一定有銷毀。當(dāng)js收到app傳遞過(guò)來(lái)onUnload方法,說(shuō)明這個(gè)原生頁(yè)面被銷毀了,js也會(huì)干掉對(duì)應(yīng)的js對(duì)象。
所以保證原生頁(yè)面的生命周期正確被調(diào)用很重要。同時(shí),原生頁(yè)面要正確的被釋放,比如從我的頁(yè)面打開(kāi)登錄頁(yè)面,然后點(diǎn)了登錄返回,此時(shí)登錄頁(yè)面應(yīng)該被銷毀并觸發(fā)onUnload方法,這很重要,這樣才能確保資源被正確的釋放。
總結(jié)一下:
在BaseActivity和BaseFragment封裝中,一定要正確觸發(fā)onLoad, onShow, onHide, onUnload。
全局一個(gè)橋,如何區(qū)分頁(yè)面的?
了解了上面的js的操作邏輯,其實(shí)實(shí)現(xiàn)對(duì)應(yīng)的原生頁(yè)面也不難了。在正式說(shuō)明之前,需要說(shuō)明一個(gè)重要的約定,即任何一個(gè)頁(yè)面都一定有一個(gè)具體的子類。比如登錄頁(yè)面一定有一個(gè)DengluActivity,我們不是動(dòng)態(tài)從父類實(shí)例化的,我們是從一個(gè)確定的子類來(lái)的,這非常重要。后面說(shuō)到原因。因?yàn)槊總€(gè)頁(yè)面可能未來(lái)操作不太一樣,而且每個(gè)頁(yè)面的數(shù)據(jù)事件都是在子類各自實(shí)現(xiàn)的。
首先在原生需要定義一個(gè)map,這個(gè)map主要實(shí)現(xiàn)兩個(gè)功能:
(1)給一個(gè)頁(yè)面的page字符串,需要知道對(duì)應(yīng)頁(yè)面的具體的類名,用于push的時(shí)候動(dòng)態(tài)反射實(shí)例化。
(2)如果page對(duì)應(yīng)的頁(yè)面實(shí)例化后,需要再保存對(duì)應(yīng)的存在的頁(yè)面對(duì)象。
因?yàn)榘沧縯ab的原因,我們?cè)O(shè)計(jì)了BasePageInterface接口來(lái)統(tǒng)一BaseActivity和BaseFragment. 所以這個(gè)map我們這樣設(shè)計(jì):
(1)首先map放哪,我覺(jué)得應(yīng)該可以放到靜態(tài)變量中,ios因?yàn)橹挥幸粋€(gè)類,我放到了BaseActivity中。假設(shè)你放到全局變量中:pageMap
(2)大概長(zhǎng)什么樣子?
let pageMap: [String: BasePageInterface] = {?
? ? "denglu": {
? ? ? ? ? ? "Class": "DengluActivity",//登錄頁(yè)面的類名,用來(lái)反射實(shí)例化對(duì)象
? ? ? ? ? ? "instance": null, //BasePageInterface類型,登錄頁(yè)面的實(shí)例化后的對(duì)象
????} ,
? ?//其他頁(yè)面 ??
}
有了這個(gè)page后,雖然全局只有一個(gè)橋,但js用頁(yè)面的name可以找到精準(zhǔn)的對(duì)應(yīng)的頁(yè)面。
現(xiàn)在我們?cè)倩氐椒庋b中,以BaseActivity為例(BaseFragment同理),頁(yè)面的初始化的時(shí)候一定要完善name字段,每個(gè)頁(yè)面都有name屬性。
在BaseActivity的onLoad里面
pageMap[this.name].instance = this //當(dāng)前頁(yè)面已經(jīng)是一個(gè)實(shí)例,指針?lè)诺絤ap中。
js("onLoad") //調(diào)用js的onLoad,上一篇已經(jīng)說(shuō)明過(guò)了
很明顯,有一個(gè)對(duì)稱的操作:
在BaseActivity的onUnload里面
pageMap[this.name].instance = null //當(dāng)前頁(yè)面已經(jīng)銷毀,從map中移除實(shí)例
js("onUnload") //調(diào)用js的onUnload,上一篇已經(jīng)說(shuō)明過(guò)了,
初始化tab需要初始化完善一些map需要的信息:
好了?,F(xiàn)在我們創(chuàng)建4個(gè)tab頁(yè)面的時(shí)候,這4個(gè)tab頁(yè)面一啟動(dòng)就存在了,所以我們需要手動(dòng)完善下map:
pageMap["shouye"].instance = shouye //其他4個(gè)頁(yè)面同理
app一啟動(dòng),有默認(rèn)有5個(gè)instance存在于map中了,其他頁(yè)面基本是封裝好后,js來(lái)自動(dòng)化管理控制了。假設(shè)沒(méi)操作這步,很明顯js在使用name找頁(yè)面的時(shí)候是找不到對(duì)應(yīng)的tab頁(yè)面的。
技術(shù)實(shí)戰(zhàn):
push協(xié)議:
協(xié)議名:push
參數(shù):?
{
? ? "name": "denglu" ?//push新頁(yè)面的name,app需要根據(jù)name取出Class實(shí)例化
? ? "options": "", //json格式的參數(shù),后面細(xì)說(shuō)
}
push的時(shí)候,app需要根據(jù)name取出Class實(shí)例化,然后打開(kāi)新頁(yè)面,可以知道,因?yàn)槭欠庋b的原因,新頁(yè)面創(chuàng)建后,在內(nèi)部onLoad會(huì)自動(dòng)把自己放到pageMap中。
當(dāng)然我們要觸發(fā)push依賴點(diǎn)擊事件,這個(gè)是下一篇文件VM表單控件觸發(fā)的說(shuō)完才能觸發(fā)push,不過(guò)可以先寫(xiě)push這個(gè)方法。我們循循漸進(jìn)。