點我達騎手Weex接入過程詳述

一、概述

截止11月底點我達騎手APP已完整的接入了13個weex頁面,效果還不錯,Weex化推進也比較順利。現特分享一下Android端點我達騎手APP接入步驟及相關核心邏輯,以此作為記錄,同時也希望能給后來者帶來一些幫助。

二、集成Weex

Android 集成有兩種方式:

- 源碼依賴:能夠快速使用WEEX最新功能,可以根據自己項目的特性進行相關改進。

- SDK依賴:WEEX 會在jcenter 定期發布穩定版本。

由于業務關系點我達騎手APP接入了菜鳥SDK,而菜鳥SDK通過SDK依賴的方式在其中引入了Weex。

1、新建Weex module

新建一個Android Library類型的module,起名Weex。

2、添加build.gradle依賴

在Weex module下的build.gradle文件添加Weex依賴。

compile 'com.taobao.android:weex_sdk:0.11.0'
compile 'com.taobao.android:weex_inspector:0.12.1'

3、實現Weex接口協議

Weex提供了擴展機制,可以根據自己的業務進行定制自己的功能。比如需要加載圖片,則需要實現實現Weex的圖片接口協議。常見的module、component及adapter實現,官方示例中都已經給出完整的案例。

public class ImageAdapter implements IWXImgLoaderAdapter {
  @Override
  public void setImage(String url, ImageView view, WXImageQuality quality, 
                      WXImageStrategy strategy) {
    //實現你自己的圖片下載,否則圖片無法顯示。
  }
}

4、初始化

新建DWeexManager管理類,由此類統一管理Weex初始化、配置文件加載及路由控制等相關配置。initWeex()是DWeexManager的入口,初始化WXSDK引擎、加載JS配置文件列表及注冊擴展Module等。以下是initWeex()方法的相關邏輯:

public void initWeex(Application application) {
        mContext = application.getApplicationContext();
        weexPath = mContext.getFilesDir().getPath();
        appVersion = PhoneUtils.getAppVersion(mContext);
        InitConfig config=new InitConfig.Builder().setImgAdapter(new ImageAdapter())
                    .setHttpAdapter(new OkHttpAdapter()).build();
        WXSDKEngine.initialize(application, config);
        mConfigList = WXJsonUtils.getList(ConfigManager.getWeexConfig(mContext), 
                      WeexConfig.class);
        try {
            WXSDKEngine.registerModule("DEvent", WXEventModule.class);
            WXSDKEngine.registerModule("DModal", ModalModule.class);
            WXSDKEngine.registerModule("DCommon", WXCommonModule.class);
            WXSDKEngine.registerModule("DRouter", WXRouterModule.class);
        } catch (WXException e) {
            e.printStackTrace();
        }
    }

在Application的onCreate方法中調用進行初始化。

public class DwdApplication extends Application {  
  @Override
  public void onCreate() {
    super.onCreate();
    DWeexManager.getInstance().initWeex(this);
  }
}

5、開始渲染

新建一個統一的渲染頁面WeexPageActivity,在onCreate中初始化WXSDKInstance,并加載js文件。實現接口IWXRenderListener,重寫onRenderSuccess、onException等回調方法,對加載過程進行控制,具體實現可以參考官方demo中AbsWeexActivity。所有的Weex頁面統一跳轉到此activity,通過Intent傳入以下四個參數:

  • mUrl:js鏈接,線上及本地均可
  • mH5:降級到h5的鏈接
  • mBundleUrl:需要傳入JS頁面的參數BUNDLE_URL
  • pageName:JS頁面對應Native頁面名字,從配置文件中獲取,降級到Native使用

以下為渲染的部分代碼,renderURL方法為加載URL的關鍵方法,由于本地JS文件與在線JS加載方法不一致,此處需要根據URL判斷是否本地JS文件,options為需要傳入JS頁面的參數,格式類似Http的get請求。

protected void createWeexInstance() {  
        destoryWeexInstance();
        mInstance = new WXSDKInstance(this);
        mInstance.registerRenderListener(this);
    }

protected void destoryWeexInstance() {  
        if (mInstance != null) {
            mInstance.registerRenderListener(null);
            mInstance.destroy();
            mInstance = null;
        }
    } 

protected void renderURL(String url, String bundleUrl, String jsonInitData) {  
        Map<String, Object> options = new HashMap<>();
        options.put(WXSDKInstance.BUNDLE_URL, bundleUrl);
        if (isLocalPage()) {
            Uri uri = Uri.parse(url);
            if (uri != null) {
                mInstance.render(getPageName(), 
                                WXFileUtils.loadFileOrAsset(assembleFilePath(uri), 
                                this), options, jsonInitData, 
                                PhoneUtils.getScreenWidth(this), 
                                PhoneUtils.getScreenHeight(this),
                                WXRenderStrategy.APPEND_ASYNC);
            }
        } else {
            mInstance.renderByUrl(getPageName(), url, options, jsonInitData, 
                                  PhoneUtils.getScreenWidth(this),
                                  PhoneUtils.getScreenHeight(this), 
                                  WXRenderStrategy.APPEND_ASYNC);
        }
    }

渲染成功回調,在此方法中可以進行完成后的相關操作。如取消渲染計時器及隱藏加載進度條。

@Override
public void onRenderSuccess(WXSDKInstance instance, int width, int height) {  
        renderFinish = true;
        if (timer != null) {
            timer.cancel();
        }
        mProgressBar.setVisibility(View.GONE);
    }

6、降級

渲染失敗或者加載時間超時,降級到Native或者h5頁面。

@Override
public void onException(WXSDKInstance instance, String errCode, String msg) {  
        renderFinish = true;
        if (timer != null) {
            timer.cancel();
        }
        downgrade(errCode, msg);
    }

private void downgrade(String errCode, String msg) {  
        if (mProgressBar != null) {
            mProgressBar.setVisibility(View.GONE);
        }
        boolean isClosePage = true;
        if (!TextUtils.isEmpty(mH5)) {
            isClosePage = WeexNavHelper.openWebview(this, mBundleUrl, getIntent());
        } else { 
            errorOnpenNative = true;
            isClosePage = WeexNavHelper.openNative(this, mBundleUrl, pageName, 
                                                    getIntent());
        if (isClosePage) {
          finish();
         }
    }

三、高階知識

1、路由控制

路由主要由配置文件預先設定好的規則進行控制,配置文件由服務端下發,實現動態更新。由于Weex剛接入,為了降低風險,增加了全局開關以及單個頁面開關,開關關閉時就直接訪問Native頁面。路由規則如下圖: 配置文件:

{
    "weex_switch": 1,
    "version": "1.0.0",
    "interfaceVersion":"v1",
    "support_city_list":["1"],
    "js_list": [
        {
            "activityName": "com.dwd.setting.MoreActivity",
            "jsDownloadUrl": "http://prodwbbucket.com/weex/js/SettingView.js",
            "h5Url": "",
            "pageName": "setting/SettingView.js",
            "jsSwitch": 1,
            "version": "1.0"
        }
    ]
}

外層為全局參數:

weex_switch:全局開關  
version:文件版本號  
interfaceVersion:頁面訪問接口版本號  
support_city_list:支持Weex城市列表,區域控制,減小影響范圍

列表為單個js頁面相關參數:

h5Url:降級H5鏈接  
md5:js文件md5值  
activityName:對應的activity頁面名,完整包名  
pageName:對應js文件名  
jsDownloadUrl:js文件下載鏈接  
version:js文件版本號  
jsSwitch:單個js開關

訪問頁面時,會通過Intent中的class或者Url鏈接查找配置文件對應配置,如果未找到或者開關關閉,就直接訪問Native頁面(前提是對應的Native頁面存在),反之則進行js參數組裝,然后調用WeexPageActivity渲染頁面。

public Intent getIntentByActivityName(Context context, Intent paramsIntent) {
        if (!ConfigManager.getWeexEnable(mContext) || mConfigList == null) {
            return paramsIntent;
        }
        ComponentName componentName = paramsIntent.getComponent();
        if (componentName == null) {
            return paramsIntent;
        }
        String className = componentName.getClassName();
        for (WeexConfig weexConfig : mConfigList) {
            if (TextUtils.equals(className, weexConfig.name) && weexConfig.jsSwitch 
                 == 1) {
                Bundle bundle = paramsIntent.getExtras();
                String urlParams = WeexNav.makeUrl(bundle, "");
                String url = weexConfig.page + urlParams;
                Intent intent = getIntentByUrl(context, url, weexConfig);
                if (intent != null) {
                    return intent;
                }
            }
        }
        return paramsIntent;
    }

2、JS預下載

為了加快Weex頁面打開時間,推薦采用本地加載js的方式。為此在程序啟動之后更新配置文件同時下載js文件。具體流程如下:

1) 應用啟動時校驗配置文件MD5以及版本號,如果不一致更新配置文件,配置文件與應用版本綁定,防止程升級后加載老版本Weex配置文件。另外為了確保實時性,增加了輪詢服務進行同步;

2)遍歷js列表,校驗本地是否存在該js文件,如果存在,則繼續校驗js文件版本號(由于目前配置文件為手動上傳,無法生成MD5,暫時不比較文件MD5,此處會有風險),若文件不存在或者版本不一致則下載更新js文件;

更新關鍵方法如下:

public void update() {
        if (mConfigList == null || mConfigList.size() <= 0) {
            return;
        }
        try {
            for (WeexConfig config : mConfigList) {
                File jsFile = new File(weexPath, config.page);
                if (jsFile.exists()) {
                    if (!TextUtils.equals(config.version, 
                        ShareStoreHelper.getString(mContext, WEEX_FILE_VERSION +
                            config.page))) {
                        jsFile.delete();
                        downloadJs(config);
                    } 
                } else {
                    downloadJs(config);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

3、降級Native參數傳值

降級Native時根據路由規則跳轉對應的Native頁面,同時組裝相應的參數。如果是根據Url鏈接匹配頁面則需要拆分鏈接生成對應參數。特別說明Native頁面與js頁面參數key需要統一,否則會出現參數無法識別異常。

public static Intent putIntentExtra(String url, Intent intent) {
        if (TextUtils.isEmpty(url) || intent == null) {
            return intent;
        }
        Uri uri = Uri.parse(url);
        Set<String> set = uri.getQueryParameterNames();
        if (set == null || set.size() <= 0) {
            return intent;
        }
        for (String name : set) {
            intent.putExtra(name, uri.getQueryParameter(name));
        }
        return intent;
    }

四、后語

至此整個集成過程已經完成,總體來說集成過程比較順利,在此感謝Weex技術社區的力量,也希望此文能給后來者一些幫助。不過由于Weex開源時間比較短,整個生態圈還不太完善,在Weex開發的過程中也踩了一些坑,期待更多的Weex愛好者能為此貢獻自己的一份力量,讓Weex發揚光大,一統江湖!

 

來自:http://tech.dianwoda.com/2017/12/25/android-dian-wo-da-qi-shou-weexjie-ru-guo-cheng-xiang-shu/

 

 本文由用戶 yangyenan 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!