菜鳥裹裹App分析系列-UI框架設計分析

androad發表於2019-03-04

前兩天分析了菜鳥裹裹的具體業務,菜鳥裹裹能夠成功快遞行業的王牌產品,業務當然是非常重要的一環,不過App的操作體驗,以及能夠讓使用者使用上更加方便快捷,也是成功的重要因素,所以這次就來分析菜鳥裹裹的UI框架設計。
這次對主要功能頁面進行分析,分析工具:

  • UIAutomatorViewer-用來掃描和分析Android應用程式的UI元件的GUI工具
  • jadx-反編譯工具

首頁

菜鳥裹裹App分析系列-UI框架設計分析
圖中看出UI設計主要分為了:底部的menu_and_navigation_bar_container和內容區域navigation_bar_content 佈局檔案

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout android:id="@id/navigation_bar_root" android:clipChildren="false" android:layout_width="fill_parent" android:layout_height="fill_parent"
  xmlns:android="http://schemas.android.com/apk/res/android">
    <FrameLayout android:layout_gravity="top" android:id="@id/navigation_bar_content" 
    android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_marginBottom="@dimen/navigation_bar_height" />
    <ViewStub android:id="@id/navigation_bar_loading_view" 
    android:layout="@layout/cainiao_progress_dialog" android:inflatedId="@id/rn_loading_view" android:layout_width="fill_parent" android:layout_height="fill_parent" />
    <FrameLayout android:layout_gravity="bottom" android:id="@id/menu_and_navigation_bar_container" 
    android:clipChildren="false" android:layout_width="fill_parent" android:layout_height="@dimen/navigation_bar_height">
        <com.cainiao.commonlibrary.navigation.NavigationBarView android:gravity="bottom" 
        android:layout_gravity="center_vertical" android:id="@id/navigation_bar_view" 
        android:clipChildren="false" android:layout_width="fill_parent" android:layout_height="fill_parent" />
    </FrameLayout>
    <ViewStub android:id="@id/full_screen_splash_view" android:layout="@layout/libs_full_screen_splash_view" 
    android:inflatedId="@id/splash_layout" android:layout_width="fill_parent" android:layout_height="fill_parent" />
</FrameLayout>
複製程式碼

內容區域佈局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent"
  xmlns:android="http://schemas.android.com/apk/res/android">
    <com.cainiao.wireless.uikit.view.feature.PtrBirdFrameLayout android:id="@id/store_house_ptr_frame" 
    android:background="@color/full_transparent" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_below="@id/header_title_view">
        <ListView android:id="@id/package_listview" android:background="@color/homepage_fragment_listview_background" 
        android:scrollbars="none" android:layout_width="fill_parent" android:layout_height="fill_parent" 
        android:layout_marginBottom="10.0dip" android:listSelector="#00000000" android:divider="@null" 
        android:choiceMode="singleChoice" android:overScrollMode="never" />
    </com.cainiao.wireless.uikit.view.feature.PtrBirdFrameLayout>
    <LinearLayout android:orientation="vertical" android:id="@id/homepage_fragment_scrollable_layout" 
    android:layout_width="fill_parent" android:layout_height="wrap_content" 
    android:layout_below="@id/header_title_view">
        <com.cainiao.wireless.homepage.presentation.view.widget.newfeatureview.HomepageNewFeatureLayout android:id="@id/home_page_fragment_new_grid_feature_enter_layout" 
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" />
    </LinearLayout>
    <com.cainiao.wireless.homepage.presentation.view.widget.HomepageTitleView android:id="@id/header_title_view" 
    android:layout_width="fill_parent" android:layout_height="45.0dip" />
</RelativeLayout>
複製程式碼

佈局檔案的具體結構圖:

菜鳥裹裹App分析系列-UI框架設計分析

  • menu_and_navigation_bar_container主要包含了NavigationBarView,底部導航內容:首頁,取件,寄件,驛站,我。
  • navigation_bar_content:內容區域。通過底部導航的切換,內容顯示不同的頁面。
  • main_activity_content:首頁的內容區域顯示。分為三部分:
    • header_title_view:通過自定義ViewHomepageTitleView實現
    • homepage_fragment_scrollable_layout:通過HomepageNewFeatureLayout實現
    • store_house_ptr_frame:展現列表和下拉重新整理,分別通過ListViewPtrBirdFrameLayout實現

物流詳情

菜鳥裹裹App分析系列-UI框架設計分析
物流詳情的頁面比較有特色,地圖展示訂單的軌跡,列表展示從發貨到收貨各個節點資訊。 UI結構圖:
菜鳥裹裹App分析系列-UI框架設計分析

  • 最底層是全屏mapview
  • 選單操作層覆蓋在mapview上
  • 最上面一層是物流從發貨到收貨的節點列表

不過從反編譯中無法找到對應的佈局xml,通過關鍵字logistic在AndroidManifest.xml檔案搜尋到相關的Activity。發現com.cainiao.wireless.logisticsdetail.presentation.view.activity.ShowGoodInfoActivity有相關性,ShowGoodInfoActivity中使用ShowGoodInfoFragment渲染, ShowGoodInfoFragment中有個方法會真正進入到詳情的邏輯。

public void showGoodInfo(List<LogisticsDetailGoodsDO> packageItems) {
    if (packageItems != null) {
        if (packageItems.size() == 0) {
            Bundle bundle = new Bundle();
            bundle.putString("orderCode", this.mOrderCode);
            bundle.putString("mailNo", this.mMailNo);
            bundle.putString("cpCode", this.mCpCode);
            //進入詳情的Router宣告
            Router.from(getActivity()).withExtras(bundle)
            .toUri("guoguo://go/logistic");
            getActivity().overridePendingTransition(0, 0);
            finish();
        }
        if (packageItems.size() == 1) {
            Router.from(getActivity()).toUri(((LogisticsDetailGoodsDO) packageItems.get(0)).taobaoGoodUrl);
            getActivity().overridePendingTransition(0, 0);
            finish();
            return;
        }
        this.mSlideShowView.setDatas(packageItems);
    }
}
複製程式碼

該方法通過Router進行跳轉到guoguo://go/logistic,在AndroidManifest.xml有對應的宣告:

<activity android:configChanges="keyboardHidden|orientation" android:exported="false" 
android:name="com.taobao.cainiao.newlogistic.LogisticDetailActivity" 
android:screenOrientation="portrait" android:theme="@style/Theme.NoBackgroundAndTitle.TabPage" 
android:windowSoftInputMode="adjustResize">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <data android:host="go" 
        android:path="/logistic" 
        android:scheme="guoguo"/>
    </intent-filter>
    <meta-data android:name="bundleLocation" android:value="com.taobao.cainiao"/>
</activity>
複製程式碼

沒錯就是它, LogisticDetailActivity就是我們要找的顯示物流詳情的頁面。 反編譯的程式碼中沒有對應的LogisticDetailActivity的原始碼,這些部分應該是通過Atlas動態部署的。 LogisticDetailActivity在Atlas框架中的宣告

package android.taobao.atlas.framework;

public class FrameworkProperties {
    public static String autoStartBundles = "com.android.update,com.cainiao.wireless.pr";
    public static String bundleInfo = " 
    ...
    {\"activities\":[\"com.taobao.cainiao.newlogistic.LogisticDetailActivity\"],\"contentProviders\":[],\"dependency\":[],\"isInternal\":true,\"pkgName\":\"com.taobao.cainiao\",\"receivers\":[],\"services\":[],\"unique_tag\":\"67520454e3fdb8fd2307b1c08c602abf\",\"version\":\"4.7.1@1.1.1.12\"}
    ....";

    public static String group = "cainiao4android";
    public static String outApp = "false";
    private String version = "4.7.1";

    public String getVersion() {
        return this.version;
    }
}
複製程式碼

寄件記錄

菜鳥裹裹App分析系列-UI框架設計分析
為什麼分析這個頁面,因為這個cn_wx_page_container,看id的名字判斷出這是weex頁面。 UI佈局:

<LinearLayout android:orientation="vertical" android:background="#fff2f2f2" android:layout_width="fill_parent" android:layout_height="fill_parent"
  xmlns:android="http://schemas.android.com/apk/res/android">
    <com.cainiao.android.cnweexsdk.weex.view.CNWXTopBar android:id="@id/cn_wx_page_topbar" android:layout_width="fill_parent" android:layout_height="?cnWXTopBarHeightStyle" />
    <FrameLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
        <FrameLayout android:id="@id/cn_wx_page_container" android:background="#ffffffff" android:layout_width="fill_parent" android:layout_height="fill_parent" />
        <FrameLayout android:layout_gravity="bottom" android:id="@id/cn_wx_page_cover" android:background="@color/cn_wx_transparent" android:layout_width="fill_parent" android:layout_height="wrap_content" />
        <TextView android:textSize="16.0sp" android:textColor="@color/cn_wx_exception_msg_color" android:layout_gravity="center" android:id="@id/cn_wx_container_page_exception" android:visibility="gone" android:layout_width="140.0dip" 
        android:layout_height="80.0dip" android:text="@string/cn_wx_reload_weex_txt" />
    </FrameLayout>
</LinearLayout>
複製程式碼

這個頁面,通過抓包分析,該頁面的請求url: https://cn.alicdn.com/cainiao-weex/order_center/0.3.0/main/order-center-homepage.js?navtype=weex&fc=true&bs=black&orderType=send&referrer=guoguo%3A%2F%2Fgo%2Fsendpackage 裡面主要是Vue編寫的頁面程式碼和邏輯。

總結

分析了App三個主要的功能,大致對菜鳥裹裹的UI框架有所瞭解。 在Android工程師角度分析App使用的開源框架-3.菜鳥裹裹一文中,羅列了App使用的一些框架。 通過分析,物流詳情中使用了Atlas,寄件記錄使用了Weex,其他的頁面,有興趣的同學可以自行分析。 雖然物流App,不像電商App(淘寶,天貓,京東等)那樣要求很高的動態化,不過菜鳥裹裹App使用了很多動態化框架,在不影響操作體驗的前提下,又增加了運營可以操作性,還是非常值得學習的。 以後有關菜鳥裹裹的分享,會集中在從零開始高仿菜鳥裹裹App(計劃中),希望同學們多多支援。

相關文章