前言
最近开始试水Weex开发,使用这么长一段时间,感觉写Weex还是非常方便的。作为一个Android开发,免不了要追查一下weex的sdk源码。今天,就以Weex SDK for Android为例,分析SDK的
认识Weex SDK
源码https://github.com/alibaba/weex/tree/dev/android
整体分析下拉,按照js文件的渲染过程,绘制出了下面架构图:
WEEX文件渲染过程
为了更加详细的说明整个渲染过程,我对源码进行了分析。并结合示例,进行了日志分析;比如,我们要开发如下一个简单的组件(红色方框内):
那么,我们的wxc-title.we源码为:
<!-- wxc-title.we created by mochuan.zhb-->
<template>
<div class="container">
<image class="image" src="{
{
item.pic}}"></image>
<text class="text">{
{
item.name}}</text>
</div>
</template>
<style>
.container {
position: relative;
flex-direction: row;
width: 750px;
height: 60px;
align-items: center;
}
.image {
margin-left: 100px;
width: 45px;
height: 45px;
}
.text {
margin-left: 10px;
font-size: 28px;
color: #444444;
}
</style>
<script>
module.exports = {
data: {
item: {
pic: '//img.alicdn.com/tfs/TB1AEcQNXXXXXX8XXXXXXXXXXXX-50-50.png',
name: '当地玩乐'
}
},
methods: {
}
}
</script>
上述.we文件经过weex编译之后,生成的js文件,经过格式化如下:
...
([function (module, exports) {
module.exports = {
"type": "div",
"classList": [
"container"
],
"children": [
{
"type": "image",
"classList": [
"image"
],
"attr": {
"src": function () {
return this.item.pic
}
}
},
{
"type": "text",
"classList": [
"text"
],
"attr": {
"value": function () {
return this.item.name
}
}
}
]
}
}, function (module, exports) {
module.exports = {
"container": {
"position": "relative",
"flexDirection": "row",
"width": 750,
"height": 60,
"alignItems": "center"
},
"image": {
"marginLeft": 100,
"width": 45,
"height": 45
},
"text": {
"marginLeft": 10,
"fontSize": 28,
"color": "#444444"
}
}
}, function (module, exports) {
module.exports = function (module, exports, __weex_require__) {
'use strict';
module.exports = {
data: function () {
return {
item: {
pic: '//img.alicdn.com/tfs/TB1AEcQNXXXXXX8XXXXXXXXXXXX-50-50.png',
name: '当地玩乐'
}
}
},
methods: {}
};
}
}
]);
上述分别使用了三个function,对template、style和script进行了封装;那么,这个文件是怎么被weex sdk执行并解析,最终生成结构化的View的呢?
渲染过程
时序图1:
从扫码开始,首先经历如下过程;依次经过readerPage,createInstance,一直到WXBridge的exeJs方法;也就是说,最终,Java通过调用native的exeJs方法,来执行js文件的。
时序图2:
紧接着时序图1:执行到JNI层的Java_com_taobao_weex_bridge_WXBridge_execJS方法;
然后js通过native调用WXBridge的callNative方法,达到js调用Java代码的目的;
JNI层的部分代码如下:
jint Java_com_taobao_weex_bridge_WXBridge_execJS(JNIEnv *env, jobject this1, jstring jinstanceid,
jstring jnamespace, jstring jfunction,
jobjectArray jargs) {
v8::HandleScope handleScope;
v8::Isolate::Scope isolate_scope(globalIsolate);
v8::Context::Scope ctx_scope(V8context);
v8::TryCatch try_catch;
int length = env->GetArrayLength(jargs);
v8::Handle<v8::Value> obj[length];
jclass jsObjectClazz = (env)->FindClass("com/taobao/weex/bridge/WXJSObject");
for (int i = 0; i < length; i++) {
jobject jArg = (env)->GetObjectArrayElement(jargs, i);
jfieldID jTypeId = (env)->GetFieldID(jsObjectClazz, "type", "I");
jint jTypeInt = env->GetIntField(jArg, jTypeId);
jfieldID jDataId = (env)->GetFieldID(jsObjectClazz, "data", "Ljava/lang/Object;");
jobject jDataObj = env->GetObjectField(jArg, jDataId);
if (jTypeInt == 1) {
jclass jDoubleClazz = (env)->FindClass("java/lang/Double");
jmethodID jDoubleValueId = (env)->GetMethodID(jDoubleClazz, "doubleValue", "()D");
jdouble jDoubleObj = (env)->CallDoubleMethod(jDataObj, jDoubleValueId);
obj[i] = v8::Number::New((double) jDoubleObj);
env->DeleteLocalRef(jDoubleClazz);
} else if (jTypeInt == 2) {
jstring jDataStr = (jstring) jDataObj;
obj[i] = jString2V8String(env, jDataStr);
} else if (jTypeInt == 3) {
v8::Handle<v8::Value> jsonObj[1];
v8::Handle<v8::Object> global = V8context->Global();
json = v8::Handle<v8::Object>::Cast(global->Get(v8::String::New("JSON")));
json_parse = v8::Handle<v8::Function>::Cast(json->Get(v8::String::New