weex eros是基于alibaba weex框架進行二次封裝的客戶端跨平臺開發框架,主要是為前端開發者(可以不用熟悉客戶端開發)提供的一站式客戶端app開發解決方案。官網地址為:https://bmfe.github.io/eros-docs/#/。為了方便前端開發者和客戶端開發者了解框架的原理和遇到問題時更快的定位,我將從源碼的角度解析功能。
eros主要功能介紹
eros cli是eros開發腳手架,可以用來生成eros項目,提供了編譯,打包,運行,更新等一系列開發功能。eros widget在js端提供了vue實例中可以方便調用的許多原生擴展功能(請求,路由,事件發布訂閱,本地存儲等)。eros module在原生端對eros widget功能進行真正實現。eros component在原生端實現的擴展組件eros通過appboard配置實現多頁面的公共代碼js bundle抽出。eros通過mediator實現多頁面內存共享。
首先從eros widget源碼開始分析
eros widget提供了請求,路由,本地儲存,原生導航,發布訂閱等功能,下面將從請求功能去分析eros widget源碼實現。
在eors官網中介紹的請求的定義是axios,前端的開發者看到這個會覺得很熟悉,因為有個著名的前端開源Http請求框架也叫作這個名字,我剛開始看到這個也是非常興奮,因為axios開源框架功能很強大,所以覺得基于業務的Http請求封裝很easy,可以直接復用了,但是用了之后發現不是那么回事,后面研究了源碼之后,才知道eros只是把請求功能叫axios這個名字,但是跟開源框架axios背后實現原理,實現功能完全不一樣!所以大家不要誤解了!
我們先從Js調用端開始分析:
通過eros-cli創建項目之后,我們可以看到關于請求的配置有兩個地方:
在config/index.js文件中我們可以看到就做了一個事情:new widget()創建了一個widget對象。new widget是eros widget功能的入口,在new widget()時通過傳參完成了widget相關功能的配置,圖中ajax對象正是對widget axios功能的配置。通過require引用找到Widget定義的地方,分析widget源碼,也就是eros widget庫的相關代碼。
// 配置方法
import
'./src/mixins.js'import
'./src/font.js'
// 彈窗
import
'./src/notice.js'
// 獲取地理位置
import
'./src/geo.js'
// 獲取相機信息
import
'./src/camera.js'
// 圖片操作相關
import
'./src/image.js'
// 設置導航
import
'./src/nav.js'
// 支付相關(已抽離第三方插件)
// import
'./src/pay.js'
// bindingx
import
'./src/bindingx.js'
// 存儲相關
import
'./src/storage.js'
// 全局事件
import
'./src/events.js'
// 分享(已抽離第三方插件)
// import
'./src/share.js'
// 工具方法
import
'./src/tools.js'import
'./src/coms.js'// 路由
import Router from
'./src/router.js'
// 發送請求
import Axios from
'./src/axios.js'let instance = null
export default class Widget {constructor ({ router, ajax }) {
if (!instance) {//這里是我們需要關注的,這里創建的請求對象,并且掛載在Vue里Vue.use(new Axios(ajax))Vue.use(new Router(router))instance = this}
return instance}
}
2.代碼我們可以很清楚的看到,整個widget的功能都是在這里被引入的,相關的配置信息也是通過widget的構造函數傳到對應功能模塊的。我們可以看到我們分析的Axios定義就在./src/axios.js這個文件里。繼續往下分析axios.js代碼:
import _isFunction from
'lodash/isFunction'
const bmAxios = weex.requireModule(
'bmAxios')//請求的真正執行者,這里對應一個weex原生自定義module,注冊名字叫bmAxios
export default class Axios {//構造函數,通過外部傳遞請求相關配置參數constructor ({ timeout, apis, baseUrl =
'', requestHandler, responseHandler }) {this.apis = apis //apis是配置請求別名的到路徑的映射,別名通過它可以找到真實路徑this.timeout = timeout//請求的超時時間this.baseUrl = baseUrl//請求的基礎urlthis.requestHandler = requestHandler//請求的攔截器this.responseHandler = responseHandler//響應的攔截器
return this}//vue自定義組件安裝函數,前面說的vue.use()會調用該函數進行自定義組件的添加install (Vue) {/*** Contributor: Eric Xiao.* Description: extend promise.* Eros thanks every contributor.*/Promise.prototype.finally =
function (callback) {const P = this.constructor;
return this.then(value => P.resolve(callback()).then(() => value),reason => P.resolve(callback()).then(() => { throw reason }));};Promise.prototype.done =
function (onFulfilled, onRejected) {this.then(onFulfilled, onRejected).catch(
function (reason) {// Throw a global error
setTimeout(() => { throw reason }, 0);});};const self = this//此處是在vue原型中掛載一個
$fetch函數,掛載之后在vue實例中可以通過this.
$fetch進行調用該函數,該函數是eros http請求的調用函數,支持多種http請求方式。Vue.prototype.
$fetch = (options) => {
return new Promise((resolve, reject) => {//判斷requestHandle是否是函數,如果是函數則先執行requestHandle對請求進行處理,處理完成后再由handleAxios處理,否則直接由handleAxios處理。
if (_isFunction(self.requestHandler)) {self.requestHandler(options, () => { //統一的http功能處理handleAxios(options, resolve, reject) })}
else {//統一的http功能處理handleAxios(options, resolve, reject)}})}//vue原型上提供this.
$get發起get請求的調用,邏輯同上Vue.prototype.
$get = (options) => {options.method =
'GET'return new Promise((resolve, reject) => {
if (_isFunction(self.requestHandler)) {self.requestHandler(options, () => { handleAxios(options, resolve, reject) })}
else {handleAxios(options, resolve, reject)}})}//vue原型上提供this.
$post發起Post請求的調用,邏輯同上Vue.prototype.
$post = (options) => {options.method =
'POST'return new Promise((resolve, reject) => {
if (_isFunction(self.requestHandler)) {self.requestHandler(options, () => { handleAxios(options, resolve, reject) })}
else {handleAxios(options, resolve, reject)}})}//請求js端真正處理者
function handleAxios (options, resolve, reject) {//首先對請求參數進行解析const { name, url, data, method, header, params } = options//通過name去apis配置里找真正請求路徑const requestPath = name && pathFormater(name, params)//這里才是真正的請求功能的發起者,通過eros自定義weex的bmAxios原生模塊真正發起請求,通過傳遞回調函數給原生從而在請求執行完之后獲取到請求結果,再由promise對結果進行分發,如果自己定義了responseHandler函數,則由調用者在responseHandler函數中根據http status和業務code去分發請求結果bmAxios.fetch({url: url || (self.baseUrl requestPath),data: data || {},method: method && method.toUpperCase() ||
'GET',header: header || {},timeout: self.timeout || 30000}, (resData) => {// 統一的監控
if (_isFunction(self.responseHandler)) {self.responseHandler(options, resData, resolve, reject)}
else {resolve(resData)}})}//此函數是用來根據name去映射apis路徑,以及對路徑參數進行賦值替換
function pathFormater (name, params) {
let _path = self.apis[name]const matcher = _path.match(/[^{][a-zA-Z0-9] (?=\})/g)
if (matcher && matcher.length) {matcher.forEach(item => {
if (!params[item]) throw new Error(`you are using dynamic params, but
${item} not existed
in your params`)_path = _path.replace(`{
${item}}`, params[item] ||
'undefined')})}
return _path}}
}
3.通過上面的代碼分析我們知道了在vue中通過this.$fetch調用真正的js處理邏輯,實際上js只是對請求參數進行定義和簡單功能的封裝。真正實現http調用處還是在原生,這個原生是相對的,如果jsbundle是運行在android上則是通過android weex模塊去調用,如果運行在ios則通過ios weex模塊去調用。
下面分析eros android端源碼
首先找到android erosSdk中的 AxiosModule.java類文件。這個類里面定義了js端調用的相關方法。
package com.benmu.framework.extend.module;import com.benmu.framework.constant.WXConstant;
import com.benmu.framework.constant.WXEventCenter;
import com.benmu.framework.manager.ManagerFactory;
import com.benmu.framework.manager.impl.dispatcher.DispatchEventManager;
import com.benmu.framework.model.WeexEventBean;
import com.taobao.weex.annotation.JSMethod;
import com.taobao.weex.bridge.JSCallback;
import com.taobao.weex.common.WXModule;/*** Created by Carry on 17/1/16.*/public class AxiosModule extends WXModule {@JSMethod(uiThread =
false)public void fetch(String params, final JSCallback jsCallback) {WeexEventBean eventBean = new WeexEventBean();eventBean.setContext(mWXSDKInstance.getContext());eventBean.setKey( WXEventCenter.EVENT_FETCH);eventBean.setJsParams(params);eventBean.setJscallback(jsCallback);ManagerFactory.getManagerService(DispatchEventManager.class).getBus().post(eventBean);}//其他省略....
}
整個類看起來很簡單,跟js端bmAxios對應的方法就一個fetch(),里面有兩個參數,一個為js傳遞過來的請求參數,另外一個是js端的回調函數。我們可以看到方法的實現里面并沒有具體的執行邏輯,只是創建了一個叫做WeexEventBean的實體類,并把參數params和jsCallback等傳給了它,并通過類似bus的對象給post出去了。在這里說一下,所有的eros自定義module都是通過事件總線(android otto框架)的機制進行分發和功能處理的。WeexEventBean是對所有Module功能入口的統一封裝,它通過統一包裝所有的js調用請求,根據創建時定義的key,通過反射分發到對應key的功能類上進行處理。下面我們找到WeexEventBean事件的接收處。
package com.benmu.framework.event;import android.app.Activity;
import android.content.Context;
import android.text.TextUtils;
import com.benmu.framework.adapter.router.RouterTracker;
import com.benmu.framework.constant.WXEventCenter;
import com.benmu.framework.manager.ManagerFactory;
import com.benmu.framework.manager.impl.dispatcher.DispatchEventManager;
import com.benmu.framework.model.BaseEventBean;
import com.benmu.framework.model.WeexEventBean;
imporot cm.benmu.framework.utils.JsPoster;
import com.benmu.wxbase.EventGate;
import com.benmu.wxbase.EventGateFactory;
import com.squareup.otto.Subscribe;
import com.taobao.weex.WXSDKInstance;
import com.taobao.weex.bridge.JSCallback;import java.util.ArrayList;/*** Created by Carry on 2017/8/23.*/public class DispatchEventCenter {//這里DispatchEventCenter創建了一個單例對象private static DispatchEventCenter mInstance = new DispatchEventCenter();private
DispatchEventCenter() {}public static DispatchEventCenter
getInstance() {
return mInstance;}//這里對DispatchEventCenter對象進行注冊,注冊之后可以接收Bus分發的事件public void
register() {ManagerFactory.getManagerService(DispatchEventManager.class).getBus().register(this);}//這里對DispatchEventCenter對象進行解注,解注之后取消接收Bus分發的事件public void
unregister() {ManagerFactory.getManagerService(DispatchEventManager.class).getBus().unregister(this);}//這里是WeexEventBean事件的接收,所有eros module post出來的WeexEventBean類型對象都在這里接收之后進行轉發@Subscribepublic void onWeexEvent(WeexEventBean weexEventBean) {
if (weexEventBean == null)
return;Context context = safeContext(weexEventBean.getContext());
if (context == null)
return;String params = weexEventBean.getJsParams();switch (weexEventBean.getKey()) {
case WXEventCenter.EVENT_IMAGE_UPLOAD://這里就是我們要找的key為EVENT_FETCH的處理地方
case WXEventCenter.EVENT_FETCH://這里我們直接傳遞了一個class絕對路徑的string,此處的做法值得商榷。下面我們繼續看reflectionClazzPerform方法reflectionClazzPerform(
"com.benmu.framework.event.http.EventFetch", context, weexEventBean,
"", weexEventBean.getKey());
break;...中間省略default:reflectionClazzPerform(weexEventBean.getKey(), context, weexEventBean,
"");
break;}}//真正反射創建對象的調用邏輯在這個函數里private void reflectionClazzPerform(String clazzName, Context context, WeexEventBean weexEventBean, String errosMsg, String
type) {//這里EventGateFactory根據clazzName反射去創建對象,但是為啥對象是EventGate類型的呢,因為eros所有的Event都實現了EventGate接口,所以創建出來的對象都是EventGate實現類的對象。EventGate event = EventGateFactory.getEventGate(clazzName);String params = weexEventBean.getJsParams();
if (null != event) {//根據上面調用邏輯,
type為WXEventCenter.EVENT_FETCH,不為空,直接走
else邏輯
if (TextUtils.isEmpty(
type)) {event.perform(context, weexEventBean);}
else {//event.perform是所有實現EventGate接口的Event對象執行功能的入口,本文分析的是com.benmu.framework.event.http.EventFetch這個類,下面我去找EventFetch對象的perform方法。event.perform(context, weexEventBean,
type);}}
else {//如果找不到對應的EVENT處理類,則給js回調失敗處理
if (TextUtils.isEmpty(params)) {JsPoster.postFailed(weexEventBean.getJscallback());}
else {JsPoster.postFailed(errosMsg, weexEventBean.getJscallback());}}}}
通過DispatchEventCenter 類,我們把js端的調用真正的分發到了對應的事件類上進行處理,每個事件類名對應著一個js調用模塊的函數名。此處我們繼續分析:com.benmu.framework.event.http.EventFetch這個類:
package com.benmu.framework.event.http;import android.content.Context;
import android.text.TextUtils;
import android.widget.Toast;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.benmu.framework.constant.Constant;
import com.benmu.framework.constant.WXEventCenter;
import com.benmu.framework.http.okhttp.OkHttpUtils;
import com.benmu.framework.http.okhttp.callback.StringCallback;
import com.benmu.framework.http.okhttp.exception.CancelException;
import com.benmu.framework.http.okhttp.exception.HttpException;
import com.benmu.framework.http.okhttp.exception.IrregularUrlException;
import com.benmu.framework.http.okhttp.utils.L;
import com.benmu.framework.manager.ManagerFactory;
import com.benmu.framework.manager.impl.AxiosManager;
import com.benmu.framework.manager.impl.ImageManager;
import com.benmu.framework.manager.impl.ModalManager;
import com.benmu.framework.manager.impl.ParseManager;
import com.benmu.framework.manager.impl.PersistentManager;
import com.benmu.framework.manager.impl.dispatcher.DispatchEventManager;
import com.benmu.framework.model.AxiosGet;
import com.benmu.framework.model.AxiosPost;
import com.benmu.framework.model.AxiosResultBean;
import com.benmu.framework.model.UploadImageBean;
import com.benmu.framework.model.UploadResultBean;
import com.benmu.framework.model.WeexEventBean;
import com.benmu.framework.utils.JsPoster;
import com.benmu.framework.utils.TextUtil;
import com.benmu.wxbase.EventGate;
import com.lzy.imagepicker.bean.ImageItem;
import com.squareup.otto.Subscribe;
import com.taobao.weex.bridge.JSCallback;import java.util.ArrayList;import okhttp3.Call;/*** Created by Carry on 2017/8/16.*/public class EventFetch extends EventGate {private JSCallback mUploadAvatar;private Context mUploadContext;//根據上面分析執行到這里@Overridepublic void perform(Context context, WeexEventBean weexEventBean, String
type) {String params = weexEventBean.getJsParams();pe//此處
type為WXEventCenter.EVENT_FETCH,所以直接執行
if里面的fetch方法
if (WXEventCenter.EVENT_FETCH.equals(
type)) {fetch(params, context, weexEventBean.getJscallback());}
else if (WXEventCenter.EVENT_IMAGE_UPLOAD.equals(
type)) {uploadImage(params, context, weexEventBean.getJscallback());}}//js端fetch請求分發到這里public void fetch(String params, final Context context, final JSCallback jscallback) {//創建參數解析管理類ParseManager parseManager = ManagerFactory.getManagerService(ParseManager.class);//創建Axios執行管理類AxiosManager axiosManager = ManagerFactory.getManagerService(AxiosManager.class);//把js 參數解析成Json對象JSONObject object = parseManager.parseObject(params);//獲取請求的Urlfinal String mUrl = object.getString(
"url");Boolean noRepeat = object.getBoolean(
"noRepeat");//如果重復發了則取消上一個請求
if (noRepeat != null && noRepeat) {axiosManager.cancel(mUrl);}//此處提供了所有的restful請求方法,說明js端可以發起所有的restful請求,根據對應的method進行分發處理switch (object.getString(
"method")) {
case OkHttpUtils.METHOD.GET:AxiosGet axiosGet = parseManager.parseObject(params, AxiosGet.class);get(context, axiosManager, axiosGet, jscallback);
break;
case OkHttpUtils.METHOD.POST:AxiosPost axiosPost = parseManager.parseObject(params, AxiosPost.class);post(context, axiosManager, axiosPost, jscallback);
break;
case OkHttpUtils.METHOD.HEAD:AxiosGet axiosHead = parseManager.parseObject(params, AxiosGet.class);head(context, axiosManager, axiosHead, jscallback);
break;
case OkHttpUtils.METHOD.DELETE:AxiosPost axiosDelete = parseManager.parseObject(params, AxiosPost.class);delete(context, axiosManager, axiosDelete, jscallback);
break;
case OkHttpUtils.METHOD.PUT:AxiosPost axiosPut = parseManager.parseObject(params, AxiosPost.class);put(context, axiosManager, axiosPut, jscallback);
break;
case OkHttpUtils.METHOD.PATCH:AxiosPost axiosPatch = parseManager.parseObject(params, AxiosPost.class);patch(context, axiosManager, axiosPatch, jscallback);
break;}}//暫時只分析get請求,其他是一樣的。private void get(final Context context, AxiosManager axiosManager, AxiosGet axiosGet, finalJSCallback jscallback) {//此處只是調用axiosManager.get()方法,真正的http調用發起邏輯是在axiosManager類里面,通過給該方法傳遞StringCallback()回調獲取到http執行之后的結果,然后對結果進行解析之后回調到Js端。axiosManager.get(axiosGet.url, axiosGet.data, axiosGet.header, new
StringCallback() {@Overridepublic void onError(Call call, Exception e, int id) {//請求出現error之后的處理parseError(context, e, jscallback);}@Overridepublic void onResponse(String response, int id) {//請求成功之后的處理parseResponse(response, jscallback, code);}}, axiosGet.url, axiosGet.timeout);}//請求錯誤的解析private void parseError(Context context, Exception e, JSCallback callback) {
if (e instanceof CancelException) {//request canceledModalManager.BmLoading.dismissLoading(context);
return;}AxiosResultBean bean = new AxiosResultBean();
if (e instanceof HttpException) {HttpException httpException = (HttpException) e;bean.status = httpException.getmErrorCode();bean.errorMsg = httpException.getmErrorMessage();}
else if (e instanceof IrregularUrlException) {IrregularUrlException irregularUrlException = (IrregularUrlException) e;bean.status = 9;bean.errorMsg = irregularUrlException.getmErrosMeeage();}//請求錯誤之后給js端回調,回調的data為AxiosResultBean,到這里js——>java——>js 整個調用過程結束了
if (callback != null) {callback.invoke(bean);}}//請求正常的解析private void parseResponse(String response, JSCallback callBack, int code) {try {AxiosResultBean bean = new AxiosResultBean();
if (callBack != null && !TextUtils.isEmpty(response)) {bean.status = code;bean.errorMsg =
"";bean.data = JSON.parse(response);//請求正常返回之后給js端回調,回調的data為AxiosResultBean,到這里js——>java——>js 整個調用過程結束了callBack.invoke(bean);}} catch (Exception e) {e.printStackTrace();L.e(
"json 解析錯誤");AxiosResultBean bean = new AxiosResultBean();bean.status = -1;bean.errorMsg =
"json 解析錯誤";
if (callBack != null) {//請求錯誤之后給js端回調,回調的data為AxiosResultBean,到這里js——>java——>js 整個調用過程結束了callBack.invoke(bean);}}}
}
通過EventFetch源碼,我們知道EventFetch只是做了請求參數的解析,根據請求http method進行對應分發處理,并且對http請求之后的結果進行封裝之后發起jsCallback處理,jsCallback調用之后,整個js——>java——>js調用過程結束。但是真正http執行邏輯還在AxiosManager里面,下面我們繼續分析AxiosManager類:
package com.benmu.framework.manager.impl;import android.content.Context;
import android.net.Uri;
import android.text.TextUtils;import com.benmu.framework.BMWXEnvironment;
import com.benmu.framework.extend.adapter.WeexOkhttp3Interceptor;
import com.benmu.framework.http.Api;
import com.benmu.framework.http.BMPersistentCookieStore;
import com.benmu.framework.http.okhttp.OkHttpUtils;
import com.benmu.framework.http.okhttp.builder.GetBuilder;
import com.benmu.framework.http.okhttp.builder.OkHttpRequestBuilder;
import com.benmu.framework.http.okhttp.builder.OtherRequestBuilder;
import com.benmu.framework.http.okhttp.builder.PostFormBuilder;
import com.benmu.framework.http.okhttp.callback.FileCallBack;
import com.benmu.framework.http.okhttp.callback.StringCallback;
import com.benmu.framework.http.okhttp.cookie.CookieJarImpl;
import com.benmu.framework.http.okhttp.exception.IrregularUrlException;
import com.benmu.framework.http.okhttp.log.LoggerInterceptor;
import com.benmu.framework.manager.Manager;
import com.benmu.framework.manager.ManagerFactory;
import com.benmu.framework.manager.impl.dispatcher.DispatchEventManager;
import com.benmu.framework.model.UploadResultBean;
import com.benmu.framework.utils.AppUtils;
import com.benmu.framework.utils.DebugableUtil;import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;import okhttp3.Call;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;/*** Created by Carry on 2017/8/7. default implement by okHttpUtils*/public class AxiosManager extends Manager {private static final String DEFAULT_MEDIATYPE =
"application/json; charset=utf-8";private static final String DEFAULT_HOST =
"http://app.weex-eros.com";//創建OkHttpClient對象public OkHttpClient createClient(Context context, long timeout) {CookieJarImpl cookieJar = new CookieJarImpl(new BMPersistentCookieStore(context));OkHttpClient.Builder builder = new OkHttpClient.Builder().addInterceptor(new LoggerInterceptor(
"TAG"))//接口超時時間 默認3000毫秒.connectTimeout(timeout == 0 ? 3000L : timeout, TimeUnit.MILLISECONDS).readTimeout(timeout == 0 ? 30000L : timeout, TimeUnit.MILLISECONDS).cookieJar(cookieJar);
if (DebugableUtil.isDebug()) {builder.addNetworkInterceptor(new WeexOkhttp3Interceptor());}
return builder.build();}public void initClient(Context context) {OkHttpUtils.initClient(createClient(context, 0));}public void cancel(Object tag) {}//上面EventFetch get請求調用到這里,這里是真正發起請求的地方,最終通過okhttpUtil發送的請求。public void get(String mUrl, HashMap<String, String> params, HashMap<String, String> header,StringCallback stringCallback, Object tag, long timeout) {mUrl = safeUrl(mUrl);
if (mUrl == null) {
if (stringCallback != null) {stringCallback.onError(null, new IrregularUrlException(
"url不合法"), 0);}
return;}
if (header == null) {header = new HashMap<>();}
setTimeout(timeout);//此處使用的是對okhttp進行封裝的OkHttpUtils框架發送的get請求,并通過stringCallback回調真正的請求結果。GetBuilder builder = OkHttpUtils.get().url(mUrl).tag(tag).headers(header);generateParams(params, builder);builder.build().execute(stringCallback);}private void
setTimeout(long timeout) {
if (timeout != 0) {OkHttpUtils.getInstance().updateHttpClient(createClient(BMWXEnvironment.mApplicationContext, timeout));}}private RequestBody createRequestBodyByMediaType(Map<String, String> header, String content) {
if (header != null && !TextUtils.isEmpty(header.get(
"Content-Type"))) {String s = header.get(
"Content-Type");MediaType mediaType = null;try {mediaType = MediaType.parse(s);} catch (Exception e) {e.printStackTrace();}
if (mediaType == null) {mediaType = MediaType.parse(DEFAULT_MEDIATYPE);}
return RequestBody.create(mediaType, content);}
return RequestBody.create(MediaType.parse(DEFAULT_MEDIATYPE), content);}private String safeUrl(String origin) {
if (origin == null)
return null;Uri parse = Uri.parse(origin);StringBuilder builder = new StringBuilder();Uri requestHost = Uri.parse(TextUtils.isEmpty(Api.BASE_URL) ? DEFAULT_HOST : Api.BASE_URL);
if (TextUtils.isEmpty(parse.getScheme())) {builder.append(requestHost.getScheme());}
else {builder.append(parse.getScheme());}builder.append(
"://");
if (TextUtils.isEmpty(parse.getHost())) {builder.append(requestHost.getHost());}
else {builder.append(parse.getHost());}
if (parse.getPort() != -1) {builder.append(
":").append(parse.getPort());}
if (!TextUtils.isEmpty(parse.getPath())) {builder.append(origin.substring(origin.indexOf(parse.getPath())));}String finalUrl = builder.toString();
return HttpUrl.parse(finalUrl) == null ? null : builder.toString();}private void generateParams(Map<String, String> params, OkHttpRequestBuilder builder) {
if (params == null) {params = new HashMap<>();}
if (builder instanceof GetBuilder) {GetBuilder getBuilder = (GetBuilder) builder;
for (Map.Entry<String, String> entry : params.entrySet()) {getBuilder.addParams(entry.getKey().trim(), entry.getValue().trim());}}}/*** 組合返回給前端的Js 數據*/public UploadResultBean resultBean(int code, String message, ArrayList<String> arrayList) {UploadResultBean uploadResultBean = new UploadResultBean();uploadResultBean.resCode = code;uploadResultBean.msg = message;uploadResultBean.setData(arrayList);
return uploadResultBean;}
}
AxiosManager使用的是OkhttpUtils發起的http請求,它對okhttpclient進行的一些配置和攔截。至此,整個js端axios.fetch發起的調用分析結束。
總結
整個eros js端和原生功能封裝的比較完整,基本上是按照weex原生功能風格去擴展的。對于前端同學進行純weex項目開發來說,eros提供了一站式解決方案還是比原生weex開發方便很多。但是也有一些不足的地方,比如說在js 端在非Vue實例中調用widget功能(儲存功能可能js里調用)還是稍微有點不方便,需要自己去擴展。還有提供的http模塊可配置性和攔截器功能比原生js http框架弱很多,對于復雜的js請求處理起來很別扭,需要自己擴展等等,android原生端實現模塊功能切分的比較清晰,不過感覺整個調用邏輯有點繞,還有就是通過絕對路徑Key去反射創建對象這個做法有隱患。當然,能夠在weex原生的基礎上擴展出來這么多功能,還是比較贊的,很多地方還是值得學習的!
后記
下次分析一下eros是如何在weex多頁應用中插入js widget功能,多頁應用中如何在js端進行全局生命周期監聽和全局配置處理。
更多專業前端知識,請上
【猿2048】www.mk2048.com
總結
以上是生活随笔為你收集整理的weex eros框架源码解析的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。