點我達騎手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/