Weex Android SDK源码分析之界面渲染(上)
Posted 王永迪
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Weex Android SDK源码分析之界面渲染(上)相关的知识,希望对你有一定的参考价值。
前言
首先感谢阿里巴巴团队对移动端跨三端与动态化做出的杰出贡献,阿里在6月初,彻底开放了weex android与ios端内测,最近已使用一周有余,效果果然达到了write once,run everywhere!而且运行效果可以与原声媲美,并且virtual dom的加入更加优化了性能问题,切对native扩展等提供了很好的预留,目前可以采用组件形式与全页形式进行集成,接下来我给大家介绍下weex在android端的工作原理及代码分析。
Weex SDK目录结构
源码分析
初始化操作
BaseApplication 初始化SDK 引擎
WXSDKEngine.init(this, null, null, new ImageAdapter(), null);
@Deprecated
public static void init(Application application, IWXUserTrackAdapter utAdapter, String framework)
synchronized (mLock)
if (init)
return;
init = true;
WXEnvironment.sApplication = application;
WXEnvironment.JsFrameworkInit = false;
WXSoInstallMgrSdk.init(application);
WXEnvironment.sSupport = WXSoInstallMgrSdk.initSo(V8_SO_NAME, 1, utAdapter);
if (!WXEnvironment.sSupport)
return;
WXSDKManager.getInstance().initScriptsFramework(framework);
register();
new AsyncTask<Application, Void, Void>()
@Override
protected Void doInBackground(Application... params)
try
Class cls = Class.forName("com.taobao.weex.WXPrettyFish");
Method m = cls.getMethod("init", new Class[]Application.class);
m.invoke(cls, new Object[]params[0]);
catch (Exception e)
WXLogUtils.d("WXPrettyFish not found!");
return null;
.execute(application);
WXSDKEngine初始化了三件事:
1、初始化so库文件,渲染逻辑、脚本业务框架等都封装在了这里;
2、初始化initScriptsFramework : 初始化脚本框架;
private void invokeInitFramework(Message msg)
String framework = "";
if (msg.obj != null)
framework = (String) msg.obj;
if (!mInit)
if (TextUtils.isEmpty(framework))
if (WXEnvironment.isApkDebugable())
WXLogUtils.d("framework from assets");
framework = WXFileUtils.loadFileContent("main.js", WXEnvironment.getApplication());
if (TextUtils.isEmpty(framework))
mInit = false;
return;
try
long start = System.currentTimeMillis();
if(mWXBridge.initFramework(framework, assembleDefaultOptions())==INIT_FRAMEWORK_OK)
WXEnvironment.sJSLibInitTime = System.currentTimeMillis() - start;
WXLogUtils.renderPerformanceLog("initFramework", WXEnvironment.sJSLibInitTime);
mInit = true;
execRegisterFailTask();
WXEnvironment.JsFrameworkInit = true;
else
WXLogUtils.e("[WXBridgeManager] invokeInitFramework Executejavascript fail");
catch (Throwable e)
WXLogUtils.e("[WXBridgeManager] invokeInitFramework " + e.getCause());
3、register 操作,初始化weex组件与module;
IndexActivity
private void renderWX()
Rect outRect = new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(outRect);
if (instance != null)
instance.destroy();
instance = null;
instance = new WXSDKInstance(this);
instance.registerRenderListener(this);
Map<String, Object> options = new HashMap<>();
options.put("bundleUrl", WEEX_INDEX_URL);
instance.renderByUrl(TAG, WEEX_INDEX_URL, options, null, ScreenUtil.getDisplayWidth(this),
ScreenUtil.getDisplayHeight(this), WXRenderStrategy.APPEND_ASYNC);
首先看这个方法,可以在activity oncreate中被调用,可以清楚的看到,注册了渲染监听器,以及传入了当前屏幕的宽高及url,可以猜测weex的适配方案采用的是百分比方案。
WXSDKInstance renderByUrl
public void renderByUrl(final String pageName, final String url, Map<String, Object> options, final String jsonInitData, final int width, final int height, final WXRenderStrategy flag)
if (options == null)
options = new HashMap<>();
if (!options.containsKey("bundleUrl"))
options.put("bundleUrl", url);
Uri uri=Uri.parse(url);
if(uri!=null && TextUtils.equals(uri.getScheme(),"file"))
render(pageName, WXFileUtils.loadFileContent(assembleFilePath(uri), mContext),options,jsonInitData,width,height,flag);
return;
IWXHttpAdapter adapter=WXSDKManager.getInstance().getIWXHttpAdapter();
if (adapter == null)
adapter = new DefaultWXHttpAdapter();
WXRequest wxRequest = new WXRequest();
wxRequest.url = url;
if (wxRequest.paramMap == null)
wxRequest.paramMap = new HashMap<String, Object>();
wxRequest.paramMap.put("user-agent", WXHttpUtil.assembleUserAgent());
adapter.sendRequest(wxRequest, new WXHttpListener(pageName, options, jsonInitData, width, height, flag, System.currentTimeMillis()));
mWXHttpAdapter = adapter;
方法内调用了httpadapter进行加载url,并且拼装了user-agent header参数;
DefaultWXHttpAdapter 网络处理
public class DefaultWXHttpAdapter implements IWXHttpAdapter
@Override
public void sendRequest(final WXRequest request, final OnHttpListener listener)
if (listener != null)
listener.onHttpStart();
WXHttpManager.getInstance().execute(new Runnable()
@Override
public void run()
WXResponse response = new WXResponse();
try
HttpURLConnection connection = openConnection(request, listener);
int responseCode = connection.getResponseCode();
response.statusCode = String.valueOf(responseCode);
if (responseCode == 200 || responseCode == 202)
response.originalData = readInputStream(connection.getInputStream(), listener).getBytes();
else
response.errorMsg = readInputStream(connection.getErrorStream(), listener);
if (listener != null)
listener.onHttpFinish(response);
catch (IOException e)
e.printStackTrace();
response.errorCode="-1";
response.errorMsg=e.getMessage();
if(listener!=null)
listener.onHttpFinish(response);
);
/**
* Opens an @link HttpURLConnection with parameters.
*
* @param request
* @param listener
* @return an open connection
* @throws IOException
*/
private HttpURLConnection openConnection(WXRequest request, OnHttpListener listener) throws IOException
URL url = new URL(request.url);
HttpURLConnection connection = createConnection(url);
connection.setConnectTimeout(request.timeoutMs);
connection.setReadTimeout(request.timeoutMs);
connection.setUseCaches(false);
connection.setDoInput(true);
if (!TextUtils.isEmpty(request.method))
connection.setRequestMethod(request.method);
if (request.paramMap != null)
Set<String> keySets = request.paramMap.keySet();
for (String key : keySets)
connection.addRequestProperty(key, request.paramMap.get(key).toString());
if (request.body != null)
if (listener != null)
listener.onHttpUploadProgress(0);
connection.setDoOutput(true);
connection.setRequestMethod("POST");
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
out.write(request.body.getBytes());
out.close();
if (listener != null)
listener.onHttpUploadProgress(100);
return connection;
private String readInputStream(InputStream inputStream, OnHttpListener listener)
StringBuilder builder = new StringBuilder();
try
int fileLen = inputStream.available();
BufferedReader localBufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] data = new char[2048];
int len = -1;
while ((len = localBufferedReader.read(data)) > 0)
builder.append(data, 0, len);
if (listener != null && fileLen > 0)
listener.onHttpResponseProgress((builder.length() / fileLen) * 100);
localBufferedReader.close();
try
inputStream.close();
catch (IOException e)
WXLogUtils.e("DefaultWXHttpAdapter: " + WXLogUtils.getStackTrace(e));
catch (IOException e)
e.printStackTrace();
return builder.toString();
/**
* Create an @link HttpURLConnection for the specified @code url.
*/
protected HttpURLConnection createConnection(URL url) throws IOException
return (HttpURLConnection) url.openConnection();
其实就是一个封装的简单的网络请求工具类,把请求下来的json数据回调给WXSDKInstance,不用多说什么~
WXSDKInstance render
public void render(String pageName, String template, Map<String, Object> options, String jsonInitData, int width, int height, WXRenderStrategy flag)
if (mRendered || TextUtils.isEmpty(template))
return;
if(options==null)
options=new HashMap<>();
if(WXEnvironment.sDynamicMode && !TextUtils.isEmpty(WXEnvironment.sDynamicUrl) && options!=null && options.get("dynamicMode")==null)
options.put("dynamicMode","true");
renderByUrl(pageName,WXEnvironment.sDynamicUrl,options,jsonInitData,width,height,flag);
return;
mWXPerformance.pageName = pageName;
mWXPerformance.JSTemplateSize = template.length() / 1024;
mRenderStartTime = System.currentTimeMillis();
mRenderStrategy = flag;
mGodViewWidth = width;
mGodViewHeight = height;
mInstanceId = WXSDKManager.getInstance().generateInstanceId();
WXSDKManager.getInstance().createInstance(this, template, options, jsonInitData);
mRendered = true;
进行view的创建初始化~
WXSDKManager createInstance
void createInstance(WXSDKInstance instance, String code, Map<String, Object> options, String jsonInitData)
mWXRenderManager.createInstance(instance, instance.getInstanceId());
mBridgeManager.createInstance(instance.getInstanceId(), code, options, jsonInitData);
1、将json数据与instanceId添加到renderManager中;
private ConcurrentHashMap<String, WXRenderStatement> mRegistries;
public void createInstance(WXSDKInstance instance, String instanceId)
mRegistries.put(instanceId, new WXRenderStatement(instance, instanceId));
2、使用bridge桥接管理器进行UI绘制;
public void createInstance(final String instanceId, final String template,
final Map<String, Object> options, final String data)
if (!WXEnvironment.sSupport || TextUtils.isEmpty(instanceId)
|| TextUtils.isEmpty(template) || mJSHandler == null)
WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
if (instance != null)
instance.onRenderError(WXRenderErrorCode.WX_CREATE_INSTANCE_ERROR, "createInstance fail!");
return;
post(new Runnable()
@Override
public void run()
long start = System.currentTimeMillis();
invokeCreateInstance(instanceId, template, options, data);
final long totalTime = System.currentTimeMillis() - start;
WXSDKManager.getInstance().postOnUiThread(new Runnable()
@Override
public void run()
WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
if (instance != null)
instance.createInstanceFinished(totalTime);
, 0);
WXLogUtils.renderPerformanceLog("invokeCreateInstance", totalTime);
, instanceId);
private void invokeCreateInstance(String instanceId, String template,
Map<String, Object> options, String data)
if (mMock)
mock(instanceId);
else
if (!mInit)
WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
if (instance != null)
instance.onRenderError(WXRenderErrorCode.WX_CREATE_INSTANCE_ERROR, "createInstance "
+ "fail!");
String err = "[WXBridgeManager] invokeCreateInstance: framework.js uninitialized.";
WXErrorCode.WX_ERR_INVOKE_NATIVE.appendErrMsg(err);
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_ERR_INVOKE_NATIVE);
WXLogUtils.e(err);
return;
try
if (WXEnvironment.isApkDebugable())
WXLogUtils.d("createInstance >>>> instanceId:" + instanceId
+ ", options:"
+ WXJsonUtils.fromObjectToJSONString(options)
+ ", data:" + data);
WXJSObject instanceIdObj = new WXJSObject(WXJSObject.String,
instanceId);
WXJSObject instanceObj = new WXJSObject(WXJSObject.String,
template);
WXJSObject optionsObj = new WXJSObject(WXJSObject.JSON,
options == null ? ""
: WXJsonUtils.fromObjectToJSONString(options));
WXJSObject dataObj = new WXJSObject(WXJSObject.JSON,
data == null ? "" : data);
WXJSObject[] args = instanceIdObj, instanceObj, optionsObj,
dataObj;
mWXBridge.execJS(instanceId, null, METHOD_CREATE_INSTANCE, args);
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_SUCCESS);
catch (Throwable e)
WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(instanceId);
if (instance != null)
instance.onRenderError(WXRenderErrorCode.WX_CREATE_INSTANCE_ERROR,
"createInstance failed!");
String err = "[WXBridgeManager] invokeCreateInstance " + e.getCause();
WXErrorCode.WX_ERR_INVOKE_NATIVE.appendErrMsg(err);
commitJSBridgeAlarmMonitor(instanceId, WXErrorCode.WX_ERR_INVOKE_NATIVE);
WXLogUtils.e(err);
WXBridge
class WXBridge implements IWXBridge
private static final String TAG = "WXBridge";
/**
* Init JSFrameWork
*
* @param framework assets/main.js
*/
public native int initFramework(String framework, WXParams params);
/**
* Execute JavaScript function
*
* @param instanceId
* @param namespace default global
* @param function function string name
* @param args WXJSObject array
*/
public native int execJS(String instanceId, String namespace, String function, WXJSObject[] args);
/**
* JavaScript uses this methods to call Android code
*
* @param instanceId
* @param tasks
* @param callback
*/
public void callNative(String instanceId, String tasks, String callback)
WXBridgeManager.getInstance().callNative(instanceId, tasks, callback);
/**
* Report JavaScript error.
*
* @param instanceId
* @param func exception function
* @throws String exception
*/
public void reportJSException(String instanceId, String func, String exception)
WXBridgeManager.getInstance().reportJSException(instanceId, func, exception);
public void setTimeoutNative(String callbackId, String time)
WXBridgeManager.getInstance().setTimeout(callbackId, time);
作用: execJS 调用 so库方法执行JS脚本,进行UI渲染;
总结
流程大概就是这样,只是按照渲染流程进行分析,但是目前c++代码并没有开源,只能追到这里,等开源后会将后续分析加入,希望能够对大家有所帮助~ 谢谢!!!
以上是关于Weex Android SDK源码分析之界面渲染(上)的主要内容,如果未能解决你的问题,请参考以下文章
Weex Android SDK源码分析之Module(navigator)
Weex Android SDK源码分析之Module(modal)
Weex Android SDK源码分析之Module(webview)
Weex Android SDK源码分析之Module(animation)