天天看點

Shield——開源的移動端頁面子產品化開發架構

引言

一直以來,如何能更高效地開發與維護頁面是Android與iOS開發同學最主要的工作和最關心的問題。随着業務的不斷發展,根據特定業務場景産生的定制化需求變得越來越多。單一頁面往往需要根據不同業務、不同場景甚至不同使用者展示不同的内容。在這樣的背景下,我們開始考慮對頁面進行切分,把一個頁面切分成多個子產品,以提高複雜頁面的可維護性。

各種不同的定制化頁面如下:

Shield是美團點評到店綜合團隊子產品化UI界面解決方案,它不僅僅是一個Native(Android&iOS)的UI開發架構,還是到店綜合團隊基于自身複雜的業務場景沉澱出來的UI開發最佳實踐。它具備高可複用、容易協同開發等特性,還包括後端動态配置、動态子產品等一系列解決方案,目前已經在GitHub上開源:https://github.com/Meituan-Dianping/Shield。

什麼是子產品

在Shield架構裡,頁面是由一個個子產品(Agent)組成的。子產品是頁面中粗粒度的抽象元件,包含部分頁面UI展示和與之相關的業務邏輯。這些子產品按線性的方式排布在頁面中,可以很靈活地調換位置且互不影響。每個子產品都有自己獨立的生命周期,可以單獨通過網絡擷取資料、渲染視圖等等。

每一個子產品都有自己獨立的邏輯和UI,子產品之間完全解耦,這樣就可以很友善地通過排列子產品來完成不同的頁面定制化需求,使一個頁面可以展示不同的内容。同時,由于子產品并不依賴某一具體頁面,子產品也可以在不同的頁面之間進行複用。

不同于MVP或是MVVM的設計模式,Shield的子產品化拆分方式根據視圖和業務邏輯對頁面進行橫向切分。子產品化的拆分與MVP等架構方式的拆分并不沖突。開發者完全可以在Shield的某個子產品裡運用MVP或MVVM的架構方式,來對頁面的邏輯進行進一步的拆分以提升代碼複用性,使子產品邏輯變得更加清晰。

為了更好地抽象UI界面開發的各種場景,Shield架構賦予了子產品完整的頁面能力,包括完整的頁面生命周期和上下文環境(Context)等。這樣子產品的開發方式與原有的頁面開發方式完全一緻,頁面不再關心具體的UI展現,而是把這些都交給子產品。同時子產品可以單獨開發維護,運作在任意接入了Shield架構的頁面中。

以下是子產品Agent的接口定義:

public interface AgentInterface {

        void onCreate(Bundle savedInstanceState);

        void onStart();

        void onResume();

        void onPause();

        void onStop();

        void onDestroy();

        Bundle saveInstanceState();

        void onActivityResult(int requestCode, int resultCode, Intent data);

        String getIndex();

        void setIndex(String index);

        String getHostName();

        void setHostName(String hostName);

        SectionCellInterface getSectionCellInterface();

        String getAgentCellName();
}      

一個Agent子產品的結構主要包含兩部分:

  1. 生命周期回調。
  2. 提供一個SectionCellInterface。

其中,SectionCellInterface是子產品的視圖邏輯抽象。一個子產品可以為頁面提供一個連續的包含多塊(Section)的UI片段,每一塊視圖可以是視覺上的單行(Row)視圖,也可以是多行視圖。具體的接口定義如下:

public interface SectionCellInterface {

    int getSectionCount();

    int getRowCount(int sectionPosition);

    int getViewType(int sectionPosition, int rowPosition);

    int getViewTypeCount();

    View onCreateView(ViewGroup parent, int viewType);

    void updateView(View view, int sectionPosition, int rowPosition, ViewGroup parent);

}      

一個子產品化頁面的組成結構

有了子產品承擔絕大部分的頁面邏輯,Shield架構中的頁面就變成了一個單純的子產品容器。頁面通過不同的子產品配置(Config)來靈活改變自己的視圖展現,同時在子產品配置(Config)中,定義了子產品的位置資訊,這樣除了本地配置之外,Shield架構也可以很容易就能支援後端動态下發子產品配置,以達到用戶端的一定動态性。

在接入了Shield架構的頁面中,還有兩個比較重要的角色,分别是子產品管理器(AgentManager)和視圖管理器(CellManager)。

其中,子產品管理器(AgentManager)負責子產品的建立、銷毀、生命周期分發等工作。而視圖管理器(CellManager)則負責将子產品所提供的視圖檔段(SectionCellInterface)有序地添加到頁面中,并在适當的時候對這些視圖進行更新。

子產品通信

在某些場景下,頁面中的一些視圖檔段會根據使用者操作發生一些關聯。而當這些視圖檔段處于不同的子產品中時,這些子產品就需要進行通信。

在這種情況下,如果讓子產品與子產品直接進行互動,就無法避免子產品之間的耦合,這樣既無法保證子產品的獨立性,也影響可複用性。于是我們基于RxJava設計實作了觀察者模式的白闆元件,在Shield架構中稱之為WhiteBoard。WhiteBoard在一個頁面中唯一,所有子產品共享,子產品之間或是子產品與頁面的通信都通過WhiteBoard來進行。

Shield架構關注的重

靈活配置

隻要把子產品配置放到遠端,通過統一的配置背景進行配置,就可以很輕松地實作App中各個頁面一定的動态化特性,無需借助其它插件化、熱更新檔等方案。

下圖便是美團點評開發的頁面子產品配置背景:

多端統一

我們通過提供多端統一的子產品化架構,減少開發者在不同平台的視覺實作差異上耗費的精力,進而将精力集中于如何實作具體的視圖檔段。Shield架構針對Native開發中常見的畫分隔線、loading動畫等一系列場景做了抽象,為子產品提供了豐富的定制化功能,簡化了App開發過程中占比較高的視圖開發工作。

動态化

子產品化架構對子產品的業務和視圖邏輯行為都做了一定的抽象,這樣,ReactNative一類的動态化方案不僅可以運用到視圖繪制層面上,同時也可以通過不同的JSBridge實作子產品業務邏輯的動态化。而配置背景不僅可以動态調整子產品,同時可以動态調整子產品的内部展示,這樣整個子產品化架構可以通過配置背景實作不同粒度的頁面動态化方案。有關動态子產品的相關方案,後續将另文詳述。

頁面混排與穩定性

借助于子產品化架構,可以有效地降低諸如ReactNative等開源架構的接入成本,無需對整個頁面進行改造,而是在子產品級的粒度上進行快速試錯,有效控制影響範圍,提升頁面整體的穩定性。

圍繞子產品化架構的工具鍊及生态圈結語

繼續閱讀