導語

市場環境瞬息變換,產品需要根據市場進行快速調整。如何在保證優秀的用戶體驗,常規發版節奏不變的情況下,可針對部分重要產品功能完成熱部署,成爲當下我們要解決的技術問題。市場上的解決方案多種多樣,如插件化、RN、WEEX等。前幾期文章介紹過iOS的輕量級動態部署開發框架,現將Android端的動態部署開發框架-DU也一併發出來,一起探討學習。下面將向大家詳細介紹此框架。

DU的框架產生

什麼是DU?DU,全稱爲DynamicUpdate。顧名思義,就是動態更新框架。DU的誕生,是爲了解決Android平臺的動態部署能力,因此我們可以通過DU解決產品同學想快速驗證的部分重要需求,同時用戶體驗接近Native。

要實現快速迭代,就要避開APP發版環節,採用動態部署的方式,將功能動態下發到用戶手機內。市場上解決此類問題的方案也多種多樣,常見方案大致存在以下幾種:

A、Web / Hybird 方案;

B、JS + Native 方案;

C、Android插件化方案。

三種方案各有優缺點,具體優缺點對比以及技術選型不是本文重點,這裏不再展開討論,感興趣的同學可自行查閱相關文章。我們選取的是第二種方案:JS+Native解決方案。

JS+Native動態部署方案,其原理是:通過JS與native交互協議,用JS代碼操作原生系統的UI組件,代替DOM元素來渲染。由於最終渲染是由Native完成,所以即實現了跨平臺動態更新的特性,也保證了流暢的用戶體驗。市面上較流行的解決方案有:

React Native:是由Facebook開源的跨平臺移動應用開發框架。支持用開源的JavaScript庫React.js來開發iOS和Android原生App。其主張“Learn once, write everywhere”。

WEEX:WEEX是一款基於通用跨平臺的 Web 開發語言和開發經驗,來構建 Android、iOS 和 Web 應用的開發框架。目前 前端框架Vue 和 Rax被廣泛應用於 Weex 頁面開發。其宣稱“Write Once, Run Everywhere”。

DU也是基於JS+Native原理。它更加輕量,是面向Android研發人員設計的一款動態開發框架。它的設計思路遵循招才貓動態部署框架整體的思路,使Android/iOS  Native開發的小夥伴上手機開發成本低,甚至可忽略。下圖是用DU框架開發的頁面,大家可以看出,與我們Android開發規範相似度非常高。

看了demo代碼,相信大家對DU的開發有了個初步的認識。下面我將向大家詳細介紹DU開發框架原理與實現。

DU框架原理

上一章已提到,DU的技術方案爲JS+Native。具體方案如下圖:

協議通信層:DU框架,選取了Google的JavaScript引擎V8,實現JavaScript和Android的相互調用。在JS端以及Native分別對協議進行了封裝與解析。DU所有的數據交互,都是以此爲基礎來擴展的。
JS端SDK:DU圍繞協議層,封裝了對上層業務支持的各個功能模塊,並提供DynamicUpdateAPI,供JS業務層調用。如頁面組件、類轉換器、資源管理、配置管理、擴展模塊、崩潰收集等,這些模塊的封裝,會通過協議層傳輸到Native端,具體的實現,都由Native端完成。
Native端:則是對JS端定義的模塊具體實現。如網絡擴展模塊,會接受JS端傳遞的網絡協議數據,然後調用Native網絡框架(如OKHttp)去執行真正的網絡請求,並將結果通過協議層,會傳JS端。
JS業務層:業務邏輯具體實現層,通過調用JS端提供的DynamicUpdateAPI,完成需求功能的開發工作。
DU框架完整的運轉流程如下圖:

DU渲染原理

上文提到過,DU是一款面向Android開發人員的動態開發框架,主要體現在頁面創建、生命週期管理以及組件間通訊等封裝,都與Android Native開發規範高度保持一致。除了JS語言與Java語言在編寫方式上稍有差別外,Android同學在使用DU過程中,會有一種熟悉感撲面而來。下面向大家介紹DU頁面渲染以及生命週期管理的原理。

1、渲染原理

DU的佈局文件、文案定義、顏色、尺寸定義,都與Android完全一致,都是用xml定義,就連文件命名也延續了Android的命名;

DU的圖片,放到了固定的圖片文件夾中,在佈局文件中使用的時候,只要定義$drawable/xxx即可加載對應的圖片文件;

DU框架裏面封裝了加載DU頁面的DUActivity以及DUFragment。在啓動DU頁面時,將佈局文件與頁面進行關聯。在Activity/Fragment創建的時候,會自動創建資源解析器與構建器。

資源解析器會將佈局文件以及佈局中用到的顏色、尺寸、圖片等信息,進行解析轉換,並交給Views生成器,生成一個個帶有完整描述的組件,這些組件會形成ViewsTree。

轉換器將生成的ViewsTree交給構建器。構建模塊會根據各個控件的描述,創建對應的組件,並添加到DecorView上,併爲有交互的控件添加事件監聽。

至此,DU完成了頁面的渲染。

2、生命週期 DU將Android的生命週期,映射到了JS頁面的生命週期,使JS可以在生命週期內,處理自己的業務邏輯。具體方式如下圖:

DU同樣支持帶有啓動模式的Activity。由於Android的Activity需要在AndroidManifest.xml註冊,DU採用了佔坑的方式,提前在AndroidManifest.xml註冊了帶有啓動模式的Activity。

3、UI擴展 DU已經對構建頁面的基本組件做了封裝。如常用的Layout、Button、ListView、CheckBox等。但是業務錯綜複雜,交互設計千變萬化。顯然一個框架是不能覆蓋全部頁面元素的。這裏DU提供了UI擴展功能,只要按照DU的擴展規範,即可輕鬆創建屬於你的UI界面。具體方法如下:

JSUIComponents,是對應控件的調用封裝。如封裝JSButton對應的各種方法調用。

UIComponents組件,就是現有APP自己創建的控件,也可以是系統封裝的控件,如Button。

Proxy,是控件代理層。代理層有兩個作用:

A、封裝屬性代理。通過代理裏面封裝的Property,爲不同控件設置不同的屬性,並且Property是可以繼承的,相應的也就是控件的屬性可以繼承。如DUViewGroupProxy.Property 繼承自DUViewProxy.Property,所以DUViewGroup不但擁有了自己的屬性,同時也擁有了DUView的屬性。這樣可以避免重複定義控件屬性,增加屬性複用性。

B、將調用與實現隔離。如Button控件,在招才貓端對應的就是招才貓封裝的ZCMButton,但是對應其他APP,就會是xxxButton。有了代理層, 在集成DU框架時,可以實現控件的快速切換,而不是再封裝一套。

view_config配置文件,此文件主要作用是將View與Viewproxy做映射關係。

layout.xml,爲佈局文件。

以上爲Native端的實現。

SDK裏面已經封裝了交互協議以及View生成器。在SDK初始化的時候,已經根據view_config.xml的配置信息,將View與ViewProxy做了一一對應。在渲染頁面時,view生成器會根據layout創建相應控件,並通過ViewProxy,調用view的setxxx方法,爲view屬性賦值。

DU模塊擴展

使用DU框架進行混合開發,不可避免的要使用一些Native已經封裝好功能,比如分享、網絡請求、支付等等。爲解決此類使用場景,DU提供了擴展功能。具體原理如圖:

與UI擴展類似:

jSExtendsible封裝了擴展模塊的方法調用;

NativeExtengdsible,是具體擴展功能的實際執行方;

extendsible_config.xml將jSExtendsible與NativeExtengdsible做了映射關係;

SDK內部,通過ModuleManager,將jSExtendsible調用協議解析、並交給NativeExtengdsible執行,最後將執行結果返回。

DU類轉換器

JS是弱類型語言,在DU的協議傳輸中,DU框架將所有數據轉爲字符串傳輸。而Android端的具體執行,其實都是根據協議,通過反射調用相應功能模塊來完成的。Java是強類型語言,這就需要將協議中方法調用的參數做強類型轉換。

例如:JS端調用textView.setHeight(12)設置高度,協議傳輸過程中,12是字符串,調用的是Android端TextView的setHeight(int pixels) 方法。這時需要將字符串”12“轉換爲int類型。類轉換器處理的就是類似場景。

目前DU已經封裝了30幾種類轉換器,基本可以覆蓋常規開發需要。接入方也可以根據實際情況,擴展自己的類轉換器。具體原理以及實現過程和UI擴展、模塊擴展一致,如下圖。這裏不再贅述。

DU踩的坑

以上, DU動態框架核心技術點已給大家分享完畢。當然,我們在開發過程中,遇到了各種各樣的問題,在這裏和大家做個分享,採坑經驗最寶貴:

1、JS引擎的選擇

在DU行程框架誕生之前,招才貓使用了以WebView爲引擎,作爲協議中轉核心,通過JS,創建Native頁面並執行相關邏輯,實現了發佈頁面的動態化。

在後續優化中,在發佈頁面基礎上,提取了通用協議,並做了更加豐富的封裝,產出了第一版DU,同樣,第一版DU框架的核心引擎也是WebView。WebView在這裏的作用僅僅是執行JS,並負責與Native通訊。可以想見,WebView頁面繪製等功能並沒有使用,但是我們仍會進行初始化,造成了資源浪費。經過對比與調研,我們最終引入了V8,作爲DU框架的JS解析執行以及通訊引擎,減少了DU在運行時的資源消耗。

2、複雜動畫的處理

在需求開發中,必然會用到各種動畫效果,DU框架已支持常用的動效實現,如Animation、Transition等,DU已做了封裝,可以直接使用。但在我們使用過程中發現,簡單動效還好,DU完全能夠勝任。一旦在DU中實現比較複雜的動效時,頁面就會出現卡頓現象。經過試驗與分析,我們發現在動效執行過程中,JS與Native會進行頻繁交互,在協議傳輸、解析過程中,由於數據傳輸過於頻繁,造成通訊模塊處理延遲,導致頁面卡頓。

在解決動畫問題上,我們針對動效交互的協議做了大量優化,但收益不佳。在後續優化中,我們放棄了在動效交互協議上做文章,而是考慮其他解決方案。得益於我們UI擴展能力,在開發實踐中,我們將複雜動效封裝成UI組件,將動效完全交由Native實現,JS端僅僅作爲調用方。這樣,就不存在動效執行中,協議交互頻繁的問題了。此方案的壞處就是如果動效組件在之前版本中沒有實現過,還是需要跟隨版本上線。不過在實踐中,需要特別複雜動效的情況,少之又少。DU完全能夠勝任目前的需求。

結語

除以上框架核心技術內容,DU框架還有其他優秀的技術實現,如高效的DUListView、框架安全、崩潰採集等,限於篇幅原因,我們不在此一一贅述,歡迎大家線下相互交流、學習。

參考文獻

1、https://reactnative.cn/
2、https://weex.apache.org/zh/guide/introduction.html
3、https://nodejs.org/en/
4、https://github.com/eclipsesource/J2V8
5、https://developer.android.com/docs

作者簡介

黃金鑫,HRG技術部資深開發工程師,目前主要負責招才貓直聘安卓端相關業務開發與維護工作,對移動Android端相關技術,尤其是動態框架開發方面有一定研究。

閱讀推薦

相關文章