誰阻礙了你做元件化開發?

齊翊發表於2019-03-01

前言

之前寫了一篇關於總結一波安卓元件化開源方案的文章,反響還不錯,很高興能夠對大家整體瞭解android元件化技術有所幫助。

有些開發者在瞭解元件化開發的好處及相關開源框架後,想要對自己所負責的專案進行元件化改造以解決多人(多團隊)協同開發困難及單工程開發編譯時間過長等問題,但一直難以下決心真正開始實施,停留在瞭解階段或僅僅寫個demo體驗一把的階段,其中很大一部分原因是迭代開發任務排的很緊,很難空出一段時間來實施,而且元件化改造是純技術上的優化,產品經理和業務部門並不太關心。

為此,本文將介紹一下如何用 CC 框架來破解android元件化不易上手的難題(想要了解CC實現原理的細節,請戳這裡

一、誰阻礙了你

先來解決幾個可能阻擋我們下決心實施元件化改造的攔路石:

  1. 怕配置複雜,容易遺漏或出錯
    • CC將配置封裝到了一個cc-settings.gradle檔案,在需要元件化的module的build.gradle中新增一行依賴cc-settings.gradle檔案的程式碼即可
  2. 怕一開始就需要很大的改動
    • 使用CC可以先不改變當前專案中現有的程式碼,無需新增註解,只需新增一個介面的實現類即可定義一個元件,將其服務暴露給其它元件呼叫,後續有空的時候再逐步拆分
  3. 怕元件化開發框架學習成本高,團隊內每個人都瞭解需要較長時間
    • CC提供了統一的呼叫方式和實現方式
    • 定義元件僅需實現1個介面類,並確保通過呼叫CC.sendCCResult(callId, cCResult)將元件呼叫的執行結果傳送給呼叫者即可
    • 呼叫元件僅需瞭解一下CC鏈式呼叫即可,例如:(CC.obtainBuilder("demo.ComponentA").setActionName("login").addParam("id", 12345).build().callAsync(callback)
    • 另外library模式切換成application的方式簡化為在local.properties中配置一行module名稱=true即可,而且local.properties不會被提交到程式碼倉庫中,不會因為誤操作導致在jenkins上編譯出錯的情況
    • 幾乎零門檻就可以進行元件化開發
  4. 怕增加專案的維護成本
    • CC採用了編譯時自動註冊外掛AutoRegister來自動維護元件的註冊工作,無需手動維護
    • 元件化框架下進行開發跟普通的開發一樣,未使用hook等黑科技
    • 元件將業務隔離在內部,並且可單獨除錯,能降低專案維護成本
  5. 剛開始元件化時如果呼叫其它元件必須要打包一起執行,則享受不到單元件執行的便利
    • CC支援跨app呼叫
    • CC支援一個module中包含多個元件類,即使沒有進行拆分,也可以在主工程中定義這些元件類(在主app moudle或在被呼叫功能所在的module都可以),暴露呼叫入口給其它元件呼叫,後續在進行元件拆分時將元件類一同拆分出去即可
    • 所以,可以將需要被呼叫到的功能先定義好元件,供新建的元件跨app呼叫,無需與主工程一起打包,從一開始就可以單獨執行元件
  6. Fragment不好元件化
    • 其它元件化方案採用下沉介面的方式提供元件間呼叫,但只是獲取了Fragment物件,難以進行後續的通訊
    • CC框架下,獲取Fragment物件的方式跟其它元件呼叫完全一樣,並且後續可以將此Fragment物件作為引數回傳給原元件進行Fragment內部功能的呼叫,真正做到業務隔離在元件內部進行處理
  7. 有自定義View或者第三方View的功能不好元件化,例如將第三方地圖SDK封裝成元件,由於其它元件頁面中要用到MapView控制元件,是否需要強依賴?

二、推薦的元件化實施步驟

設想一下,在做元件化改造之前,如果按照如下步驟來實施,是不是可行性更高一些,讓我們更快地享受到元件化給我們帶來的便利和好處,不至於因為迭代任務節奏快而遲遲不能落實:

2.1 快速上手

  • 先不用修改當前專案中現有的程式碼(最大程度地降低工作量及出錯概率)
  • 可以選擇將新的業務按照元件化的方式來進行開發,單獨以apk的方式編譯執行&除錯(也可以選擇一個耦合度較低且相對獨立的業務來進行這一步)
  • 在主工程中建立新元件所需要呼叫到的主工程業務的元件類
  • 在這些元件類在元件尚未完整拆分之前即可按照元件化的方式對其它元件暴露呼叫入口
  • 恭喜,元件化改造的第一步已經成功邁出。

2.2 全域性規劃

由於元件化是全域性的架構,提前規劃好整個工程的元件劃分並明確各自的業務邊界,會讓我們實施元件化改造的過程更加有章法,專案結構更加清晰,責任更加明確,元件的可複用性更強。

關於元件如何劃分,不同的團隊有不同的理解,不同的業務應用場景下也有不同的要求。一般常用的劃分方式以下2種,可以結合起來使用:

  • 按UI(Activity/Fragment/View)劃分,每個頁面或控制元件都作為獨立的元件。
    • 優點是粒度較細,方便複用,某個頁面發生變化不會影響其他頁面
    • 缺點是如果頁面多,會導致元件太多,並且如果一個業務有多個頁面,這種方式導致業務內部太鬆散,不方便管理。
    • 另外需要將非頁面性的一些服務封裝為元件
  • 按業務/功能來劃分,將同一個業務下的不同功能和頁面劃分在同一個元件中
    • 優點是可以統一管理本業務下的所有功能(包括頁面和服務),提高了內聚性,改造方便
    • 缺點是如果掌控不好粒度可能會比較粗

不管具體如何劃分,有一點是相通的:單一職責。即需要確定好業務邊界,將元件的業務隔離在自己內部,只暴露呼叫協議給外部。

舉個栗子:

與使用者賬號相關的業務,根據業務複雜程度及元件在不同app中複用的需求等不同情況,可以將其整體劃分為1個元件,也可以劃分為登入元件、設定元件、地址管理元件等各種更細粒度的元件,如果你願意,也可以每個頁面1個元件再加上賬號相關的服務元件。

但需要注意的是必須有明確的業務邊界。比如其中的登入元件,就只負責使用者的賬號登入/註冊等功能,不能將各種登入後的頁面跳轉業務需求耦合到登入元件中,可以採用這種方式來實現:實現登入成功再進入目標介面功能

再舉個JsBridge的栗子:

由於每個元件的業務都內聚在自身內部,所以JsBridge可以封裝得十分優雅,迴歸其本質:僅作為js與java通訊的橋樑,與其它元件完全解耦,不需要下沉業務BridgePlugin介面

  • js呼叫java時,在JsBridge元件中直接將引數轉發給對應的元件
  • java呼叫js時,在JsBridge元件中根據呼叫引數呼叫對應頁面的js
  • 做好對應業務元件找不到時的降級處理

再也不需要在application中註冊一系列的Plugin

詳情請戳讓jsBridge更優雅

2.3 有空再弄

元件化改造中工作量最大的是要進行業務隔離,逐個元件抽離、解耦,這是一個比較長的過程,不能一蹴而就,可以在迭代任務有空閒的時候一個個進行拆分,拆分的難度取決於原來專案中程式碼的耦合程度:

  • 已封裝完好的業務module,只暴露一個或多個入口給別的module呼叫
    • 這種最簡單,僅需建立一個IComponent實現類,並將原來直接類呼叫的程式碼改成元件呼叫即可
  • 耦合度比較高的業務
    • 這種業務的拆分需要一定的時間,可以安排在迭代任務沒那麼繁忙的時間段來做。如果正好有改版的需求就更好了,可以藉著改版的機會用元件化的方式來開發,替換原來的程式碼。
    • 也可以暫時先粗粒度地拆分,但按照全域性的規劃建立多個IComponent介面實現類,相當於一個module中包含多個元件,後續有時間再進一步拆分
  • 各種Base類、工具類
    • 這種module建議仍然下沉作為公共庫的形式供其它元件依賴

三、常見問題

3.1 自定義型別如何在元件間傳遞?

  • 下沉到公共庫中,作為公共型別
    • 適用於使用頻次高或對效能要求特別敏感的場景
  • json傳遞 & bean冗餘:即在每個用到此型別的元件,通過冗餘bean的方式來傳遞
    • 適用於使用頻次較低且對效能要求不是十分敏感的場景

3.2 如何確定一個module到底是該作為元件提供服務還是下沉為base基礎庫供其它元件依賴?

由於元件有可單獨執行除錯、無強型別耦合、AOP等優點,除非有特殊情況,原則上絕大多數的業務module都應該作為元件來封裝。

這些特殊情況有:

  • 各種Base類、工具類
  • 在元件間傳遞的公共自定義型別

其它諸如Fragment/View的元件化CC都已經支援了,如果有您需要的功能CC還未支援歡迎給我提issue

四、總結

本文主要介紹瞭如何更方便地使用CC框架來進行元件化改造,看完這篇文章後,對老專案進行元件化改造所需的成本應該有個比較直觀的認識。

如果您雖然很想在自己負責的專案中實施元件化改造,渴望元件化開發帶來的便利,但還有本文中未涉及到的其它顧慮導致尚未開始執行,歡迎在評論中給我留言!

QQ交流群

CC交流群

或者掃描下方二維碼加群聊

image

相關文章