You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@weex.apache.org by xi...@apache.org on 2018/12/20 06:10:11 UTC

[incubator-weex] branch master updated: * [Android][iOS][C++] Add eagle version of data-render (#1937)

This is an automated email from the ASF dual-hosted git repository.

xifang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-weex.git


The following commit(s) were added to refs/heads/master by this push:
     new a11a9dc  * [Android][iOS][C++] Add eagle version of data-render (#1937)
a11a9dc is described below

commit a11a9dc8280764fa66f99dcb3593ebb54f510cf8
Author: YorkShen <sh...@gmail.com>
AuthorDate: Thu Dec 20 14:10:06 2018 +0800

    * [Android][iOS][C++] Add eagle version of data-render (#1937)
    
    * [core] add vcomponent diff
    
    * [core] support component ref finder
    
    * [core][data_render] support class binding
    
    * [core][data_render] add event support
    
    * [core][data_render] support value array of attr parser
    
    * [core][data_render] support vcomponent lifecycle and update from js
    
    * [core][data_render] support event
    
    * [iOS] add js binding on iOS
    
    * [core][eagle] fix codegen prefix invalid problem
    
    * [iOS] add createinstance to execute js
    
    * [core] add http_module
    
    * [core][eagle] fix event params
    
    * [eagle] fix repeat bug
    
    * [iOS] add requestHandle to download js
    
    * [iOS] fix weexsdk compile error
    
    * [iOS] fix weexsdk compile error
    
    * [Android] make WXHttpListener be in common use
    
    * [core][eagle] support httpmodule in android
    
    * [eagle] support binding style and computed
    
    * [eagle] fix bugs
    
    * [Android] fix update styles bug when only border change
    
    * [Android] do not set the same text repeatedly
    
    * [Android] fix boxshadow not change size when view size changed
    
    * * [Android] Update URL render rule
    
    1. __data_render==true for WXRenderStrategy.DATA_RENDER
    2. __eagle==true for WXRenderStrategy.DATA_RENDER_BINARY
    3. others for WXRenderStrategy.APPEND_ASYNC
    
    * [core] support javascript binding on iOS
    
    * [iOS] update js framework
    
    * [core] fix click event error on eagle
    
    * [core] fix crash when data is null on eagle
    
    * [core] fix crash when data array are null on eagle
    
    * * [Android] Update libweexjss for updateComponentData.
    
    * [core] fix bool type equre operator error
    
    * [core] support js file cache
    
    * [iOS] fix data null error
    
    * [iOS] support bundleUrl on eagle
    
    * [core] fix crash when root_node is null
    
    * * [Android] Add libweexcore.so due to the malfunction of integration machine
    
    * [jsframework] updata jsframework to support get data
    
    * * [Android] Update jsfm.js
    
    * [core] fix incorrect data this get from js
    
    * * [Android] Update libweexcore.so
    
    * [core] fix parent component bug
    
    * [core] fix onAppear event can not exec
    
    * * [Android] Update so
    
    * [iOS] add CUSTOM_PREPROCESS record time
    
    * * [Android] Add customPreprocess for APM
    
    * * [Android] Update build.gradle
---
 WeexSDK.podspec                                    |   7 +-
 .../main/java/com/alibaba/weex/WXPageActivity.java |   7 +-
 android/sdk/.gitignore                             |   3 -
 android/sdk/build.gradle                           |   4 +
 android/sdk/libs/armeabi-v7a/libweexjss.so         | Bin 341516 -> 341572 bytes
 android/sdk/libs/armeabi/libweexjss.so             | Bin 341516 -> 341572 bytes
 .../main/java/com/taobao/weex/WXHttpListener.java  | 260 ++++++++++
 .../main/java/com/taobao/weex/WXSDKInstance.java   | 206 +-------
 .../com/taobao/weex/bridge/RequestHandler.java     | 101 ++++
 .../main/java/com/taobao/weex/bridge/WXBridge.java |  14 +-
 .../com/taobao/weex/bridge/WXBridgeManager.java    |   9 +-
 .../java/com/taobao/weex/common/IWXBridge.java     |   2 -
 .../com/taobao/weex/performance/WXInstanceApm.java |   4 +
 .../weex/ui/action/GraphicActionUpdateStyle.java   |  25 +-
 .../weex/ui/component/AbstractEditComponent.java   |   3 +
 .../com/taobao/weex/ui/component/WXVContainer.java |  24 +-
 .../com/taobao/weex/utils/WXDataStructureUtil.java |  28 +-
 ios/sdk/WeexSDK.xcodeproj/project.pbxproj          | 108 +++-
 ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m   |  11 +-
 ios/sdk/WeexSDK/Sources/Bridge/WXCoreBridge.h      |   2 +
 ios/sdk/WeexSDK/Sources/Bridge/WXCoreBridge.mm     | 170 ++-----
 ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.mm   |  15 +
 ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.h  |  20 +
 ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.m  |  45 ++
 ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m      |   4 +
 .../WeexSDK/Sources/Performance/WXApmForInstance.h |   2 +
 .../WeexSDK/Sources/Performance/WXApmForInstance.m |   2 +
 .../WeexSDK/Sources/Protocol/WXBridgeProtocol.h    |   6 +
 ios/sdk/WeexSDK/Sources/Utility/WXConvertUtility.h |  60 +++
 .../WeexSDK/Sources/Utility/WXConvertUtility.mm    | 249 ++++++++++
 ios/sdk/WeexSDK/Sources/WeexSDK.h                  |   1 +
 weex_core/Source/CMakeLists.txt                    |   7 +
 weex_core/Source/IPC/IPCMessageJS.h                |   1 +
 .../bridge/script_bridge_in_multi_process.cpp      |  17 +
 .../android/bridge/script_bridge_in_multi_so.cpp   |  16 +-
 weex_core/Source/android/jniprebuild/jni_files     |   1 +
 weex_core/Source/android/jniprebuild/jni_load.cc   |   4 +-
 .../jniprebuild/jniheader/RequestHandler_jni.h     | 122 +++++
 .../android/jniprebuild/jniheader/WXBridge_jni.h   |   4 +-
 weex_core/Source/android/wrap/wx_bridge.cpp        |  13 +-
 weex_core/Source/base/string_util.h                |  29 ++
 .../core/bridge/platform/core_side_in_platform.cpp |  28 +-
 .../core/bridge/script/core_side_in_script.cpp     |   9 +
 .../core/bridge/script/core_side_in_script.h       |   3 +
 weex_core/Source/core/bridge/script_bridge.h       |   3 +
 weex_core/Source/core/data_render/ast.h            |   2 +
 weex_core/Source/core/data_render/class_json.cc    |   2 +-
 weex_core/Source/core/data_render/class_math.cc    |  10 +-
 weex_core/Source/core/data_render/class_object.cc  |   2 +-
 weex_core/Source/core/data_render/class_regex.cc   |   6 +-
 weex_core/Source/core/data_render/class_string.cc  |  24 +-
 .../Source/core/data_render/code_generator.cc      |  50 +-
 weex_core/Source/core/data_render/exec_state.cc    |   4 +
 weex_core/Source/core/data_render/exec_state.h     |  12 +
 .../Source/core/data_render/exec_state_section.cc  | 184 +++++--
 .../Source/core/data_render/exec_state_section.h   |   5 +-
 weex_core/Source/core/data_render/object.cc        |   2 +-
 weex_core/Source/core/data_render/object.h         |  54 +-
 weex_core/Source/core/data_render/parser.cc        | 553 ++++++++++++---------
 weex_core/Source/core/data_render/string_table.h   |   2 +-
 weex_core/Source/core/data_render/vm.cc            |  19 +-
 .../core/data_render/vnode/android/conversion.cc   |  81 +++
 .../conversion.h}                                  |  27 +-
 .../vnode/android/vcomponent_lifecycle_listener.cc | 265 ++++++++++
 .../vnode/android/vnode_on_event_listener.cc       | 112 +++++
 .../vnode/ios/vcomponent_lifecycle_listener.mm     |  77 +++
 .../vnode/ios/vnode_on_event_listener.mm           |  49 ++
 .../Source/core/data_render/vnode/vcomponent.cc    | 215 ++++++--
 .../Source/core/data_render/vnode/vcomponent.h     |  89 ++--
 ..._context.cc => vcomponent_lifecycle_listener.h} |  25 +-
 weex_core/Source/core/data_render/vnode/vnode.cc   |  62 ++-
 weex_core/Source/core/data_render/vnode/vnode.h    |  59 ++-
 .../core/data_render/vnode/vnode_exec_env.cc       | 181 ++++---
 ...render_context.cc => vnode_on_event_listener.h} |  19 +-
 .../core/data_render/vnode/vnode_render_context.cc |   7 +-
 .../core/data_render/vnode/vnode_render_context.h  |  36 ++
 .../core/data_render/vnode/vnode_render_manager.cc | 318 +++++++++---
 .../core/data_render/vnode/vnode_render_manager.h  |  33 +-
 .../network/android/default_request_handler.cc     |  77 +++
 .../android/default_request_handler.h}             |  53 +-
 .../http_module.cc}                                |  23 +-
 .../http_module.h}                                 |  23 +-
 .../ios/default_request_handler.h}                 |  24 +-
 .../ios/default_request_handler.mm}                |  31 +-
 .../request_handler.h}                             |  26 +-
 weex_core/Source/include/WeexApiHeader.h           |   3 +
 weex_core/release.sh                               |  10 +-
 87 files changed, 3416 insertions(+), 1089 deletions(-)

diff --git a/WeexSDK.podspec b/WeexSDK.podspec
index bcb2743..f0ae762 100644
--- a/WeexSDK.podspec
+++ b/WeexSDK.podspec
@@ -19,7 +19,7 @@ Pod::Spec.new do |s|
            Alibaba-INC copyright
     LICENSE
   }
-  s.authors      = { 
+  s.authors      = {
                     "cxfeng1"      => "cxfeng1@gmail.com",
                     "boboning"     => "ningli928@163.com",
                     "yangshengtao" => "yangshengtao1314@163.com",
@@ -32,7 +32,7 @@ Pod::Spec.new do |s|
   s.ios.deployment_target = '8.0'
 
   # use for public
-  # s.source =  { 
+  # s.source =  {
   #  :git => 'https://github.com/apache/incubator-weex.git',
   #  :tag => #{s.version}
   # }
@@ -46,7 +46,8 @@ Pod::Spec.new do |s|
                     'weex_core/Source/wson/**/*.{h,hpp,m,mm,c,cpp,cc}',
                     'weex_core/Source/third_party/**/*.{h,hpp,m,mm,c,cpp,cc}',
                     'weex_core/Source/include/**/*.{h,hpp,m,mm,c,cpp,cc}'
-  s.exclude_files = 'weex_core/Source/**/*android.{h,hpp,m,mm,c,cpp,cc}'
+  s.exclude_files = 'weex_core/Source/**/*android.{h,hpp,m,mm,c,cpp,cc}',
+                    'weex_core/Source/core/network/android/'
 
   s.private_header_files = 'ios/sdk/WeexSDK/Sources/Component/RecycleList/WXJSASTParser.h'
   s.public_header_files = 'ios/sdk/WeexSDK/Sources/WeexSDK.h',
diff --git a/android/playground/app/src/main/java/com/alibaba/weex/WXPageActivity.java b/android/playground/app/src/main/java/com/alibaba/weex/WXPageActivity.java
index b6d8e56..606b5d1 100644
--- a/android/playground/app/src/main/java/com/alibaba/weex/WXPageActivity.java
+++ b/android/playground/app/src/main/java/com/alibaba/weex/WXPageActivity.java
@@ -44,7 +44,6 @@ import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ProgressBar;
 import android.widget.Toast;
-
 import com.alibaba.fastjson.JSON;
 import com.alibaba.weex.commons.WXAnalyzerDelegate;
 import com.alibaba.weex.constants.Constants;
@@ -63,7 +62,6 @@ import com.taobao.weex.ui.component.WXComponent;
 import com.taobao.weex.ui.component.WXVContainer;
 import com.taobao.weex.utils.WXFileUtils;
 import com.taobao.weex.utils.WXLogUtils;
-
 import java.io.File;
 import java.io.UnsupportedEncodingException;
 import java.net.MalformedURLException;
@@ -246,8 +244,11 @@ public class WXPageActivity extends WXBaseActivity implements IWXRenderListener,
         try {
           Uri uri = Uri.parse(url);
           mConfigMap.put("bundleUrl", url);
-          if (uri.getPath().endsWith(".wlasm")){
+          if(TextUtils.equals(uri.getQueryParameter("__eagle"), Boolean.TRUE.toString())){
             mInstance.render(TAG, task.response.data, mConfigMap, null);
+          }
+          else if (TextUtils.equals(uri.getQueryParameter("__data_render"), Boolean.TRUE.toString())){
+            mInstance.render(TAG, new String(task.response.data, "UTF-8"), mConfigMap, null, WXRenderStrategy.DATA_RENDER);
           } else {
             mInstance.render(TAG, new String(task.response.data, "utf-8"), mConfigMap, null, WXRenderStrategy.APPEND_ASYNC);
           }
diff --git a/android/sdk/.gitignore b/android/sdk/.gitignore
index 25d1179..9c18c2d 100755
--- a/android/sdk/.gitignore
+++ b/android/sdk/.gitignore
@@ -14,6 +14,3 @@ lint.xml
 project.properties
 assets/main.js
 .externalNativeBuild
-libs/armeabi/libweexcore.so
-libs/armeabi-v7a/libweexcore.so
-libs/x86/libweexcore.so
\ No newline at end of file
diff --git a/android/sdk/build.gradle b/android/sdk/build.gradle
index ecba7bc..e8986f5 100755
--- a/android/sdk/build.gradle
+++ b/android/sdk/build.gradle
@@ -60,6 +60,10 @@ version = project.hasProperty('weexVersion')? project.getProperty('weexVersion')
 
 android {
 
+    delete 'libs/armeabi/libweexcore.so'
+    delete 'libs/armeabi-v7a/libweexcore.so'
+    delete 'libs/x86/libweexcore.so'
+
     compileSdkVersion project.compileSdkVersion
     buildToolsVersion project.buildToolsVersion
     resourcePrefix "weex"
diff --git a/android/sdk/libs/armeabi-v7a/libweexjss.so b/android/sdk/libs/armeabi-v7a/libweexjss.so
index de119ed..50e261a 100755
Binary files a/android/sdk/libs/armeabi-v7a/libweexjss.so and b/android/sdk/libs/armeabi-v7a/libweexjss.so differ
diff --git a/android/sdk/libs/armeabi/libweexjss.so b/android/sdk/libs/armeabi/libweexjss.so
index de119ed..50e261a 100755
Binary files a/android/sdk/libs/armeabi/libweexjss.so and b/android/sdk/libs/armeabi/libweexjss.so differ
diff --git a/android/sdk/src/main/java/com/taobao/weex/WXHttpListener.java b/android/sdk/src/main/java/com/taobao/weex/WXHttpListener.java
new file mode 100644
index 0000000..4e10863
--- /dev/null
+++ b/android/sdk/src/main/java/com/taobao/weex/WXHttpListener.java
@@ -0,0 +1,260 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package com.taobao.weex;
+
+import android.net.Uri;
+import android.text.TextUtils;
+
+import com.taobao.weex.adapter.IWXHttpAdapter;
+import com.taobao.weex.adapter.IWXUserTrackAdapter;
+import com.taobao.weex.common.WXErrorCode;
+import com.taobao.weex.common.WXPerformance;
+import com.taobao.weex.common.WXRenderStrategy;
+import com.taobao.weex.common.WXResponse;
+import com.taobao.weex.performance.WXInstanceApm;
+import com.taobao.weex.tracing.WXTracing;
+import com.taobao.weex.utils.WXLogUtils;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * load bundle js listener
+ */
+public class WXHttpListener implements IWXHttpAdapter.OnHttpListener {
+
+    private String pageName;
+    private Map<String, Object> options;
+    private String jsonInitData;
+    private WXRenderStrategy flag;
+    private WXSDKInstance instance;
+    private long startRequestTime;
+    private int traceId;
+    private WXPerformance mWXPerformance;
+    private WXInstanceApm mApmForInstance;
+    private IWXUserTrackAdapter mUserTrackAdapter;
+
+    private String mBundleUrl;
+
+    public WXHttpListener(WXSDKInstance instance) {
+        this.instance = instance;
+        this.traceId = WXTracing.nextId();
+        this.mWXPerformance = instance.getWXPerformance();
+        this.mApmForInstance = instance.getApmForInstance();
+        this.mUserTrackAdapter = WXSDKManager.getInstance().getIWXUserTrackAdapter();
+        if (WXTracing.isAvailable()) {
+            WXTracing.TraceEvent event = WXTracing.newEvent("downloadBundleJS", instance.getInstanceId(), -1);
+            event.iid = instance.getInstanceId();
+            event.tname = "Network";
+            event.ph = "B";
+            event.traceId = traceId;
+            event.submit();
+        }
+    }
+
+    public WXHttpListener(WXSDKInstance instance, String bundleUrl) {
+        this(instance);
+        this.startRequestTime = System.currentTimeMillis();
+        this.mBundleUrl = bundleUrl;
+    }
+
+    public WXHttpListener(WXSDKInstance instance, String pageName, Map<String, Object> options, String jsonInitData, WXRenderStrategy flag, long startRequestTime) {
+        this(instance);
+        this.pageName = pageName;
+        this.options = options;
+        this.jsonInitData = jsonInitData;
+        this.flag = flag;
+        this.startRequestTime = startRequestTime;
+        this.mBundleUrl = instance.getBundleUrl();
+    }
+
+    public void setSDKInstance(WXSDKInstance instance) {
+        this.instance = instance;
+    }
+
+    @Override
+    public void onHttpStart() {
+        if (this.instance != null
+                && this.instance.getWXStatisticsListener() != null) {
+            this.instance.getWXStatisticsListener().onHttpStart();
+        }
+    }
+
+    @Override
+    public void onHeadersReceived(int statusCode, Map<String,List<String>> headers) {
+        if (this.instance != null
+                && this.instance.getWXStatisticsListener() != null) {
+            this.instance.getWXStatisticsListener().onHeadersReceived();
+            this.instance.onHttpStart();
+        }
+        if(this.instance != null
+                && this.instance.responseHeaders != null
+                && headers != null){
+            this.instance.responseHeaders.putAll(headers);
+        }
+    }
+
+    @Override
+    public void onHttpUploadProgress(int uploadProgress) {
+
+    }
+
+    @Override
+    public void onHttpResponseProgress(int loadedLength) {
+        instance.getApmForInstance().extInfo.put(WXInstanceApm.VALUE_BUNDLE_LOAD_LENGTH,loadedLength);
+    }
+
+    @Override
+    public void onHttpFinish(WXResponse response) {
+
+        if (this.instance != null
+                && this.instance.getWXStatisticsListener() != null) {
+            this.instance.getWXStatisticsListener().onHttpFinish();
+        }
+
+        if (WXTracing.isAvailable()) {
+            WXTracing.TraceEvent event = WXTracing.newEvent("downloadBundleJS", instance.getInstanceId(), -1);
+            event.traceId = traceId;
+            event.tname = "Network";
+            event.ph = "E";
+            event.extParams = new HashMap<>();
+            if (response != null && response.originalData != null) {
+                event.extParams.put("BundleSize", response.originalData.length);
+            }
+            event.submit();
+        }
+
+        mWXPerformance.networkTime = System.currentTimeMillis() - startRequestTime;
+        if(null!= response && response.extendParams!=null){
+            mApmForInstance.updateRecordInfo(response.extendParams);
+            Object actualNetworkTime=response.extendParams.get("actualNetworkTime");
+            mWXPerformance.actualNetworkTime=actualNetworkTime instanceof Long?(long)actualNetworkTime:0;
+
+            Object pureNetworkTime=response.extendParams.get("pureNetworkTime");
+            mWXPerformance.pureNetworkTime=pureNetworkTime instanceof Long?(long)pureNetworkTime:0;
+
+            Object connectionType=response.extendParams.get("connectionType");
+            mWXPerformance.connectionType=connectionType instanceof String?(String)connectionType:"";
+
+            Object packageSpendTime=response.extendParams.get("packageSpendTime");
+            mWXPerformance.packageSpendTime=packageSpendTime instanceof Long ?(long)packageSpendTime:0;
+
+            Object syncTaskTime=response.extendParams.get("syncTaskTime");
+            mWXPerformance.syncTaskTime=syncTaskTime instanceof Long ?(long)syncTaskTime:0;
+
+            Object requestType=response.extendParams.get("requestType");
+            mWXPerformance.requestType=requestType instanceof String?(String)requestType:"none";
+
+            Object cacheType = response.extendParams.get(WXPerformance.Dimension.cacheType.toString());
+            if(cacheType instanceof String){
+                mWXPerformance.cacheType = (String) cacheType;
+            }
+
+            Object zCacheInfo = response.extendParams.get("zCacheInfo");
+            mWXPerformance.zCacheInfo = zCacheInfo instanceof String?(String)zCacheInfo:"";
+
+            if(isNet(mWXPerformance.requestType) && mUserTrackAdapter!=null){
+                WXPerformance performance=new WXPerformance(instance.getInstanceId());
+                if(!TextUtils.isEmpty(mBundleUrl)){
+                    try {
+                        performance.args= Uri.parse(mBundleUrl).buildUpon().clearQuery().toString();
+                    } catch (Exception e) {
+                        performance.args=pageName;
+                    }
+                }
+                if(!"200".equals(response.statusCode)){
+                    performance.errCode= WXErrorCode.WX_ERR_JSBUNDLE_DOWNLOAD.getErrorCode();
+                    performance.appendErrMsg(response.errorCode);
+                    performance.appendErrMsg("|");
+                    performance.appendErrMsg(response.errorMsg);
+
+                }else if("200".equals(response.statusCode) && (response.originalData==null || response.originalData.length<=0)){
+                    performance.errCode=WXErrorCode.WX_ERR_JSBUNDLE_DOWNLOAD.getErrorCode();
+                    performance.appendErrMsg(response.statusCode);
+                    performance.appendErrMsg("|template is null!");
+                }else {
+                    performance.errCode=WXErrorCode.WX_SUCCESS.getErrorCode();
+                }
+
+                if (mUserTrackAdapter != null) {
+                    mUserTrackAdapter.commit(instance.getContext(), null, IWXUserTrackAdapter.JS_DOWNLOAD, performance, null);
+                }
+            }
+        }
+        String wxErrorCode = WXInstanceApm.VALUE_ERROR_CODE_DEFAULT;
+        if (response!=null && response.originalData!=null && TextUtils.equals("200", response.statusCode)) {
+            mApmForInstance.onStage(WXInstanceApm.KEY_PAGE_STAGES_DOWN_BUNDLE_END);
+            onSuccess(response);
+
+            // check content-type
+        } else if (TextUtils.equals(WXErrorCode.WX_DEGRAD_ERR_BUNDLE_CONTENTTYPE_ERROR.getErrorCode(),
+                response.statusCode)) {
+            WXLogUtils.e("user intercept: WX_DEGRAD_ERR_BUNDLE_CONTENTTYPE_ERROR");
+            wxErrorCode = WXErrorCode.WX_DEGRAD_ERR_BUNDLE_CONTENTTYPE_ERROR.getErrorCode();
+            instance.onRenderError(wxErrorCode,
+                    "|response.errorMsg==" + response.errorMsg +
+                            "|instance bundleUrl = \n" + instance.getBundleUrl() +
+                            "|instance requestUrl = \n" + Uri.decode(WXSDKInstance.requestUrl)
+            );
+            onFail(response);
+
+            // check content-length
+        } else if (response!=null && response.originalData!=null && TextUtils.equals("-206", response.statusCode)) {
+            WXLogUtils.e("user intercept: WX_DEGRAD_ERR_NETWORK_CHECK_CONTENT_LENGTH_FAILED");
+            wxErrorCode =  WXErrorCode.WX_DEGRAD_ERR_NETWORK_CHECK_CONTENT_LENGTH_FAILED.getErrorCode();
+            instance.onRenderError(wxErrorCode ,
+                    WXErrorCode.WX_DEGRAD_ERR_NETWORK_CHECK_CONTENT_LENGTH_FAILED.getErrorCode() +
+                            "|response.errorMsg==" + response.errorMsg
+            );
+            onFail(response);
+        }
+        else {
+            wxErrorCode = WXErrorCode.WX_DEGRAD_ERR_NETWORK_BUNDLE_DOWNLOAD_FAILED.getErrorCode();
+            instance.onRenderError(wxErrorCode,
+                    response.errorMsg);
+            onFail(response);
+        }
+        if (!WXInstanceApm.VALUE_ERROR_CODE_DEFAULT.equals(wxErrorCode)){
+            mApmForInstance.addProperty(WXInstanceApm.KEY_PROPERTIES_ERROR_CODE,wxErrorCode);
+        }
+    }
+
+    private boolean isNet(String requestType){
+
+        return "network".equals(requestType) || "2g".equals(requestType) || "3g".equals(requestType)
+                || "4g".equals(requestType) || "wifi".equals(requestType) || "other".equals(requestType)
+                || "unknown".equals(requestType);
+    }
+
+    public void onSuccess(WXResponse response) {
+        if (flag==WXRenderStrategy.DATA_RENDER_BINARY){
+            instance.render(pageName, response.originalData, options, jsonInitData);
+        }else {
+            String template = new String(response.originalData);
+            instance.render(pageName, template, options, jsonInitData, flag);
+        }
+    }
+
+    public void onFail(WXResponse response) {
+
+    }
+}
+
+
diff --git a/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java b/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java
index 19404b3..36ca0bb 100644
--- a/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java
+++ b/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java
@@ -18,6 +18,9 @@
  */
 package com.taobao.weex;
 
+import static com.taobao.weex.common.WXErrorCode.WX_ERR_RELOAD_PAGE;
+import static com.taobao.weex.http.WXHttpUtil.KEY_USER_AGENT;
+
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.content.Context;
@@ -37,12 +40,11 @@ import android.view.Menu;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ScrollView;
-
 import com.alibaba.fastjson.JSONObject;
 import com.taobao.weex.adapter.IDrawableLoader;
-import com.taobao.weex.adapter.IWXJscProcessManager;
 import com.taobao.weex.adapter.IWXHttpAdapter;
 import com.taobao.weex.adapter.IWXImgLoaderAdapter;
+import com.taobao.weex.adapter.IWXJscProcessManager;
 import com.taobao.weex.adapter.IWXUserTrackAdapter;
 import com.taobao.weex.adapter.URIAdapter;
 import com.taobao.weex.appfram.websocket.IWebSocketAdapter;
@@ -57,11 +59,9 @@ import com.taobao.weex.common.OnWXScrollListener;
 import com.taobao.weex.common.WXErrorCode;
 import com.taobao.weex.common.WXModule;
 import com.taobao.weex.common.WXPerformance;
-import com.taobao.weex.common.WXPerformance.Dimension;
 import com.taobao.weex.common.WXRefreshData;
 import com.taobao.weex.common.WXRenderStrategy;
 import com.taobao.weex.common.WXRequest;
-import com.taobao.weex.common.WXResponse;
 import com.taobao.weex.dom.WXEvent;
 import com.taobao.weex.http.WXHttpUtil;
 import com.taobao.weex.instance.InstanceOnFireEventInterceptor;
@@ -82,7 +82,6 @@ import com.taobao.weex.utils.WXLogUtils;
 import com.taobao.weex.utils.WXReflectionUtils;
 import com.taobao.weex.utils.WXUtils;
 import com.taobao.weex.utils.WXViewUtils;
-
 import java.io.Serializable;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -92,9 +91,6 @@ import java.util.Map;
 import java.util.PriorityQueue;
 import java.util.concurrent.ConcurrentHashMap;
 
-import static com.taobao.weex.common.WXErrorCode.WX_ERR_RELOAD_PAGE;
-import static com.taobao.weex.http.WXHttpUtil.KEY_USER_AGENT;
-
 
 /**
  * Each instance of WXSDKInstance represents an running weex instance.
@@ -797,7 +793,7 @@ public class WXSDKInstance implements IWXActivityStateListener,View.OnLayoutChan
     wxRequest.paramMap.put(KEY_USER_AGENT, WXHttpUtil.assembleUserAgent(mContext,WXEnvironment.getConfig()));
     wxRequest.paramMap.put("isBundleRequest","true");
     WXHttpListener httpListener =
-            new WXHttpListener(pageName, renderOptions, jsonInitData, flag, System.currentTimeMillis());
+            new WXHttpListener(this, pageName, renderOptions, jsonInitData, flag, System.currentTimeMillis());
     httpListener.setSDKInstance(this);
     mApmForInstance.onStage(WXInstanceApm.KEY_PAGE_STAGES_DOWN_BUNDLE_START);
     adapter.sendRequest(wxRequest, (IWXHttpAdapter.OnHttpListener) httpListener);
@@ -1909,198 +1905,6 @@ public class WXSDKInstance implements IWXActivityStateListener,View.OnLayoutChan
   }
 
   /**
-   * load bundle js listener
-   */
-  class WXHttpListener implements IWXHttpAdapter.OnHttpListener {
-
-    private String pageName;
-    private Map<String, Object> options;
-    private String jsonInitData;
-    private WXRenderStrategy flag;
-    private WXSDKInstance instance;
-    private long startRequestTime;
-    private int traceId;
-
-    private WXHttpListener(String pageName, Map<String, Object> options, String jsonInitData, WXRenderStrategy flag, long startRequestTime) {
-      this.pageName = pageName;
-      this.options = options;
-      this.jsonInitData = jsonInitData;
-      this.flag = flag;
-      this.startRequestTime = startRequestTime;
-      this.traceId = WXTracing.nextId();
-
-      if (WXTracing.isAvailable()) {
-        WXTracing.TraceEvent event = WXTracing.newEvent("downloadBundleJS", mInstanceId, -1);
-        event.iid = mInstanceId;
-        event.tname = "Network";
-        event.ph = "B";
-        event.traceId = traceId;
-        event.submit();
-      }
-    }
-
-    public void setSDKInstance(WXSDKInstance instance) {
-      this.instance = instance;
-    }
-
-    @Override
-    public void onHttpStart() {
-      if (this.instance != null
-              && this.instance.getWXStatisticsListener() != null) {
-        this.instance.getWXStatisticsListener().onHttpStart();
-      }
-    }
-
-    @Override
-    public void onHeadersReceived(int statusCode, Map<String,List<String>> headers) {
-      if (this.instance != null
-              && this.instance.getWXStatisticsListener() != null) {
-        this.instance.getWXStatisticsListener().onHeadersReceived();
-        this.instance.onHttpStart();
-      }
-      if(this.instance != null
-              && this.instance.responseHeaders != null
-              && headers != null){
-        this.instance.responseHeaders.putAll(headers);
-      }
-    }
-
-    @Override
-    public void onHttpUploadProgress(int uploadProgress) {
-
-    }
-
-    @Override
-    public void onHttpResponseProgress(int loadedLength) {
-        getApmForInstance().extInfo.put(WXInstanceApm.VALUE_BUNDLE_LOAD_LENGTH,loadedLength);
-    }
-
-    @Override
-    public void onHttpFinish(WXResponse response) {
-
-      if (this.instance != null
-              && this.instance.getWXStatisticsListener() != null) {
-        this.instance.getWXStatisticsListener().onHttpFinish();
-      }
-
-      if (WXTracing.isAvailable()) {
-        WXTracing.TraceEvent event = WXTracing.newEvent("downloadBundleJS", mInstanceId, -1);
-        event.traceId = traceId;
-        event.tname = "Network";
-        event.ph = "E";
-        event.extParams = new HashMap<>();
-        if (response != null && response.originalData != null) {
-          event.extParams.put("BundleSize", response.originalData.length);
-        }
-        event.submit();
-      }
-
-      mWXPerformance.networkTime = System.currentTimeMillis() - startRequestTime;
-      if(null!= response && response.extendParams!=null){
-        mApmForInstance.updateRecordInfo(response.extendParams);
-        Object actualNetworkTime=response.extendParams.get("actualNetworkTime");
-        mWXPerformance.actualNetworkTime=actualNetworkTime instanceof Long?(long)actualNetworkTime:0;
-
-        Object pureNetworkTime=response.extendParams.get("pureNetworkTime");
-        mWXPerformance.pureNetworkTime=pureNetworkTime instanceof Long?(long)pureNetworkTime:0;
-
-        Object connectionType=response.extendParams.get("connectionType");
-        mWXPerformance.connectionType=connectionType instanceof String?(String)connectionType:"";
-
-        Object packageSpendTime=response.extendParams.get("packageSpendTime");
-        mWXPerformance.packageSpendTime=packageSpendTime instanceof Long ?(long)packageSpendTime:0;
-
-        Object syncTaskTime=response.extendParams.get("syncTaskTime");
-        mWXPerformance.syncTaskTime=syncTaskTime instanceof Long ?(long)syncTaskTime:0;
-
-        Object requestType=response.extendParams.get("requestType");
-        mWXPerformance.requestType=requestType instanceof String?(String)requestType:"none";
-
-        Object cacheType = response.extendParams.get(Dimension.cacheType.toString());
-        if(cacheType instanceof String){
-          mWXPerformance.cacheType = (String) cacheType;
-        }
-
-        Object zCacheInfo = response.extendParams.get("zCacheInfo");
-        mWXPerformance.zCacheInfo = zCacheInfo instanceof String?(String)zCacheInfo:"";
-
-        if(isNet(mWXPerformance.requestType) && mUserTrackAdapter!=null){
-          WXPerformance performance=new WXPerformance(mInstanceId);
-          if(!TextUtils.isEmpty(mBundleUrl)){
-            try {
-              performance.args= Uri.parse(mBundleUrl).buildUpon().clearQuery().toString();
-            } catch (Exception e) {
-              performance.args=pageName;
-            }
-          }
-          if(!"200".equals(response.statusCode)){
-            performance.errCode=WXErrorCode.WX_ERR_JSBUNDLE_DOWNLOAD.getErrorCode();
-            performance.appendErrMsg(response.errorCode);
-            performance.appendErrMsg("|");
-            performance.appendErrMsg(response.errorMsg);
-
-          }else if("200".equals(response.statusCode) && (response.originalData==null || response.originalData.length<=0)){
-            performance.errCode=WXErrorCode.WX_ERR_JSBUNDLE_DOWNLOAD.getErrorCode();
-            performance.appendErrMsg(response.statusCode);
-            performance.appendErrMsg("|template is null!");
-          }else {
-            performance.errCode=WXErrorCode.WX_SUCCESS.getErrorCode();
-          }
-
-          if (mUserTrackAdapter != null) {
-            mUserTrackAdapter.commit(getContext(), null, IWXUserTrackAdapter.JS_DOWNLOAD, performance, null);
-          }
-        }
-      }
-      String wxErrorCode = WXInstanceApm.VALUE_ERROR_CODE_DEFAULT;
-      if (response!=null && response.originalData!=null && TextUtils.equals("200", response.statusCode)) {
-        mApmForInstance.onStage(WXInstanceApm.KEY_PAGE_STAGES_DOWN_BUNDLE_END);
-        if (flag==WXRenderStrategy.DATA_RENDER_BINARY){
-          render(pageName, response.originalData, options, jsonInitData);
-        } else {
-          String template = new String(response.originalData);
-          render(pageName, template, options, jsonInitData, flag);
-        }
-
-        // check content-type
-      } else if (TextUtils.equals(WXErrorCode.WX_DEGRAD_ERR_BUNDLE_CONTENTTYPE_ERROR.getErrorCode(),
-              response.statusCode)) {
-        WXLogUtils.e("user intercept: WX_DEGRAD_ERR_BUNDLE_CONTENTTYPE_ERROR");
-        wxErrorCode = WXErrorCode.WX_DEGRAD_ERR_BUNDLE_CONTENTTYPE_ERROR.getErrorCode();
-        onRenderError(wxErrorCode,
-                "|response.errorMsg==" + response.errorMsg +
-                        "|instance bundleUrl = \n" + instance.getBundleUrl() +
-                        "|instance requestUrl = \n" + Uri.decode(WXSDKInstance.requestUrl)
-        );
-
-        // check content-length
-      } else if (response!=null && response.originalData!=null && TextUtils.equals("-206", response.statusCode)) {
-        WXLogUtils.e("user intercept: WX_DEGRAD_ERR_NETWORK_CHECK_CONTENT_LENGTH_FAILED");
-        wxErrorCode =  WXErrorCode.WX_DEGRAD_ERR_NETWORK_CHECK_CONTENT_LENGTH_FAILED.getErrorCode();
-        onRenderError(wxErrorCode ,
-                WXErrorCode.WX_DEGRAD_ERR_NETWORK_CHECK_CONTENT_LENGTH_FAILED.getErrorCode() +
-                        "|response.errorMsg==" + response.errorMsg
-        );
-      }
-      else {
-        wxErrorCode = WXErrorCode.WX_DEGRAD_ERR_NETWORK_BUNDLE_DOWNLOAD_FAILED.getErrorCode();
-        onRenderError(wxErrorCode,
-                response.errorMsg);
-      }
-      if (!WXInstanceApm.VALUE_ERROR_CODE_DEFAULT.equals(wxErrorCode)){
-        mApmForInstance.addProperty(WXInstanceApm.KEY_PROPERTIES_ERROR_CODE,wxErrorCode);
-      }
-    }
-  }
-
-  private boolean isNet(String requestType){
-
-    return "network".equals(requestType) || "2g".equals(requestType) || "3g".equals(requestType)
-            || "4g".equals(requestType) || "wifi".equals(requestType) || "other".equals(requestType)
-            || "unknown".equals(requestType);
-  }
-
-  /**
    * return md5, and bytes length
    * */
   public String getTemplateInfo() {
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/RequestHandler.java b/android/sdk/src/main/java/com/taobao/weex/bridge/RequestHandler.java
new file mode 100644
index 0000000..a5bf160
--- /dev/null
+++ b/android/sdk/src/main/java/com/taobao/weex/bridge/RequestHandler.java
@@ -0,0 +1,101 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package com.taobao.weex.bridge;
+
+import android.net.Uri;
+import android.text.TextUtils;
+
+import com.taobao.weex.WXEnvironment;
+import com.taobao.weex.WXHttpListener;
+import com.taobao.weex.WXSDKInstance;
+import com.taobao.weex.WXSDKManager;
+import com.taobao.weex.adapter.IWXHttpAdapter;
+import com.taobao.weex.adapter.URIAdapter;
+import com.taobao.weex.base.CalledByNative;
+import com.taobao.weex.common.WXRequest;
+import com.taobao.weex.common.WXResponse;
+import com.taobao.weex.http.WXHttpUtil;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static com.taobao.weex.http.WXHttpUtil.KEY_USER_AGENT;
+
+public class RequestHandler {
+
+  native void nativeInvokeOnSuccess(long callback, String result);
+  native void nativeInvokeOnFailed(long callback);
+
+  @CalledByNative
+  public static RequestHandler create() {
+    return new RequestHandler();
+  }
+
+  @CalledByNative
+  public void send(String instanceId, String url, long nativeCallback) {
+    if (TextUtils.isEmpty(instanceId) || TextUtils.isEmpty(url) ||
+        nativeCallback == 0 ||
+        !WXSDKManager.getInstance().getAllInstanceMap().containsKey(
+            instanceId)) {
+      return;
+    }
+
+    WXSDKManager manager = WXSDKManager.getInstance();
+    WXSDKInstance instance =
+        WXSDKManager.getInstance().getSDKInstance(instanceId);
+    if (instance == null)
+      return;
+    IWXHttpAdapter adapter = WXSDKManager.getInstance().getIWXHttpAdapter();
+
+    WXRequest wxRequest = new WXRequest();
+    wxRequest.url = manager.getURIAdapter()
+                        .rewrite(instance, URIAdapter.BUNDLE, Uri.parse(url))
+                        .toString();
+
+    if (wxRequest.paramMap == null) {
+      wxRequest.paramMap = new HashMap<>();
+    }
+    wxRequest.paramMap.put(
+        KEY_USER_AGENT, WXHttpUtil.assembleUserAgent(
+                            instance.getContext(), WXEnvironment.getConfig()));
+    wxRequest.paramMap.put("isBundleRequest", "true");
+    adapter.sendRequest(wxRequest, new OnHttpListenerInner(instance, nativeCallback, url));
+  }
+
+  class OnHttpListenerInner extends WXHttpListener {
+    private long sNativeCallback;
+
+    OnHttpListenerInner(WXSDKInstance instance, long nativeCallback, String bundlUrl) {
+      super(instance, bundlUrl);
+      sNativeCallback = nativeCallback;
+    }
+
+    @Override
+    public void onSuccess(WXResponse response) {
+        String script = new String(response.originalData);
+        nativeInvokeOnSuccess(sNativeCallback, script);
+    }
+
+    @Override
+    public void onFail(WXResponse response) {
+      nativeInvokeOnFailed(sNativeCallback);
+    }
+  }
+}
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridge.java b/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridge.java
index de3db66..15fd438 100644
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridge.java
+++ b/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridge.java
@@ -69,7 +69,7 @@ public class WXBridge implements IWXBridge {
 
   public native String nativeExecJSOnInstance(String instanceId, String script, int type);
 
-  public native void nativeFireEventOnDataRenderNode(String instanceId, String ref, String type, String data);
+  public native void nativeFireEventOnDataRenderNode(String instanceId, String ref, String type, String data, String domChanges);
 
   public native void nativeRegisterModuleOnDataRenderNode( String data);
 
@@ -256,7 +256,12 @@ public class WXBridge implements IWXBridge {
         // TODO use a better way
         if (instance!=null && (instance.getRenderStrategy()== WXRenderStrategy.DATA_RENDER
                 || instance.getRenderStrategy()== WXRenderStrategy.DATA_RENDER_BINARY)){
-          argArray = (JSONArray) JSON.parse(new String(arguments, "UTF-8"));
+          try {
+            argArray = (JSONArray) JSON.parse(new String(arguments, "UTF-8"));
+          } catch (Exception e) {
+            // For wson use in data render mode
+            argArray = (JSONArray) WXWsonJSONSwitch.parseWsonOrJSON(arguments);
+          }
         } else {
           argArray = (JSONArray) WXWsonJSONSwitch.parseWsonOrJSON(arguments);
         }
@@ -705,9 +710,8 @@ public class WXBridge implements IWXBridge {
     }
   }
 
-  @Override
-  public void fireEventOnDataRenderNode(String instanceId, String ref, String type, String data) {
-    nativeFireEventOnDataRenderNode(instanceId,ref,type,data);
+  public void fireEventOnDataRenderNode(String instanceId, String ref, String type, String data, String domChanges) {
+    nativeFireEventOnDataRenderNode(instanceId,ref,type,data, domChanges);
   }
 
   public void registerModuleOnDataRenderNode(String data) {
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridgeManager.java b/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridgeManager.java
index e7ccda6..83cb708 100644
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridgeManager.java
+++ b/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridgeManager.java
@@ -1169,7 +1169,7 @@ public class WXBridgeManager implements Callback, BactchExecutor {
     WXSDKInstance instance = WXSDKManager.getInstance().getAllInstanceMap().get(instanceId);
     if (instance != null && (instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER ||
             instance.getRenderStrategy() == WXRenderStrategy.DATA_RENDER_BINARY)) {
-      fireEventOnDataRenderNode(instanceId, ref, type, data);
+      fireEventOnDataRenderNode(instanceId, ref, type, data, domChanges);
     } else {
       if(callback == null) {
         addJSEventTask(METHOD_FIRE_EVENT, instanceId, params, ref, type, data, domChanges);
@@ -1181,7 +1181,7 @@ public class WXBridgeManager implements Callback, BactchExecutor {
   }
 
   private void fireEventOnDataRenderNode(final String instanceId, final String ref,
-                                         final String type, final Map<String, Object> data) {
+                                         final String type, final Map<String, Object> data, final Map<String, Object> domChanges) {
     mJSHandler.postDelayed(WXThread.secure(new Runnable() {
       @Override
       public void run() {
@@ -1192,7 +1192,10 @@ public class WXBridgeManager implements Callback, BactchExecutor {
             WXLogUtils.d("fireEventOnDataRenderNode >>>> instanceId:" + instanceId
                 + ", data:" + data);
           }
-          mWXBridge.fireEventOnDataRenderNode(instanceId, ref,type,JSON.toJSONString(data));
+          if (mWXBridge instanceof WXBridge) {
+            ((WXBridge) mWXBridge).fireEventOnDataRenderNode(instanceId, ref,type,JSON.toJSONString(data), JSON.toJSONString(domChanges));
+          }
+          WXLogUtils.renderPerformanceLog("fireEventOnDataRenderNode", System.currentTimeMillis() - start);
         } catch (Throwable e) {
           String err = "[WXBridgeManager] fireEventOnDataRenderNode " + WXLogUtils.getStackTrace(e);
           WXExceptionUtils.commitCriticalExceptionRT(instanceId,
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/IWXBridge.java b/android/sdk/src/main/java/com/taobao/weex/common/IWXBridge.java
index 40c484f..847b40b 100644
--- a/android/sdk/src/main/java/com/taobao/weex/common/IWXBridge.java
+++ b/android/sdk/src/main/java/com/taobao/weex/common/IWXBridge.java
@@ -198,6 +198,4 @@ public interface IWXBridge extends IWXObject {
 
   void resetWXBridge(boolean remoteDebug);
 
-  void fireEventOnDataRenderNode(String instanceId, String ref, String type, String data);
-
 }
diff --git a/android/sdk/src/main/java/com/taobao/weex/performance/WXInstanceApm.java b/android/sdk/src/main/java/com/taobao/weex/performance/WXInstanceApm.java
index 483d5ae..777374f 100644
--- a/android/sdk/src/main/java/com/taobao/weex/performance/WXInstanceApm.java
+++ b/android/sdk/src/main/java/com/taobao/weex/performance/WXInstanceApm.java
@@ -67,6 +67,10 @@ public class WXInstanceApm {
     public static final String KEY_PAGE_STAGES_NEW_FSRENDER = "wxNewFsRender";
     public static final String KEY_PAGE_STAGES_INTERACTION = "wxInteraction";
     public static final String KEY_PAGE_STAGES_DESTROY = "wxDestroy";
+    //Custom preprocessing start, called when activity created or other time. Called by other activity
+    public static final String KEY_PAGE_STAGES_CUSTOM_PREPROCESS_START = "wxCustomPreprocessStart";
+    //Custom preprocessing end, called when you'are able to start weex render. Called by other activity
+    public static final String KEY_PAGE_STAGES_CUSTOM_PREPROCESS_END = "wxCustomPreprocessEnd";
 
     /************** stats *****************/
     public static final String KEY_PAGE_STATS_BUNDLE_SIZE = "wxBundleSize";
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionUpdateStyle.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionUpdateStyle.java
index e464cc1..bddb338 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionUpdateStyle.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/action/GraphicActionUpdateStyle.java
@@ -35,6 +35,7 @@ public class GraphicActionUpdateStyle extends BasicGraphicAction {
   private Map<String, Object> mStyle;
   private WXComponent component;
   private boolean mIsCausedByPesudo;
+  private boolean mIsBorderSet;
 
   public GraphicActionUpdateStyle(WXSDKInstance instance, String ref,
                                   Map<String, Object> style,
@@ -77,6 +78,7 @@ public class GraphicActionUpdateStyle extends BasicGraphicAction {
     }
 
     if (null != borders) {
+      mIsBorderSet = true;
       component.setBorders(borders);
     }
   }
@@ -114,23 +116,26 @@ public class GraphicActionUpdateStyle extends BasicGraphicAction {
     }
 
     if (null != borders) {
+      mIsBorderSet = true;
       component.addShorthand(borders);
     }
   }
 
   @Override
   public void executeAction() {
-    if (component == null || mStyle == null) {
-      return;
-    }
-    if(component.getTransition() != null){
-      component.getTransition().updateTranstionParams(mStyle);
-      if(component.getTransition().hasTransitionProperty(mStyle)){
-        component.getTransition().startTransition(mStyle);
+    if (component == null) return;
+    if (mStyle != null) {
+      if(component.getTransition() != null){
+        component.getTransition().updateTranstionParams(mStyle);
+        if(component.getTransition().hasTransitionProperty(mStyle)){
+          component.getTransition().startTransition(mStyle);
+        }
+      } else {
+        component.setTransition(WXTransition.fromMap(mStyle, component));
+        component.updateStyles(mStyle);
       }
-    } else {
-      component.setTransition(WXTransition.fromMap(mStyle, component));
-      component.updateStyles(mStyle);
+    } else if (mIsBorderSet) {
+      component.updateStyles(component);
     }
   }
 }
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/AbstractEditComponent.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/AbstractEditComponent.java
index 7c6134f..c06f611 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/AbstractEditComponent.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/AbstractEditComponent.java
@@ -609,6 +609,9 @@ public abstract class AbstractEditComponent extends WXComponent<WXEditText> {
     if ((view = getHostView()) == null) {
       return;
     }
+    if (TextUtils.equals(view.getText(), value)) {
+      return;
+    }
 
     mIgnoreNextOnInputEvent = true;
     int oldIndex = view.getSelectionStart();
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java
index 33cd5cb..d592038 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java
@@ -579,20 +579,22 @@ public abstract class WXVContainer<T extends ViewGroup> extends WXComponent<T> {
           mBoxShadowHost = new BoxShadowHost(getContext());
           WXViewUtils.setBackGround(mBoxShadowHost, null, this);
 
-          CSSShorthand padding = this.getPadding();
-          CSSShorthand border = this.getBorder();
+          hostView.addView(mBoxShadowHost);
+        }
 
-          int left = (int) (padding.get(CSSShorthand.EDGE.LEFT) + border.get(CSSShorthand.EDGE.LEFT));
-          int top = (int) (padding.get(CSSShorthand.EDGE.TOP) + border.get(CSSShorthand.EDGE.TOP));
-          int right = (int) (padding.get(CSSShorthand.EDGE.RIGHT) + border.get(CSSShorthand.EDGE.RIGHT));
-          int bottom = (int) (padding.get(CSSShorthand.EDGE.BOTTOM) + border.get(CSSShorthand.EDGE.BOTTOM));
+        CSSShorthand padding = this.getPadding();
+        CSSShorthand border = this.getBorder();
 
-          ViewGroup.MarginLayoutParams layoutParams = new ViewGroup.MarginLayoutParams(hostView.getLayoutParams()) ;
-          this.setMarginsSupportRTL(layoutParams, -left, -top, -right, -bottom);
-          mBoxShadowHost.setLayoutParams(layoutParams);
+        int left = (int) (padding.get(CSSShorthand.EDGE.LEFT) + border.get(CSSShorthand.EDGE.LEFT));
+        int top = (int) (padding.get(CSSShorthand.EDGE.TOP) + border.get(CSSShorthand.EDGE.TOP));
+        int right = (int) (padding.get(CSSShorthand.EDGE.RIGHT) + border.get(CSSShorthand.EDGE.RIGHT));
+        int bottom = (int) (padding.get(CSSShorthand.EDGE.BOTTOM) + border.get(CSSShorthand.EDGE.BOTTOM));
 
-          hostView.addView(mBoxShadowHost);
-        }
+        ViewGroup.MarginLayoutParams layoutParams = new ViewGroup.MarginLayoutParams(hostView.getLayoutParams()) ;
+        this.setMarginsSupportRTL(layoutParams, -left, -top, -right, -bottom);
+
+        mBoxShadowHost.setLayoutParams(layoutParams);
+        
         hostView.removeView(mBoxShadowHost);
         hostView.addView(mBoxShadowHost);
         return mBoxShadowHost;
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/WXDataStructureUtil.java b/android/sdk/src/main/java/com/taobao/weex/utils/WXDataStructureUtil.java
index a6ab07f..ee28e45 100644
--- a/android/sdk/src/main/java/com/taobao/weex/utils/WXDataStructureUtil.java
+++ b/android/sdk/src/main/java/com/taobao/weex/utils/WXDataStructureUtil.java
@@ -1,19 +1,21 @@
-/*
- * Copyright (C) 2007 The Guava Authors
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
-
 package com.taobao.weex.utils;
 
 import java.util.HashMap;
diff --git a/ios/sdk/WeexSDK.xcodeproj/project.pbxproj b/ios/sdk/WeexSDK.xcodeproj/project.pbxproj
index aeb4d3b..90b9bb0 100644
--- a/ios/sdk/WeexSDK.xcodeproj/project.pbxproj
+++ b/ios/sdk/WeexSDK.xcodeproj/project.pbxproj
@@ -96,6 +96,34 @@
 		4532670D213FCFB400DAA620 /* WXDisplayLinkManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 45326709213FC84900DAA620 /* WXDisplayLinkManager.m */; };
 		453267142140E38900DAA620 /* vcomponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 453267122140E38900DAA620 /* vcomponent.h */; };
 		453267152140E38900DAA620 /* vcomponent.cc in Sources */ = {isa = PBXBuildFile; fileRef = 453267132140E38900DAA620 /* vcomponent.cc */; };
+		453267202142731000DAA620 /* binary_file.h in Headers */ = {isa = PBXBuildFile; fileRef = 4532671E2142731000DAA620 /* binary_file.h */; };
+		453267212142731000DAA620 /* binary_file.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4532671F2142731000DAA620 /* binary_file.cc */; };
+		453F374D219A76A600A03F1D /* WXConvertUtility.h in Headers */ = {isa = PBXBuildFile; fileRef = 453F374B219A76A500A03F1D /* WXConvertUtility.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		453F374E219A76A600A03F1D /* WXConvertUtility.mm in Sources */ = {isa = PBXBuildFile; fileRef = 453F374C219A76A500A03F1D /* WXConvertUtility.mm */; };
+		453F3756219A76CA00A03F1D /* default_request_handler.h in Headers */ = {isa = PBXBuildFile; fileRef = 453F3750219A76CA00A03F1D /* default_request_handler.h */; };
+		453F3757219A76CA00A03F1D /* http_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 453F3751219A76CA00A03F1D /* http_module.cc */; };
+		453F3758219A76CA00A03F1D /* default_request_handler.mm in Sources */ = {isa = PBXBuildFile; fileRef = 453F3753219A76CA00A03F1D /* default_request_handler.mm */; };
+		453F3759219A76CA00A03F1D /* request_handler.h in Headers */ = {isa = PBXBuildFile; fileRef = 453F3754219A76CA00A03F1D /* request_handler.h */; };
+		453F375A219A76CA00A03F1D /* http_module.h in Headers */ = {isa = PBXBuildFile; fileRef = 453F3755219A76CA00A03F1D /* http_module.h */; };
+		453F375E219A76FA00A03F1D /* vcomponent_lifecycle_listener.mm in Sources */ = {isa = PBXBuildFile; fileRef = 453F375C219A76FA00A03F1D /* vcomponent_lifecycle_listener.mm */; };
+		453F375F219A76FA00A03F1D /* vnode_on_event_listener.mm in Sources */ = {isa = PBXBuildFile; fileRef = 453F375D219A76FA00A03F1D /* vnode_on_event_listener.mm */; };
+		453F3762219A770900A03F1D /* vcomponent_lifecycle_listener.h in Headers */ = {isa = PBXBuildFile; fileRef = 453F3760219A770900A03F1D /* vcomponent_lifecycle_listener.h */; };
+		453F3763219A770900A03F1D /* vnode_on_event_listener.h in Headers */ = {isa = PBXBuildFile; fileRef = 453F3761219A770900A03F1D /* vnode_on_event_listener.h */; };
+		453F3764219A77EE00A03F1D /* vcomponent_lifecycle_listener.mm in Sources */ = {isa = PBXBuildFile; fileRef = 453F375C219A76FA00A03F1D /* vcomponent_lifecycle_listener.mm */; };
+		453F3765219A77FF00A03F1D /* vnode_on_event_listener.mm in Sources */ = {isa = PBXBuildFile; fileRef = 453F375D219A76FA00A03F1D /* vnode_on_event_listener.mm */; };
+		453F3766219A780A00A03F1D /* vcomponent.cc in Sources */ = {isa = PBXBuildFile; fileRef = 453267132140E38900DAA620 /* vcomponent.cc */; };
+		453F3767219A781900A03F1D /* vcomponent_lifecycle_listener.h in Headers */ = {isa = PBXBuildFile; fileRef = 453F3760219A770900A03F1D /* vcomponent_lifecycle_listener.h */; };
+		453F3768219A782900A03F1D /* vnode_on_event_listener.h in Headers */ = {isa = PBXBuildFile; fileRef = 453F3761219A770900A03F1D /* vnode_on_event_listener.h */; };
+		453F3769219A783400A03F1D /* vcomponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 453267122140E38900DAA620 /* vcomponent.h */; };
+		453F376A219A784F00A03F1D /* http_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 453F3751219A76CA00A03F1D /* http_module.cc */; };
+		453F376B219A785C00A03F1D /* http_module.h in Headers */ = {isa = PBXBuildFile; fileRef = 453F3755219A76CA00A03F1D /* http_module.h */; };
+		453F376C219A786F00A03F1D /* request_handler.h in Headers */ = {isa = PBXBuildFile; fileRef = 453F3754219A76CA00A03F1D /* request_handler.h */; };
+		453F376D219A788800A03F1D /* default_request_handler.h in Headers */ = {isa = PBXBuildFile; fileRef = 453F3750219A76CA00A03F1D /* default_request_handler.h */; };
+		453F376E219A789A00A03F1D /* default_request_handler.mm in Sources */ = {isa = PBXBuildFile; fileRef = 453F3753219A76CA00A03F1D /* default_request_handler.mm */; };
+		453F376F219A78D700A03F1D /* WXConvertUtility.mm in Sources */ = {isa = PBXBuildFile; fileRef = 453F374C219A76A500A03F1D /* WXConvertUtility.mm */; };
+		453F3770219A78E200A03F1D /* WXConvertUtility.h in Headers */ = {isa = PBXBuildFile; fileRef = 453F374B219A76A500A03F1D /* WXConvertUtility.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		453F3771219A790100A03F1D /* binary_file.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4532671F2142731000DAA620 /* binary_file.cc */; };
+		453F3772219A790A00A03F1D /* binary_file.h in Headers */ = {isa = PBXBuildFile; fileRef = 4532671E2142731000DAA620 /* binary_file.h */; };
 		4547FD012152048700E79971 /* class_object.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4547FCFF2152048600E79971 /* class_object.cc */; };
 		4547FD022152048700E79971 /* class_object.h in Headers */ = {isa = PBXBuildFile; fileRef = 4547FD002152048600E79971 /* class_object.h */; };
 		4547FD032152049F00E79971 /* class_object.h in Headers */ = {isa = PBXBuildFile; fileRef = 4547FD002152048600E79971 /* class_object.h */; };
@@ -1117,6 +1145,19 @@
 		45326709213FC84900DAA620 /* WXDisplayLinkManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXDisplayLinkManager.m; sourceTree = "<group>"; };
 		453267122140E38900DAA620 /* vcomponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vcomponent.h; sourceTree = "<group>"; };
 		453267132140E38900DAA620 /* vcomponent.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = vcomponent.cc; sourceTree = "<group>"; };
+		4532671E2142731000DAA620 /* binary_file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = binary_file.h; sourceTree = "<group>"; };
+		4532671F2142731000DAA620 /* binary_file.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = binary_file.cc; sourceTree = "<group>"; };
+		453F374B219A76A500A03F1D /* WXConvertUtility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXConvertUtility.h; sourceTree = "<group>"; };
+		453F374C219A76A500A03F1D /* WXConvertUtility.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WXConvertUtility.mm; sourceTree = "<group>"; };
+		453F3750219A76CA00A03F1D /* default_request_handler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = default_request_handler.h; sourceTree = "<group>"; };
+		453F3751219A76CA00A03F1D /* http_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = http_module.cc; sourceTree = "<group>"; };
+		453F3753219A76CA00A03F1D /* default_request_handler.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = default_request_handler.mm; sourceTree = "<group>"; };
+		453F3754219A76CA00A03F1D /* request_handler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = request_handler.h; sourceTree = "<group>"; };
+		453F3755219A76CA00A03F1D /* http_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = http_module.h; sourceTree = "<group>"; };
+		453F375C219A76FA00A03F1D /* vcomponent_lifecycle_listener.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = vcomponent_lifecycle_listener.mm; sourceTree = "<group>"; };
+		453F375D219A76FA00A03F1D /* vnode_on_event_listener.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = vnode_on_event_listener.mm; sourceTree = "<group>"; };
+		453F3760219A770900A03F1D /* vcomponent_lifecycle_listener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vcomponent_lifecycle_listener.h; sourceTree = "<group>"; };
+		453F3761219A770900A03F1D /* vnode_on_event_listener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vnode_on_event_listener.h; sourceTree = "<group>"; };
 		4547FCFF2152048600E79971 /* class_object.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = class_object.cc; sourceTree = "<group>"; };
 		4547FD002152048600E79971 /* class_object.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = class_object.h; sourceTree = "<group>"; };
 		4547FD0B215392F900E79971 /* js_common_function.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = js_common_function.h; sourceTree = "<group>"; };
@@ -1672,6 +1713,35 @@
 			name = Layout;
 			sourceTree = "<group>";
 		};
+		453F374F219A76CA00A03F1D /* network */ = {
+			isa = PBXGroup;
+			children = (
+				453F3750219A76CA00A03F1D /* default_request_handler.h */,
+				453F3751219A76CA00A03F1D /* http_module.cc */,
+				453F3752219A76CA00A03F1D /* ios */,
+				453F3754219A76CA00A03F1D /* request_handler.h */,
+				453F3755219A76CA00A03F1D /* http_module.h */,
+			);
+			path = network;
+			sourceTree = "<group>";
+		};
+		453F3752219A76CA00A03F1D /* ios */ = {
+			isa = PBXGroup;
+			children = (
+				453F3753219A76CA00A03F1D /* default_request_handler.mm */,
+			);
+			path = ios;
+			sourceTree = "<group>";
+		};
+		453F375B219A76FA00A03F1D /* ios */ = {
+			isa = PBXGroup;
+			children = (
+				453F375C219A76FA00A03F1D /* vcomponent_lifecycle_listener.mm */,
+				453F375D219A76FA00A03F1D /* vnode_on_event_listener.mm */,
+			);
+			path = ios;
+			sourceTree = "<group>";
+		};
 		59A583031CF5B2FD0081FD3E /* Handler */ = {
 			isa = PBXGroup;
 			children = (
@@ -2073,6 +2143,8 @@
 		77D161481C02E3670010B15B /* Utility */ = {
 			isa = PBXGroup;
 			children = (
+				453F374B219A76A500A03F1D /* WXConvertUtility.h */,
+				453F374C219A76A500A03F1D /* WXConvertUtility.mm */,
 				C4D872231E5DDF7500E39BC1 /* WXBoxShadow.h */,
 				C4D872241E5DDF7500E39BC1 /* WXBoxShadow.m */,
 				59D3CA481CFC3CE1008835DC /* NSTimer+Weex.h */,
@@ -2253,6 +2325,7 @@
 		B8D66AEC2125572F003960BD /* core */ = {
 			isa = PBXGroup;
 			children = (
+				453F374F219A76CA00A03F1D /* network */,
 				B8D66AED2125572F003960BD /* data_render */,
 				B8D66B192125572F003960BD /* moniter */,
 				B8D66B1C2125572F003960BD /* css */,
@@ -2353,7 +2426,10 @@
 		B8D66AF52125572F003960BD /* vnode */ = {
 			isa = PBXGroup;
 			children = (
+				453F375B219A76FA00A03F1D /* ios */,
 				B8D66AF62125572F003960BD /* vnode.h */,
+				453F3760219A770900A03F1D /* vcomponent_lifecycle_listener.h */,
+				453F3761219A770900A03F1D /* vnode_on_event_listener.h */,
 				B8D66AF72125572F003960BD /* vnode_exec_env.cc */,
 				B8D66AF82125572F003960BD /* vnode.cc */,
 				453267132140E38900DAA620 /* vcomponent.cc */,
@@ -2695,6 +2771,7 @@
 			files = (
 				7715EB6221A69DD9001F1108 /* WXRichText.h in Headers */,
 				4532670A213FC84A00DAA620 /* WXDisplayLinkManager.h in Headers */,
+				453F374D219A76A600A03F1D /* WXConvertUtility.h in Headers */,
 				B8D66C1B21255730003960BD /* style.h in Headers */,
 				B8D66C2321255730003960BD /* layout.h in Headers */,
 				B8D66C2521255730003960BD /* flex_enum.h in Headers */,
@@ -2790,6 +2867,7 @@
 				B8D66C0F21255730003960BD /* core_side_in_platform.h in Headers */,
 				B8D66C9121255730003960BD /* render_factory_interface.h in Headers */,
 				DCE2CF9B1F46D4220021BDC4 /* WXVoiceOverModule.h in Headers */,
+				453F3756219A76CA00A03F1D /* default_request_handler.h in Headers */,
 				74BB5FB91DFEE81A004FC3DF /* WXMetaModule.h in Headers */,
 				98399A9621916A9800D83CCE /* class_function.h in Headers */,
 				DCA0EF641D6EED6F00CB18B9 /* WXGlobalEventModule.h in Headers */,
@@ -2799,6 +2877,7 @@
 				841CD1051F974DFA0081196D /* WXExceptionUtils.h in Headers */,
 				745B2D6A1E5A8E1E0092D38A /* WXRecyclerComponent.h in Headers */,
 				C42E8F9B1F39DF07001EBE9D /* WXTracingProtocol.h in Headers */,
+				453F3763219A770900A03F1D /* vnode_on_event_listener.h in Headers */,
 				B8D66C6D21255730003960BD /* render_text.h in Headers */,
 				7423899F1C32733800D748CA /* WXType.h in Headers */,
 				59A582FC1CF5B17B0081FD3E /* WXBridgeContext.h in Headers */,
@@ -2823,6 +2902,7 @@
 				B8F2C7022133A83C00635B37 /* rax_parser_scope.h in Headers */,
 				4547FD022152048700E79971 /* class_object.h in Headers */,
 				74862F791E02B88D00B7A041 /* JSValue+Weex.h in Headers */,
+				453F375A219A76CA00A03F1D /* http_module.h in Headers */,
 				B8F2C6FA2133A83C00635B37 /* class_factory.h in Headers */,
 				2A1F57B71C75C6A600B58017 /* WXTextInputComponent.h in Headers */,
 				B8D66C2D21255730003960BD /* render_manager.h in Headers */,
@@ -2920,6 +3000,7 @@
 				59A596241CB6311F0012CD52 /* WXStorageModule.h in Headers */,
 				74A4BA851CAD453400195969 /* WXNetworkProtocol.h in Headers */,
 				7461F8A81CFC33A800F62D44 /* WXThreadSafeMutableArray.h in Headers */,
+				453F3759219A76CA00A03F1D /* request_handler.h in Headers */,
 				D33451081D3E19480083598A /* WXCanvasComponent.h in Headers */,
 				17036A4E20FDE72F0029AE3D /* WXApmForInstance.h in Headers */,
 				74B8BEFE1DC47B72004A6027 /* WXRootView.h in Headers */,
@@ -2953,6 +3034,7 @@
 				B8D66C9321255730003960BD /* dom_wson.h in Headers */,
 				B8D66CAF21255730003960BD /* wson_parser.h in Headers */,
 				D317338C1C57257000BB7539 /* WXTransform.h in Headers */,
+				453F3762219A770900A03F1D /* vcomponent_lifecycle_listener.h in Headers */,
 				B8D66BC32125572F003960BD /* vnode_render_context.h in Headers */,
 				77D161301C02DE4E0010B15B /* WXComponent.h in Headers */,
 				B8D66CB121255730003960BD /* TimeUtils.h in Headers */,
@@ -2985,6 +3067,7 @@
 				7715EB6321A69DD9001F1108 /* WXRichText.h in Headers */,
 				4532670C213FCF2300DAA620 /* WXDisplayLinkManager.h in Headers */,
 				B8D66C1C21255730003960BD /* style.h in Headers */,
+				453F3770219A78E200A03F1D /* WXConvertUtility.h in Headers */,
 				B8D66C2421255730003960BD /* layout.h in Headers */,
 				B8D66C2621255730003960BD /* flex_enum.h in Headers */,
 				B85ED3032126715100EBEC11 /* WXRecyclerComponent.h in Headers */,
@@ -3045,6 +3128,11 @@
 				B8D66BC42125572F003960BD /* vnode_render_context.h in Headers */,
 				DCA445AF1EFA575D00D0CFA8 /* WXModuleProtocol.h in Headers */,
 				4547FD102153932A00E79971 /* js_common_function.h in Headers */,
+				453F376D219A788800A03F1D /* default_request_handler.h in Headers */,
+				453F376C219A786F00A03F1D /* request_handler.h in Headers */,
+				453F376B219A785C00A03F1D /* http_module.h in Headers */,
+				453F3768219A782900A03F1D /* vnode_on_event_listener.h in Headers */,
+				453F3767219A781900A03F1D /* vcomponent_lifecycle_listener.h in Headers */,
 				B8D66BF02125572F003960BD /* op_code.h in Headers */,
 				4505D12D219B21760083A1A2 /* class_window.h in Headers */,
 				4505D12B219B21470083A1A2 /* class_regex.h in Headers */,
@@ -3588,6 +3676,7 @@
 				B8D66BAF2125572F003960BD /* ast_factory.cc in Sources */,
 				7461F8A91CFC33A800F62D44 /* WXThreadSafeMutableArray.m in Sources */,
 				745B2D6D1E5A8E1E0092D38A /* WXRecyclerDataController.m in Sources */,
+				453F375F219A76FA00A03F1D /* vnode_on_event_listener.mm in Sources */,
 				B8D66BF32125572F003960BD /* object.cc in Sources */,
 				2AC750251C7565690041D390 /* WXIndicatorComponent.m in Sources */,
 				591DD3311D23AD5800BE8709 /* WXErrorView.m in Sources */,
@@ -3624,6 +3713,7 @@
 				DCA0EF651D6EED6F00CB18B9 /* WXGlobalEventModule.m in Sources */,
 				453267152140E38900DAA620 /* vcomponent.cc in Sources */,
 				2A919DA71E321F1F006EB6B5 /* WXBridgeMethod.m in Sources */,
+				453F3758219A76CA00A03F1D /* default_request_handler.mm in Sources */,
 				7423EB521F4ADE30001662D1 /* WXComponent+DataBinding.mm in Sources */,
 				DCAB35FF1D658EB700C0EA70 /* WXRuleManager.m in Sources */,
 				77D161251C02DDD10010B15B /* WXSDKInstance.m in Sources */,
@@ -3635,6 +3725,7 @@
 				17B122262090AAB000387E33 /* WXSDKError.m in Sources */,
 				B8D66C1F21255730003960BD /* layout.cpp in Sources */,
 				B8D66C2B21255730003960BD /* render_manager.cpp in Sources */,
+				453F374E219A76A600A03F1D /* WXConvertUtility.mm in Sources */,
 				C4B3D6D51E6954300013F38D /* WXEditComponent.mm in Sources */,
 				C4C30DE81E1B833D00786B6C /* WXComponent+PseudoClassManagement.m in Sources */,
 				B8D66C4F21255730003960BD /* render_action_add_element.cpp in Sources */,
@@ -3645,6 +3736,7 @@
 				74A4BA5C1CABBBD000195969 /* WXDebugTool.m in Sources */,
 				98399A9721916A9800D83CCE /* op_code.cc in Sources */,
 				742AD73B1DF98C8B007DC46C /* WXResourceLoader.m in Sources */,
+				453F3757219A76CA00A03F1D /* http_module.cc in Sources */,
 				B8A72CA0213F8BAE0024E7BE /* class_string.cc in Sources */,
 				B8D66C6721255730003960BD /* render_scroller.cpp in Sources */,
 				B8D66C5321255730003960BD /* render_action_createbody.cpp in Sources */,
@@ -3709,6 +3801,7 @@
 				B8D66BBB2125572F003960BD /* vnode_render_context.cc in Sources */,
 				841CD1031F9739890081196D /* WXExceptionUtils.m in Sources */,
 				B8D66CD921255730003960BD /* message_pump_posix.cc in Sources */,
+				453F375E219A76FA00A03F1D /* vcomponent_lifecycle_listener.mm in Sources */,
 				C4E97D341F1EF46D00ABC314 /* WXTracingManager.m in Sources */,
 				742AD72F1DF98C45007DC46C /* WXResourceRequest.m in Sources */,
 				7461F8931CFB373100F62D44 /* WXLayer.m in Sources */,
@@ -3727,6 +3820,11 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				453F376F219A78D700A03F1D /* WXConvertUtility.mm in Sources */,
+				453F376E219A789A00A03F1D /* default_request_handler.mm in Sources */,
+				453F376A219A784F00A03F1D /* http_module.cc in Sources */,
+				453F3765219A77FF00A03F1D /* vnode_on_event_listener.mm in Sources */,
+				453F3764219A77EE00A03F1D /* vcomponent_lifecycle_listener.mm in Sources */,
 				4505D12E219B22630083A1A2 /* op_code.cc in Sources */,
 				4505D12C219B216D0083A1A2 /* class_window.cc in Sources */,
 				4505D12A219B213B0083A1A2 /* class_regex.cc in Sources */,
@@ -4199,7 +4297,10 @@
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
 				VALID_ARCHS = "arm64 armv7 x86_64 i386";
-				WARNING_CFLAGS = "-Wno-documentation";
+				WARNING_CFLAGS = (
+					"-Wno-documentation",
+					"-Wno-c++14-extensions",
+				);
 			};
 			name = Debug;
 		};
@@ -4253,7 +4354,10 @@
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
 				VALID_ARCHS = "arm64 armv7 x86_64 i386";
-				WARNING_CFLAGS = "-Wno-documentation";
+				WARNING_CFLAGS = (
+					"-Wno-documentation",
+					"-Wno-c++14-extensions",
+				);
 			};
 			name = Release;
 		};
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m b/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
index 093945b..4b4b545 100644
--- a/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
@@ -134,6 +134,15 @@ _Pragma("clang diagnostic pop") \
     
     [WXCoreBridge install];
     
+    [_jsBridge registerCallUpdateComponentData:^NSInteger(NSString *instanceId, NSString *componentId, NSString *jsonData) {
+
+        WXPerformBlockOnComponentThread(^{
+            [WXTracingManager startTracingWithInstanceId:instanceId ref:componentId className:nil name:WXTDomCall phase:WXTracingBegin functionName:@"__updateComponentData" options:@{@"threadName":WXTDOMThread}];
+            [WXCoreBridge callUpdateComponentData:instanceId componentId:componentId jsonData:jsonData];
+        });
+        return 0;
+    }];
+
     [_jsBridge registerCallAddElement:^NSInteger(NSString *instanceId, NSString *parentRef, NSDictionary *elementData, NSInteger index) {
         
         WXPerformBlockOnComponentThread(^{
@@ -406,7 +415,7 @@ _Pragma("clang diagnostic pop") \
     NSMutableArray *sendQueue = [NSMutableArray array];
     [self.sendQueue setValue:sendQueue forKey:instanceIdString];
 
-    if (sdkInstance.dataRender) {
+    if (sdkInstance.dataRender && ![options[@"EXEC_JS"] boolValue]) {
         WX_MONITOR_INSTANCE_PERF_START(WXFirstScreenJSFExecuteTime, [WXSDKManager instanceForID:instanceIdString]);
         WX_MONITOR_INSTANCE_PERF_START(WXPTJSCreateInstance, [WXSDKManager instanceForID:instanceIdString]);
 
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXCoreBridge.h b/ios/sdk/WeexSDK/Sources/Bridge/WXCoreBridge.h
index 12c1f07..ca5fd83 100644
--- a/ios/sdk/WeexSDK/Sources/Bridge/WXCoreBridge.h
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXCoreBridge.h
@@ -173,6 +173,8 @@ namespace WeexCore
 
 + (void)removeRenderObjectFromMap:(NSString*)pageId object:(void*)object;
 
++ (void)callUpdateComponentData:(NSString*)pageId componentId:(NSString*)componentId jsonData:(NSString*)jsonData;
+
 + (void)callAddElement:(NSString*)pageId parentRef:(NSString*)parentRef data:(NSDictionary*)data index:(int)index;
 
 + (void)callCreateBody:(NSString*)pageId data:(NSDictionary*)data;
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXCoreBridge.mm b/ios/sdk/WeexSDK/Sources/Bridge/WXCoreBridge.mm
index b2ea970..37b5e9b 100644
--- a/ios/sdk/WeexSDK/Sources/Bridge/WXCoreBridge.mm
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXCoreBridge.mm
@@ -28,6 +28,7 @@
 #import "WXUtility.h"
 #import "WXAssert.h"
 #import "WXAppConfiguration.h"
+#import "WXConvertUtility.h"
 #import "WXSDKEngine.h"
 #import "WXAppMonitorProtocol.h"
 
@@ -44,122 +45,13 @@
 #include "core/bridge/platform/core_side_in_platform.h"
 #include "core/bridge/script/core_side_in_script.h"
 #include "base/TimeUtils.h"
+#include "core/network/http_module.h"
 
 #import <objc/runtime.h>
 #include <fstream>
 
-
-#define NSSTRING(cstr) ((__bridge_transfer NSString*)(CFStringCreateWithCString(NULL, (const char *)(cstr), kCFStringEncodingUTF8)))
-#define NSSTRING_NO_COPY(cstr) ((__bridge_transfer NSString*)(CFStringCreateWithCStringNoCopy(NULL, (const char *)(cstr), kCFStringEncodingUTF8, kCFAllocatorNull)))
-
 namespace WeexCore
-{
-    static NSString* const JSONSTRING_SUFFIX = @"\t\n\t\r";
-    
-    static NSString* TO_JSON(id object)
-    {
-        if (object == nil) {
-            return nil;
-        }
-        
-        @try {
-            if ([object isKindOfClass:[NSArray class]] || [object isKindOfClass:[NSDictionary class]]) {
-                NSError *error = nil;
-                NSData *data = [NSJSONSerialization dataWithJSONObject:object
-                                                               options:0
-                                                                 error:&error];
-                
-                if (error) {
-                    WXLogError(@"%@", error);
-                    WXAssert(NO, @"Fail to convert object to json. %@", error);
-                    return nil;
-                }
-                
-                return [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] stringByAppendingString:JSONSTRING_SUFFIX]; // add suffix so that we know this is a json string
-            }
-        } @catch (NSException *exception) {
-            WXLogError(@"%@", exception);
-            WXAssert(NO, @"Fail to convert object to json. %@", exception);
-            return nil;
-        }
-        
-        return nil;
-    }
-    
-    static id TO_OBJECT(NSString* s)
-    {
-        if ([s hasSuffix:JSONSTRING_SUFFIX]) {
-            if ([s length] == [JSONSTRING_SUFFIX length]) {
-                return [NSNull null];
-            }
-            
-            // s is a json string
-            @try {
-                NSError* error = nil;
-                id jsonObj = [NSJSONSerialization JSONObjectWithData:[s dataUsingEncoding:NSUTF8StringEncoding]
-                                                             options:NSJSONReadingMutableContainers | NSJSONReadingMutableLeaves
-                                                               error:&error];
-                
-                if (jsonObj == nil) {
-                    WXLogError(@"%@", error);
-                    WXAssert(NO, @"Fail to convert json to object. %@", error);
-                }
-                else {
-                    return jsonObj;
-                }
-            } @catch (NSException *exception) {
-                WXLogError(@"%@", exception);
-                WXAssert(NO, @"Fail to convert json to object. %@", exception);
-            }
-        }
-        return s; // return s instead
-    }
-    
-    static NSMutableDictionary* NSDICTIONARY(std::map<std::string, std::string>* map)
-    {
-        if (map == nullptr || map->size() == 0)
-            return [[NSMutableDictionary alloc] init];
-        
-        NSMutableDictionary* result = [[NSMutableDictionary alloc] initWithCapacity:map->size()];
-        for (auto it = map->begin(); it != map->end(); it ++) {
-            id object = TO_OBJECT(NSSTRING(it->second.c_str()));
-            if (object) {
-                [result setObject:object forKey:NSSTRING(it->first.c_str())];
-            }
-        }
-        return result;
-    }
-    
-    static NSMutableDictionary* NSDICTIONARY(std::vector<std::pair<std::string, std::string>>* vec)
-    {
-        if (vec == nullptr || vec->size() == 0)
-            return [[NSMutableDictionary alloc] init];
-        
-        NSMutableDictionary* result = [[NSMutableDictionary alloc] initWithCapacity:vec->size()];
-        for (auto& p : *vec) {
-            id object = TO_OBJECT(NSSTRING(p.second.c_str()));
-            if (object) {
-                [result setObject:object forKey:NSSTRING(p.first.c_str())];
-            }
-        }
-        return result;
-    }
-    
-    static NSMutableArray* NSARRAY(std::set<std::string>* set)
-    {
-        if (set == nullptr || set->size() == 0)
-            return [[NSMutableArray alloc] init];
-        
-        NSMutableArray* result = [[NSMutableArray alloc] initWithCapacity:set->size()];
-        for (auto& s : *set) {
-            id object = TO_OBJECT(NSSTRING(s.c_str()));
-            if (object) {
-                [result addObject:object];
-            }
-        }
-        return result;
-    }
-    
+{    
     static void consoleWithArguments(NSArray *arguments, WXLogFlag logLevel)
     {
         NSMutableString *jsLog = [NSMutableString string];
@@ -206,7 +98,7 @@ namespace WeexCore
             dict[@"borderRightWidth"] = @(borders.getBorderWidth(kBorderWidthRight) / pixelScaleFactor);
         }
     }
-    
+
     static void MergeBorderWidthValues(NSMutableDictionary* dict,
                                        std::vector<std::pair<std::string, std::string>>* borders,
                                        float pixelScaleFactor)
@@ -222,7 +114,7 @@ namespace WeexCore
             dict[NSSTRING(p.first.c_str())] = @(atof(p.second.c_str()) / pixelScaleFactor);
         }
     }
-    
+
     void IOSSide::SetJSVersion(const char* version)
     {
         NSString *jsVersion = NSSTRING(version);
@@ -820,7 +712,6 @@ namespace WeexCore
         page->CallBridgeTime(getCurrentTime() - startTime);
         return result;
     }
-    
 #pragma mark - Layout Impl
     
     WXCoreSize WXCoreMeasureFunctionBridge::Measure(const char* page_id, long render_ptr, float width, MeasureMode widthMeasureMode, float height, MeasureMode heightMeasureMode)
@@ -878,7 +769,13 @@ static WeexCore::ScriptBridge* jsBridge = nullptr;
     auto node_manager = weex::core::data_render::VNodeRenderManager::GetInstance();
     NSString *optionsString = [WXUtility JSONString:options];
     NSString *dataString = [WXUtility JSONString:data];
-    node_manager->CreatePage([jsBundleString UTF8String] ?: "", [pageId UTF8String] ?: "", [optionsString UTF8String] ?: "", [dataString UTF8String] ?: "");
+
+    node_manager->CreatePage([jsBundleString UTF8String] ?: "", [pageId UTF8String] ?: "", [optionsString UTF8String] ?: "", [dataString UTF8String] ?: "", [=](const char* javascript){
+        if (!javascript) {
+            return;
+        }
+        [[WXSDKManager bridgeMgr] createInstanceForJS:pageId template:NSSTRING(javascript) options:options data:data];
+    });
 }
 
 + (void)createDataRenderInstance:(NSString *)pageId contents:(NSData *)contents options:(NSDictionary *)options data:(id)data
@@ -886,7 +783,12 @@ static WeexCore::ScriptBridge* jsBridge = nullptr;
     auto node_manager = weex::core::data_render::VNodeRenderManager::GetInstance();
     NSString *optionsString = [WXUtility JSONString:options];
     NSString *dataString = [WXUtility JSONString:data];
-    node_manager->CreatePage(static_cast<const char *>(contents.bytes), contents.length, [pageId UTF8String], [optionsString UTF8String], dataString ? [dataString UTF8String] : "");
+    node_manager->CreatePage(static_cast<const char *>(contents.bytes), contents.length, [pageId UTF8String], [optionsString UTF8String], dataString ? [dataString UTF8String] : "", [=](const char* javascript) {
+        if (!javascript) {
+            return;
+        }
+        [[WXSDKManager bridgeMgr] createInstanceForJS:pageId template:NSSTRING(javascript) options:options data:data];
+    });
 }
 
 + (void)destroyDataRenderInstance:(NSString *)pageId
@@ -905,7 +807,7 @@ static WeexCore::ScriptBridge* jsBridge = nullptr;
 {
     NSString *params = [WXUtility JSONString:args];
     auto vnode_manager = weex::core::data_render::VNodeRenderManager::GetInstance();
-    vnode_manager->FireEvent([pageId UTF8String] ? : "", [ref UTF8String] ? : "", [event UTF8String] ? : "", [params UTF8String] ? : "");
+    vnode_manager->FireEvent([pageId UTF8String] ? : "", [ref UTF8String] ? : "", [event UTF8String] ? : "", [params UTF8String] ? : "", "");
 }
 
 + (void)registerModules:(NSDictionary *)modules {
@@ -1050,30 +952,12 @@ static WeexCore::ScriptBridge* jsBridge = nullptr;
     }
 }
 
-static void _convertToCString(id _Nonnull obj, void (^callback)(const char*))
-{
-    if ([obj isKindOfClass:[NSString class]]) {
-        callback([obj UTF8String]);
-    }
-    else if ([obj isKindOfClass:[NSNumber class]]) {
-        callback([[(NSNumber*)obj stringValue] UTF8String]);
-    }
-    else if ([obj isKindOfClass:[NSNull class]]) {
-        callback([JSONSTRING_SUFFIX UTF8String]);
-    }
-    else {
-        NSString* jsonstring = WeexCore::TO_JSON(obj);
-        if (jsonstring != nil) {
-            callback([jsonstring UTF8String]);
-        }
-    }
-}
 
 + (void)_parseStyleBeforehand:(NSDictionary *)styles key:(NSString *)key render:(WeexCore::RenderObject*)render
 {
     id data = styles[key];
     if (data) {
-        _convertToCString(data, ^(const char * value) {
+        ConvertToCString(data, ^(const char * value) {
             if (value != nullptr) {
                 render->AddStyle([key UTF8String], value);
             }
@@ -1095,7 +979,7 @@ static void _convertToCString(id _Nonnull obj, void (^callback)(const char*))
         }
         
         [data[@"attr"] enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
-            _convertToCString(obj, ^(const char * value) {
+            ConvertToCString(obj, ^(const char * value) {
                 if (value != nullptr) {
                     render->AddAttr([key UTF8String], value);
                 }
@@ -1111,7 +995,7 @@ static void _convertToCString(id _Nonnull obj, void (^callback)(const char*))
             if ([key isEqualToString:@"margin"] || [key isEqualToString:@"padding"] || [key isEqualToString:@"borderWidth"]) {
                 return;
             }
-            _convertToCString(obj, ^(const char * value) {
+            ConvertToCString(obj, ^(const char * value) {
                 if (value != nullptr) {
                     render->AddStyle([key UTF8String], value);
                 }
@@ -1119,7 +1003,7 @@ static void _convertToCString(id _Nonnull obj, void (^callback)(const char*))
         }];
         
         for (id obj in data[@"event"]) {
-            _convertToCString(obj, ^(const char * value) {
+            ConvertToCString(obj, ^(const char * value) {
                 if (value != nullptr) {
                     render->AddEvent(value);
                 }
@@ -1143,7 +1027,7 @@ static void _convertToCString(id _Nonnull obj, void (^callback)(const char*))
 {
     std::vector<std::pair<std::string, std::string>>* result = new std::vector<std::pair<std::string, std::string>>();
     [data enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
-        _convertToCString(obj, ^(const char * value) {
+        ConvertToCString(obj, ^(const char * value) {
             if (value != nullptr) {
                 result->emplace_back([key UTF8String], value);
             }
@@ -1152,6 +1036,12 @@ static void _convertToCString(id _Nonnull obj, void (^callback)(const char*))
     return result;
 }
 
++ (void)callUpdateComponentData:(NSString*)pageId componentId:(NSString*)componentId jsonData:(NSString*)jsonData
+{
+    weex::core::data_render::VNodeRenderManager::GetInstance()
+    ->UpdateComponentData([pageId UTF8String] ?: "", [componentId UTF8String] ?: "", [jsonData UTF8String] ?: "");
+}
+
 + (void)callAddElement:(NSString*)pageId parentRef:(NSString*)parentRef data:(NSDictionary*)data index:(int)index
 {
     using namespace WeexCore;
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.mm b/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.mm
index 3652a0d..7577b3d 100644
--- a/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.mm
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.mm
@@ -156,6 +156,21 @@
     }
 }
 
+- (void)registerCallUpdateComponentData:(WXJSCallUpdateComponentData)callUpdateComponentData;
+{
+    id callUpdateComponentDataBlock = ^(JSValue *instanceId, JSValue *cid, JSValue *data, JSValue *ifCallback) {
+        NSString *instanceIdString = [instanceId toString];
+        NSString *componentId = [cid toString];
+        NSDictionary* jsonData = [data toDictionary];
+        NSString* dataString = [WXUtility JSONString:jsonData];
+        WXLogDebug(@"CallUpdateComponentData...%@, %@, %@", instanceIdString, componentId, jsonData);
+
+        return [JSValue valueWithInt32:(int32_t)callUpdateComponentData(instanceIdString, componentId, dataString) inContext:[JSContext currentContext]];
+    };
+
+    _jsContext[@"__updateComponentData"] = callUpdateComponentDataBlock;
+}
+
 - (void)registerCallAddElement:(WXJSCallAddElement)callAddElement
 {
     id callAddElementBlock = ^(JSValue *instanceId, JSValue *ref, JSValue *element, JSValue *index, JSValue *ifCallback) {
diff --git a/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.h b/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.h
index 3386763..29d9fd1 100644
--- a/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.h
+++ b/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.h
@@ -46,6 +46,18 @@ extern "C" {
  *  @param options   :   parameters
  *  @param data      :   external data
  **/
+- (void)createInstanceForJS:(NSString *)instance
+              template:(NSString *)temp
+               options:(NSDictionary *)options
+                  data:(id)data;
+
+/**
+ *  Create Instance Method
+ *  @param instance  :   instance id
+ *  @param temp  :   template data
+ *  @param options   :   parameters
+ *  @param data      :   external data
+ **/
 - (void)createInstance:(NSString *)instance
               template:(NSString *)temp
                options:(NSDictionary *)options
@@ -105,6 +117,12 @@ extern "C" {
 - (void)executeJsFramework:(NSString *)script;
 
 /**
+ + *  download JS Script
+ + *  @param scriptUrl    :   script url
+ + **/
+- (void)DownloadJS:(NSURL *)scriptUrl completion:(void (^)(NSString *script))complection;
+
+/**
  *  Register JS service Script
  *  @param name      :   service name
  *  @param serviceScript    :   script code
@@ -217,4 +235,6 @@ extern "C" {
 - (void)fireEvent:(NSString *)instanceId ref:(NSString *)ref type:(NSString *)type params:(NSDictionary *)params DEPRECATED_MSG_ATTRIBUTE("Use fireEvent:ref:type:params:domChanges: method instead.");
 - (void)executeJsMethod:(WXBridgeMethod *)method DEPRECATED_MSG_ATTRIBUTE();
 
+- (void)callJSMethod:(NSString *)method args:(NSArray *)args;
+
 @end
diff --git a/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.m b/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.m
index f5c7a47..ba412d7 100644
--- a/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.m
+++ b/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.m
@@ -142,6 +142,21 @@ void WXPerformBlockSyncOnBridgeThread(void (^block) (void))
 }
 
 #pragma mark JSBridge Management
+- (void)createInstanceForJS:(NSString *)instance
+              template:(NSString *)temp
+               options:(NSDictionary *)options
+                  data:(id)data {
+    if (!instance || !temp) return;
+    __weak typeof(self) weakSelf = self;
+    NSMutableDictionary *newOptions = [options mutableCopy] ?: [NSMutableDictionary new];
+    newOptions[@"EXEC_JS"] = @(YES);
+    WXPerformBlockOnBridgeThread(^(){
+        [weakSelf.bridgeCtx createInstance:instance
+                                  template:temp
+                                   options:newOptions
+                                      data:data];
+    });
+}
 
 - (void)createInstance:(NSString *)instance
               template:(NSString *)temp
@@ -288,6 +303,26 @@ void WXPerformBlockSyncOnBridgeThread(void (^block) (void))
     return value;
 }
 
+- (void)DownloadJS:(NSURL *)scriptUrl completion:(void (^)(NSString *script))complection;
+{
+    if (!scriptUrl) {
+        complection(nil);
+        return;
+    }
+    WXResourceRequest* request = [WXResourceRequest requestWithURL:scriptUrl];
+    WXResourceLoader* jsLoader = [[WXResourceLoader alloc] initWithRequest:request];
+    jsLoader.onFinished = ^(WXResourceResponse *response, NSData *data) {
+        NSString* jsString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
+        complection(jsString);
+    };
+    jsLoader.onFailed = ^(NSError *loadError) {
+        WXLogError(@"No js URL found");
+        complection(nil);
+    };
+
+   [jsLoader start];
+}
+
 - (void)registerService:(NSString *)name withServiceUrl:(NSURL *)serviceScriptUrl withOptions:(NSDictionary *)options completion:(void(^)(BOOL result))completion
 {
     if (!name || !serviceScriptUrl || !options) {
@@ -483,6 +518,16 @@ void WXPerformBlockSyncOnBridgeThread(void (^block) (void))
     });
 }
 
+- (void)callJSMethod:(NSString *)method args:(NSArray *)args
+{
+    if (!method) return;
+
+    __weak typeof(self) weakSelf = self;
+    WXPerformBlockOnBridgeThread(^(){
+        [weakSelf.bridgeCtx callJSMethod:method args:args onContext:nil completion:nil];
+    });
+}
+
 #pragma mark - Deprecated
 
 - (void)executeJsMethod:(WXCallJSMethod *)method
diff --git a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m
index ccab0e5..2bc521e 100644
--- a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m
+++ b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m
@@ -473,6 +473,10 @@ typedef enum : NSUInteger {
         newOptions[bundleUrlOptionKey] = url.absoluteString;
     }
 
+    if ( [url.absoluteString containsString:@"__data_render=true"]) {
+        newOptions[@"DATA_RENDER"] = @(YES);
+    }
+
     if ([url.absoluteString hasSuffix:WEEX_LITE_URL_SUFFIX] || [url.absoluteString containsString:@"__eagle=true"]) {
         newOptions[@"WLASM_RENDER"] = @(YES);
     }
diff --git a/ios/sdk/WeexSDK/Sources/Performance/WXApmForInstance.h b/ios/sdk/WeexSDK/Sources/Performance/WXApmForInstance.h
index a816246..da559bc 100644
--- a/ios/sdk/WeexSDK/Sources/Performance/WXApmForInstance.h
+++ b/ios/sdk/WeexSDK/Sources/Performance/WXApmForInstance.h
@@ -44,6 +44,8 @@ extern NSString* const KEY_PAGE_PROPERTIES_RENDER_TYPE;
 extern NSString* const KEY_PAGE_STAGES_START;
 extern NSString* const KEY_PAGE_STAGES_DOWN_BUNDLE_START;
 extern NSString* const KEY_PAGE_STAGES_DOWN_BUNDLE_END;
+extern NSString* const KEY_PAGE_STAGES_CUSTOM_PREPROCESS_START;
+extern NSString* const KEY_PAGE_STAGES_CUSTOM_PREPROCESS_END;
 extern NSString* const KEY_PAGE_STAGES_RENDER_ORGIGIN;
 extern NSString* const KEY_PAGE_STAGES_LOAD_BUNDLE_START;
 extern NSString* const KEY_PAGE_STAGES_LOAD_BUNDLE_END;
diff --git a/ios/sdk/WeexSDK/Sources/Performance/WXApmForInstance.m b/ios/sdk/WeexSDK/Sources/Performance/WXApmForInstance.m
index d44effd..7a8822d 100644
--- a/ios/sdk/WeexSDK/Sources/Performance/WXApmForInstance.m
+++ b/ios/sdk/WeexSDK/Sources/Performance/WXApmForInstance.m
@@ -57,6 +57,8 @@ NSString* const KEY_PAGE_PROPERTIES_RENDER_TYPE = @"wxRenderType";
 NSString* const KEY_PAGE_STAGES_START = @"wxRecordStart";
 NSString* const KEY_PAGE_STAGES_DOWN_BUNDLE_START  = @"wxStartDownLoadBundle";
 NSString* const KEY_PAGE_STAGES_DOWN_BUNDLE_END  = @"wxEndDownLoadBundle";
+NSString* const KEY_PAGE_STAGES_CUSTOM_PREPROCESS_START  = @"wxCustomPreprocessStart";
+NSString* const KEY_PAGE_STAGES_CUSTOM_PREPROCESS_END  = @"wxCustomPreprocessEnd";
 NSString* const KEY_PAGE_STAGES_RENDER_ORGIGIN  = @"wxRenderTimeOrigin";
 NSString* const KEY_PAGE_STAGES_LOAD_BUNDLE_START  = @"wxStartLoadBundle";
 NSString* const KEY_PAGE_STAGES_LOAD_BUNDLE_END  = @"wxEndLoadBundle";
diff --git a/ios/sdk/WeexSDK/Sources/Protocol/WXBridgeProtocol.h b/ios/sdk/WeexSDK/Sources/Protocol/WXBridgeProtocol.h
index 90bb955..b3d1019 100644
--- a/ios/sdk/WeexSDK/Sources/Protocol/WXBridgeProtocol.h
+++ b/ios/sdk/WeexSDK/Sources/Protocol/WXBridgeProtocol.h
@@ -33,6 +33,7 @@ typedef NSInteger(^WXJSCallRefreshFinish)(NSString *instanceId);
 typedef NSInteger(^WXJSCallUpdateFinish)(NSString *instanceId);
 typedef NSInvocation *(^WXJSCallNativeModule)(NSString *instanceId, NSString *moduleName, NSString *methodName, NSArray *args, NSDictionary *options);
 typedef void (^WXJSCallNativeComponent)(NSString *instanceId, NSString *componentRef, NSString *methodName, NSArray *args, NSDictionary *options);
+typedef NSInteger(^WXJSCallUpdateComponentData)(NSString *instanceId, NSString *componentId, NSString *jsonData);
 
 @protocol WXBridgeProtocol <NSObject>
 
@@ -75,6 +76,11 @@ typedef void (^WXJSCallNativeComponent)(NSString *instanceId, NSString *componen
 @required
 
 /**
+ * Register callback when call __updateComponentData tasks occur. only use for data render
+ */
+- (void)registerCallUpdateComponentData:(WXJSCallUpdateComponentData)callUpdateComponentData;
+
+/**
  * Register callback when call native tasks occur
  */
 - (void)registerCallNative:(WXJSCallNative)callNative;
diff --git a/ios/sdk/WeexSDK/Sources/Utility/WXConvertUtility.h b/ios/sdk/WeexSDK/Sources/Utility/WXConvertUtility.h
new file mode 100644
index 0000000..25d6f3b
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Utility/WXConvertUtility.h
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+#ifndef __WX_CONVERT_UTILITY_H__
+#define __WX_CONVERT_UTILITY_H__
+
+#if defined __cplusplus
+#include "core/data_render/vnode/vnode_render_manager.h"
+
+#define NSSTRING(cstr) ((__bridge_transfer NSString*)(CFStringCreateWithCString(NULL, (const char *)(cstr), kCFStringEncodingUTF8)))
+#define NSSTRING_NO_COPY(cstr) ((__bridge_transfer NSString*)(CFStringCreateWithCStringNoCopy(NULL, (const char *)(cstr), kCFStringEncodingUTF8, kCFAllocatorNull)))
+
+id _Nonnull GenValue(weex::core::data_render::Value* _Nonnull value);
+
+NSString* _Nullable TO_JSON(id _Nullable object);
+
+id _Nonnull TO_OBJECT(NSString* _Nonnull s);
+
+NSMutableDictionary* _Nonnull NSDICTIONARY(std::map<std::string, std::string>* _Nullable map);
+
+NSMutableDictionary* _Nonnull NSDICTIONARY(std::unordered_map<std::string, std::string>* _Nullable map);
+
+NSMutableDictionary* _Nonnull NSDICTIONARY(std::vector<std::pair<std::string, std::string>>* _Nullable vec);
+
+NSMutableDictionary* _Nonnull NSDICTIONARY(const std::unordered_map<std::string, weex::core::data_render::VComponent::VNodeRefs>& ref_map);
+
+NSMutableDictionary* _Nonnull NSDICTIONARY(weex::core::data_render::Table* _Nullable table);
+
+NSMutableArray* _Nonnull NSARRAY(std::set<std::string>* _Nullable set);
+
+NSMutableArray* _Nonnull NSARRAY(weex::core::data_render::Array* _Nullable array);
+
+NSMutableArray* _Nonnull NSARRAY(std::vector<std::unordered_map<std::string, std::string>> refs);
+
+NSMutableArray* _Nonnull NSARRAY(const std::vector<weex::core::data_render::Value>& params);
+
+void ConvertToCString(id _Nonnull obj, void (^ _Nonnull callback)(const char* _Nullable));
+
+#endif
+
+#endif
diff --git a/ios/sdk/WeexSDK/Sources/Utility/WXConvertUtility.mm b/ios/sdk/WeexSDK/Sources/Utility/WXConvertUtility.mm
new file mode 100644
index 0000000..02ea25d
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Utility/WXConvertUtility.mm
@@ -0,0 +1,249 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#import "WXConvertUtility.h"
+#import "WXLog.h"
+#import "WXAssert.h"
+
+NSString* const JSONSTRING_SUFFIX = @"\t\n\t\r";
+
+NSString* TO_JSON(id object)
+{
+    if (object == nil) {
+        return nil;
+    }
+    
+    @try {
+        if ([object isKindOfClass:[NSArray class]] || [object isKindOfClass:[NSDictionary class]]) {
+            NSError *error = nil;
+            NSData *data = [NSJSONSerialization dataWithJSONObject:object
+                                                           options:0
+                                                             error:&error];
+            
+            if (error) {
+                WXLogError(@"%@", error);
+                WXAssert(NO, @"Fail to convert object to json. %@", error);
+                return nil;
+            }
+            
+            return [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] stringByAppendingString:JSONSTRING_SUFFIX]; // add suffix so that we know this is a json string
+        }
+    } @catch (NSException *exception) {
+        WXLogError(@"%@", exception);
+        WXAssert(NO, @"Fail to convert object to json. %@", exception);
+        return nil;
+    }
+    
+    return nil;
+}
+
+id TO_OBJECT(NSString* s)
+{
+    if ([s hasSuffix:JSONSTRING_SUFFIX]) {
+        if ([s length] == [JSONSTRING_SUFFIX length]) {
+            return [NSNull null];
+        }
+        
+        // s is a json string
+        @try {
+            NSError* error = nil;
+            id jsonObj = [NSJSONSerialization JSONObjectWithData:[s dataUsingEncoding:NSUTF8StringEncoding]
+                                                         options:NSJSONReadingMutableContainers | NSJSONReadingMutableLeaves
+                                                           error:&error];
+            
+            if (jsonObj == nil) {
+                WXLogError(@"%@", error);
+                WXAssert(NO, @"Fail to convert json to object. %@", error);
+            }
+            else {
+                return jsonObj;
+            }
+        } @catch (NSException *exception) {
+            WXLogError(@"%@", exception);
+            WXAssert(NO, @"Fail to convert json to object. %@", exception);
+        }
+    }
+    return s; // return s instead
+}
+
+NSMutableDictionary* NSDICTIONARY(std::map<std::string, std::string>* map)
+{
+    if (map == nullptr || map->size() == 0)
+        return [[NSMutableDictionary alloc] init];
+    
+    NSMutableDictionary* result = [[NSMutableDictionary alloc] initWithCapacity:map->size()];
+    for (auto it = map->begin(); it != map->end(); it ++) {
+        id object = TO_OBJECT(NSSTRING(it->second.c_str()));
+        if (object) {
+            [result setObject:object forKey:NSSTRING(it->first.c_str())];
+        }
+    }
+    return result;
+}
+
+NSMutableDictionary* NSDICTIONARY(std::unordered_map<std::string, std::string>* map)
+{
+    if (map == nullptr || map->size() == 0)
+        return [[NSMutableDictionary alloc] init];
+    
+    NSMutableDictionary* result = [[NSMutableDictionary alloc] initWithCapacity:map->size()];
+    for (auto it = map->begin(); it != map->end(); it ++) {
+        id object = TO_OBJECT(NSSTRING(it->second.c_str()));
+        if (object) {
+            [result setObject:object forKey:NSSTRING(it->first.c_str())];
+        }
+    }
+    return result;
+}
+
+NSMutableDictionary* NSDICTIONARY(std::vector<std::pair<std::string, std::string>>* vec)
+{
+    if (vec == nullptr || vec->size() == 0)
+        return [[NSMutableDictionary alloc] init];
+    
+    NSMutableDictionary* result = [[NSMutableDictionary alloc] initWithCapacity:vec->size()];
+    for (auto& p : *vec) {
+        id object = TO_OBJECT(NSSTRING(p.second.c_str()));
+        if (object) {
+            [result setObject:object forKey:NSSTRING(p.first.c_str())];
+        }
+    }
+    return result;
+}
+
+NSMutableDictionary* NSDICTIONARY(const std::unordered_map<std::string, weex::core::data_render::VComponent::VNodeRefs>& ref_map)
+{
+    if (ref_map.size() == 0) {
+        return [[NSMutableDictionary alloc] init];
+    }
+    NSMutableDictionary* dic = [[NSMutableDictionary alloc] initWithCapacity:ref_map.size()];
+    for (auto it : ref_map) {
+        if (it.first.empty()) {
+            continue;
+        }
+        [dic setObject:NSARRAY(it.second) forKey:NSSTRING(it.first.c_str())];
+    }
+    return dic;
+}
+
+NSMutableDictionary* NSDICTIONARY(weex::core::data_render::Table* table)
+{
+    if (table == nullptr || table->map.size() == 0)
+        return [[NSMutableDictionary alloc] init];
+
+    NSMutableDictionary* dic = [[NSMutableDictionary alloc] initWithCapacity:table->map.size()];
+    for (auto it=table->map.begin(); it!=table->map.end(); ++it) {
+        if (it->first.empty()) {
+            continue;
+        };
+        [dic setObject:GenValue(&it->second) forKey:NSSTRING(it->first.c_str())];
+    }
+    return dic;
+}
+
+NSMutableArray* NSARRAY(std::set<std::string>* set)
+{
+    if (set == nullptr || set->size() == 0)
+        return [[NSMutableArray alloc] init];
+    
+    NSMutableArray* result = [[NSMutableArray alloc] initWithCapacity:set->size()];
+    for (auto& s : *set) {
+        id object = TO_OBJECT(NSSTRING(s.c_str()));
+        if (object) {
+            [result addObject:object];
+        }
+    }
+    return result;
+}
+
+NSMutableArray* NSARRAY(weex::core::data_render::Array* array)
+{
+    if (array == nullptr || array->items.size() == 0)
+        return [[NSMutableArray alloc] init];
+
+    NSMutableArray* ns_array = [[NSMutableArray alloc] initWithCapacity:array->items.size()];
+    for (auto it=array->items.begin(); it!=array->items.end(); ++it) {
+        [ns_array addObject:GenValue(&*it)];
+    }
+    return ns_array;
+}
+
+NSMutableArray* NSARRAY(std::vector<std::unordered_map<std::string, std::string>> refs)
+{
+    if (refs.size() == 0)
+        return [[NSMutableArray alloc] init];
+
+    NSMutableArray* ns_array = [[NSMutableArray alloc] initWithCapacity:refs.size()];
+    for (auto it : refs) {
+        [ns_array addObject:NSDICTIONARY(&it)];
+    }
+    return ns_array;
+}
+
+NSMutableArray* NSARRAY(const std::vector<weex::core::data_render::Value>& params)
+{
+    if (params.size() == 0) {
+        return [[NSMutableArray alloc] init];
+    }
+    NSMutableArray* array = [[NSMutableArray alloc] initWithCapacity:params.size()];
+    for (auto it : params) {
+        [array addObject:GenValue(&it)];
+    }
+    return array;
+}
+
+id GenValue(weex::core::data_render::Value* value)
+{
+    switch (value->type) {
+        case weex::core::data_render::Value::Type::ARRAY:
+            return NSARRAY( weex::core::data_render::ValueTo<weex::core::data_render::Array>(value));
+        case weex::core::data_render::Value::Type::TABLE:
+            return NSDICTIONARY( weex::core::data_render::ValueTo<weex::core::data_render::Table>(value));
+        case weex::core::data_render::Value::Type::INT:
+            return [NSNumber numberWithLong:
+                   static_cast<long>(value->i)];
+        case weex::core::data_render::Value::Type::NUMBER:
+            return [NSNumber numberWithDouble:value->n];
+        case weex::core::data_render::Value::Type::STRING:
+            return NSSTRING(value->str->c_str());
+        case weex::core::data_render::Value::Type::BOOL:
+            return [NSNumber numberWithBool:value->b];
+        default:
+            return [NSNull null];
+    }
+}
+
+void ConvertToCString(id _Nonnull obj, void (^callback)(const char*))
+{
+    if ([obj isKindOfClass:[NSString class]]) {
+        callback([obj UTF8String]);
+    }
+    else if ([obj isKindOfClass:[NSNumber class]]) {
+        callback([[(NSNumber*)obj stringValue] UTF8String]);
+    }
+    else if ([obj isKindOfClass:[NSNull class]]) {
+        callback([JSONSTRING_SUFFIX UTF8String]);
+    }
+    else {
+        NSString* jsonstring = TO_JSON(obj);
+        if (jsonstring != nil) {
+            callback([jsonstring UTF8String]);
+        }
+    }
+}
diff --git a/ios/sdk/WeexSDK/Sources/WeexSDK.h b/ios/sdk/WeexSDK/Sources/WeexSDK.h
index a611390..9d7f293 100644
--- a/ios/sdk/WeexSDK/Sources/WeexSDK.h
+++ b/ios/sdk/WeexSDK/Sources/WeexSDK.h
@@ -65,6 +65,7 @@
 #import "WXDisplayLinkManager.h"
 #import "WXDefine.h"
 #import "WXDebugTool.h"
+#import "WXConvertUtility.h"
 #import "WXConvert.h"
 #import "WXConfigCenterProtocol.h"
 #import "WXComponentManager.h"
diff --git a/weex_core/Source/CMakeLists.txt b/weex_core/Source/CMakeLists.txt
index 2e5624a..f3e5019 100644
--- a/weex_core/Source/CMakeLists.txt
+++ b/weex_core/Source/CMakeLists.txt
@@ -124,6 +124,8 @@ set(COMMON_SRCS
    ./core/data_render/vnode/vnode_exec_env.cc
    ./core/data_render/vnode/vnode_render_manager.cc
    ./core/data_render/vnode/vnode_render_context.cc
+
+   ./core/network/http_module.cc
         )
 add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/wson)
 include_directories(${CMAKE_CURRENT_SOURCE_DIR}/wson)
@@ -175,6 +177,11 @@ if (ANDROID)
     ./android/wrap/wx_params.cpp
     ./android/base/jni_type.cpp
 
+    ./core/data_render/vnode/android/vcomponent_lifecycle_listener.cc
+    ./core/data_render/vnode/android/vnode_on_event_listener.cc
+    ./core/data_render/vnode/android/conversion.cc
+    ./core/network/android/default_request_handler.cc
+    
     ./android/jsengine/multiprocess/WeexJSConnection.cpp
     ./android/jsengine/multiprocess/ExtendJSApi.cpp
 
diff --git a/weex_core/Source/IPC/IPCMessageJS.h b/weex_core/Source/IPC/IPCMessageJS.h
index a99b265..94f698c 100644
--- a/weex_core/Source/IPC/IPCMessageJS.h
+++ b/weex_core/Source/IPC/IPCMessageJS.h
@@ -71,6 +71,7 @@ enum class IPCProxyMsg {
   	DISPATCHMESSAGE,
 	DISPATCHMESSAGESYNC,
   	ONRECEIVEDRESULT,
+  	UPDATECOMPONENTDATA,
 };
 // Message from Script to Core in ScriptBridge
 
diff --git a/weex_core/Source/android/bridge/script_bridge_in_multi_process.cpp b/weex_core/Source/android/bridge/script_bridge_in_multi_process.cpp
index 5b10902..9a5e4eb 100644
--- a/weex_core/Source/android/bridge/script_bridge_in_multi_process.cpp
+++ b/weex_core/Source/android/bridge/script_bridge_in_multi_process.cpp
@@ -954,6 +954,21 @@ std::unique_ptr<IPCResult> OnReceivedResult(IPCArguments *arguments) {
   return createInt32Result(static_cast<int32_t>(true));
 }
 
+std::unique_ptr<IPCResult> UpdateComponentData(IPCArguments *arguments) {
+    auto arg1 = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 0));
+    auto arg2 = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 1));
+    auto arg3 = std::unique_ptr<char[]>(getArumentAsCStr(arguments, 2));
+    WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
+        weex::base::MakeCopyable(
+            [page_id = std::move(arg1), cid = std::move(arg2), json_data = std::move(arg3)]() {
+              WeexCoreManager::Instance()
+                  ->script_bridge()
+                  ->core_side()
+                  ->UpdateComponentData(page_id.get(), cid.get(), json_data.get());
+            }));
+    return createInt32Result(static_cast<int32_t>(true));
+}
+
 ScriptBridgeInMultiProcess::ScriptBridgeInMultiProcess() {
   set_script_side(new bridge::script::ScriptSideInMultiProcess);
   set_core_side(new CoreSideInScript);
@@ -1047,6 +1062,8 @@ void ScriptBridgeInMultiProcess::RegisterIPCCallback(IPCHandler *handler) {
                            HandleDispatchMessageSync);
   handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::ONRECEIVEDRESULT),
                            OnReceivedResult);
+  handler->registerHandler(static_cast<uint32_t>(IPCProxyMsg::UPDATECOMPONENTDATA),
+                           UpdateComponentData);
 }
 
 }  // namespace WeexCore
diff --git a/weex_core/Source/android/bridge/script_bridge_in_multi_so.cpp b/weex_core/Source/android/bridge/script_bridge_in_multi_so.cpp
index 400a83f..32f06e5 100644
--- a/weex_core/Source/android/bridge/script_bridge_in_multi_so.cpp
+++ b/weex_core/Source/android/bridge/script_bridge_in_multi_so.cpp
@@ -478,6 +478,19 @@ static void OnReceivedResult(long callback_id,
       }));
 }
 
+static void UpdateComponentData(const char* page_id,
+                                const char* cid,
+                                const char* json_data) {
+  WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
+      weex::base::MakeCopyable(
+          [page_id = std::string(page_id), cid = std::string(cid), json_data = std::string(json_data)]() {
+            WeexCoreManager::Instance()
+                ->script_bridge()
+                ->core_side()
+                ->UpdateComponentData(page_id.c_str(), cid.c_str(), json_data.c_str());
+          }));
+}
+
 static void ReportException(const char *page_id, const char *func,
                             const char *exception_string) {
   //  WeexCoreManager::Instance()->script_bridge()->core_side()->ReportException(
@@ -529,7 +542,8 @@ FunctionsExposedByCore *ScriptBridgeInMultiSo::GetExposedFunctions() {
                                  PostMessage,
                                  DispatchMessage,
                                  DispatchMessageSync,
-                                 OnReceivedResult};
+                                 OnReceivedResult,
+                                 UpdateComponentData};
   auto functions =
       (FunctionsExposedByCore *)malloc(sizeof(FunctionsExposedByCore));
   memset(functions, 0, sizeof(FunctionsExposedByCore));
diff --git a/weex_core/Source/android/jniprebuild/jni_files b/weex_core/Source/android/jniprebuild/jni_files
index fb9b291..1d02d01 100644
--- a/weex_core/Source/android/jniprebuild/jni_files
+++ b/weex_core/Source/android/jniprebuild/jni_files
@@ -4,3 +4,4 @@ com/taobao/weex/ui/component/list/template/jni/NativeRenderObjectUtils.java
 com/taobao/weex/base/SystemMessageHandler.java
 com/taobao/weex/bridge/WXBridge.java
 com/taobao/weex/layout/ContentBoxMeasurement.java
+com/taobao/weex/bridge/RequestHandler.java
diff --git a/weex_core/Source/android/jniprebuild/jni_load.cc b/weex_core/Source/android/jniprebuild/jni_load.cc
index d668ae6..fba2c63 100644
--- a/weex_core/Source/android/jniprebuild/jni_load.cc
+++ b/weex_core/Source/android/jniprebuild/jni_load.cc
@@ -31,6 +31,7 @@
 #include "android/wrap/wx_js_object.h"
 #include "android/wrap/wx_map.h"
 #include "base/message_loop/message_pump_android.h"
+#include "core/network/android/default_request_handler.h"
 
 jint JNI_OnLoad(JavaVM *vm, void *reserved) {
   base::android::InitVM(vm);
@@ -44,7 +45,8 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) {
                 WeexCore::WXJSObject::RegisterJNIUtils(env) &&
                 WeexCore::LogUtils::RegisterJNIUtils(env) &&
                 WeexCore::WXMap::RegisterJNIUtils(env) &&
-                WeexCore::HashSet::RegisterJNIUtils(env);
+                WeexCore::HashSet::RegisterJNIUtils(env) &&
+                weex::core::network::DefaultRequestHandler::RegisterJNIUtils(env);
   if (result) {
     WeexCore::SoUtils::Init(env);
     WeexCore::WMLBridge::RegisterJNIUtils(env);
diff --git a/weex_core/Source/android/jniprebuild/jniheader/RequestHandler_jni.h b/weex_core/Source/android/jniprebuild/jniheader/RequestHandler_jni.h
new file mode 100644
index 0000000..f83ad37
--- /dev/null
+++ b/weex_core/Source/android/jniprebuild/jniheader/RequestHandler_jni.h
@@ -0,0 +1,122 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+//     weex/weex_core/Source/android/jniprebuild/jni_generator.py
+// For
+//     com/taobao/weex/bridge/RequestHandler
+
+#ifndef com_taobao_weex_bridge_RequestHandler_JNI
+#define com_taobao_weex_bridge_RequestHandler_JNI
+
+#include <jni.h>
+
+//#include "base/android/jni_int_wrapper.h"
+
+// Step 1: forward declarations.
+namespace {
+const char kRequestHandlerClassPath[] = "com/taobao/weex/bridge/RequestHandler";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_RequestHandler_clazz = NULL;
+#define RequestHandler_clazz(env) g_RequestHandler_clazz
+
+}  // namespace
+
+static void InvokeOnSuccess(JNIEnv* env, jobject jcaller,
+    jlong callback,
+    jstring result);
+
+static void InvokeOnFailed(JNIEnv* env, jobject jcaller,
+    jlong callback);
+
+// Step 2: method stubs.
+
+static intptr_t g_RequestHandler_create = 0;
+static base::android::ScopedLocalJavaRef<jobject>
+    Java_RequestHandler_create(JNIEnv* env) {
+  /* Must call RegisterNativesImpl()  */
+  //CHECK_CLAZZ(env, RequestHandler_clazz(env),
+  //    RequestHandler_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::GetMethod(
+      env, RequestHandler_clazz(env),
+      base::android::STATIC_METHOD,
+      "create",
+
+"("
+")"
+"Lcom/taobao/weex/bridge/RequestHandler;",
+      &g_RequestHandler_create);
+
+  jobject ret =
+      env->CallStaticObjectMethod(RequestHandler_clazz(env),
+          method_id);
+  base::android::CheckException(env);
+  return base::android::ScopedLocalJavaRef<jobject>(env, ret);
+}
+
+static intptr_t g_RequestHandler_send = 0;
+static void Java_RequestHandler_send(JNIEnv* env, jobject obj, jstring
+    instanceId,
+    jstring url,
+    jlong nativeCallback) {
+  /* Must call RegisterNativesImpl()  */
+  //CHECK_CLAZZ(env, obj,
+  //    RequestHandler_clazz(env));
+  jmethodID method_id =
+      base::android::GetMethod(
+      env, RequestHandler_clazz(env),
+      base::android::INSTANCE_METHOD,
+      "send",
+
+"("
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+"J"
+")"
+"V",
+      &g_RequestHandler_send);
+
+     env->CallVoidMethod(obj,
+          method_id, instanceId, url, nativeCallback);
+  base::android::CheckException(env);
+
+}
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsRequestHandler[] = {
+    { "nativeInvokeOnSuccess",
+"("
+"J"
+"Ljava/lang/String;"
+")"
+"V", reinterpret_cast<void*>(InvokeOnSuccess) },
+    { "nativeInvokeOnFailed",
+"("
+"J"
+")"
+"V", reinterpret_cast<void*>(InvokeOnFailed) },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_RequestHandler_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kRequestHandlerClassPath).Get()));
+
+  const int kMethodsRequestHandlerSize =
+      sizeof(kMethodsRequestHandler)/sizeof(kMethodsRequestHandler[0]);
+
+  if (env->RegisterNatives(RequestHandler_clazz(env),
+                           kMethodsRequestHandler,
+                           kMethodsRequestHandlerSize) < 0) {
+    //jni_generator::HandleRegistrationError(
+    //    env, RequestHandler_clazz(env), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+#endif  // com_taobao_weex_bridge_RequestHandler_JNI
diff --git a/weex_core/Source/android/jniprebuild/jniheader/WXBridge_jni.h b/weex_core/Source/android/jniprebuild/jniheader/WXBridge_jni.h
index 0b746fd..b431c4e 100644
--- a/weex_core/Source/android/jniprebuild/jniheader/WXBridge_jni.h
+++ b/weex_core/Source/android/jniprebuild/jniheader/WXBridge_jni.h
@@ -77,7 +77,8 @@ static void FireEventOnDataRenderNode(JNIEnv* env, jobject jcaller,
     jstring instanceId,
     jstring ref,
     jstring type,
-    jstring data);
+    jstring data,
+    jstring domChanges);
 
 static void RegisterModuleOnDataRenderNode(JNIEnv* env, jobject jcaller,
     jstring data);
@@ -993,6 +994,7 @@ static const JNINativeMethod kMethodsWXBridge[] = {
 "Ljava/lang/String;"
 "Ljava/lang/String;"
 "Ljava/lang/String;"
+"Ljava/lang/String;"
 ")"
 "V", reinterpret_cast<void*>(FireEventOnDataRenderNode) },
     { "nativeRegisterModuleOnDataRenderNode",
diff --git a/weex_core/Source/android/wrap/wx_bridge.cpp b/weex_core/Source/android/wrap/wx_bridge.cpp
index a699324..2e9cf92 100644
--- a/weex_core/Source/android/wrap/wx_bridge.cpp
+++ b/weex_core/Source/android/wrap/wx_bridge.cpp
@@ -582,7 +582,9 @@ static jstring ExecJSOnInstance(JNIEnv* env, jobject jcaller,
 }
 
 static void FireEventOnDataRenderNode(JNIEnv* env, jobject jcaller,
-                                      jstring instanceId, jstring ref, jstring type, jstring data) {
+                                      jstring instanceId, jstring ref,
+                                      jstring type, jstring data,
+                                      jstring domChanges) {
   if (instanceId == NULL || ref == NULL || type == NULL || data == NULL) {
     return;
   }
@@ -591,13 +593,14 @@ static void FireEventOnDataRenderNode(JNIEnv* env, jobject jcaller,
   ScopedJStringUTF8 refChar(env, ref);
   ScopedJStringUTF8 typeChar(env, type);
   ScopedJStringUTF8 dataChar(env, data);
+  ScopedJStringUTF8 domChangesChar(env, domChanges);
 
   try {
     weex::core::data_render::VNodeRenderManager::GetInstance()->FireEvent(
-        idChar.getChars(), refChar.getChars(), typeChar.getChars(), dataChar.getChars()
-    );
-  } catch (std::exception &e) {
-    auto error = static_cast<weex::core::data_render::Error *>(&e);
+        idChar.getChars(), refChar.getChars(), typeChar.getChars(),
+        dataChar.getChars(), domChangesChar.getChars());
+  } catch (std::exception& e) {
+    auto error = static_cast<weex::core::data_render::Error*>(&e);
     if (error) {
       LOGE("Error on FireEventOnDataRenderNode %s", error->what());
     }
diff --git a/weex_core/Source/base/string_util.h b/weex_core/Source/base/string_util.h
index 9e07c97..4e0ea3b 100644
--- a/weex_core/Source/base/string_util.h
+++ b/weex_core/Source/base/string_util.h
@@ -87,6 +87,35 @@ inline static std::string to_utf8(uint16_t* utf16, size_t length) {
   return output;
 }
 
+#ifdef OS_ANDROID
+static std::u16string to_utf16(char* utf8, size_t length) {
+  std::u16string dest_str;
+  dest_str.resize(length);
+  auto* dest = &dest_str[0];
+  int32_t dest_len = 0;
+
+  bool success = true;
+
+  for (int32_t i = 0; i < length;) {
+    int32_t code_point;
+    CBU8_NEXT(utf8, i, static_cast<int32_t>(length), code_point);
+
+    if (!IsValidCodepoint(code_point)) {
+      success = false;
+      code_point = kErrorCodePoint;
+    }
+
+    CBU16_APPEND_UNSAFE(dest, dest_len, code_point);
+  }
+  if (!success) {
+    return std::u16string();
+  }
+  dest_str.resize(dest_len);
+  dest_str.shrink_to_fit();
+  return dest_str;
+}
+#endif
+
 }  // namespace base
 }  // namespace weex
 #endif  // CORE_BASE_STRING_UTIL_H
diff --git a/weex_core/Source/core/bridge/platform/core_side_in_platform.cpp b/weex_core/Source/core/bridge/platform/core_side_in_platform.cpp
index a35ac01..b767ed4 100644
--- a/weex_core/Source/core/bridge/platform/core_side_in_platform.cpp
+++ b/weex_core/Source/core/bridge/platform/core_side_in_platform.cpp
@@ -429,16 +429,36 @@ int CoreSideInPlatform::CreateInstance(const char *instanceId, const char *func,
                                        const char *render_strategy) {
   // First check about DATA_RENDER mode
   if (render_strategy != nullptr) {
+    std::function<void(const char *)> exec_js =
+        [instanceId = std::string(instanceId), func = std::string(func),
+         opts = std::string(opts), initData = std::string(initData),
+         extendsApi = std::string(extendsApi)](const char *result) {
+          // FIXME Now only support vue, this should be fixed
+          std::string error;
+          auto opts_json = json11::Json::parse(opts, error);
+          std::map<std::string, json11::Json> &opts_map =
+              const_cast<std::map<std::string, json11::Json> &>(
+                  opts_json.object_items());
+          opts_map["bundleType"] = "Vue";
+          WeexCoreManager::Instance()
+              ->script_bridge()
+              ->script_side()
+              ->CreateInstance(instanceId.c_str(), func.c_str(), result,
+                               opts_json.dump().c_str(), initData.c_str(),
+                               extendsApi.c_str());
+        };
     if (strcmp(render_strategy, "DATA_RENDER") == 0) {
       auto node_manager =
-              weex::core::data_render::VNodeRenderManager::GetInstance();
-      node_manager->CreatePage(script, instanceId, render_strategy, initData);
+          weex::core::data_render::VNodeRenderManager::GetInstance();
+      node_manager->CreatePage(script, instanceId, render_strategy, initData,
+                               exec_js);
 
       return true;
     } else if (strcmp(render_strategy, "DATA_RENDER_BINARY") == 0) {
       auto node_manager =
-              weex::core::data_render::VNodeRenderManager::GetInstance();
-      node_manager->CreatePage(script, script_length, instanceId, render_strategy, initData);
+          weex::core::data_render::VNodeRenderManager::GetInstance();
+      node_manager->CreatePage(script, script_length, instanceId,
+                               render_strategy, initData, exec_js);
 
       return true;
     }
diff --git a/weex_core/Source/core/bridge/script/core_side_in_script.cpp b/weex_core/Source/core/bridge/script/core_side_in_script.cpp
index d941245..a9ba409 100644
--- a/weex_core/Source/core/bridge/script/core_side_in_script.cpp
+++ b/weex_core/Source/core/bridge/script/core_side_in_script.cpp
@@ -25,6 +25,7 @@
 #include "base/thread/waitable_event.h"
 #include "core/manager/weex_core_manager.h"
 #include "core/render/manager/render_manager.h"
+#include "core/data_render/vnode/vnode_render_manager.h"
 #ifdef OS_ANDROID
 #include "android/jsengine/multiprocess/ExtendJSApi.h"
 #endif
@@ -468,4 +469,12 @@ void CoreSideInScript::OnReceivedResult(long callback_id,
       ->platform_side()
       ->OnReceivedResult(callback_id, result);
 }
+
+void CoreSideInScript::UpdateComponentData(const char* page_id,
+                                           const char* cid,
+                                           const char* json_data) {
+  weex::core::data_render::VNodeRenderManager::GetInstance()
+      ->UpdateComponentData(page_id, cid, json_data);
+}
+
 }  // namespace WeexCore
diff --git a/weex_core/Source/core/bridge/script/core_side_in_script.h b/weex_core/Source/core/bridge/script/core_side_in_script.h
index 125b1af..2c53c1c 100644
--- a/weex_core/Source/core/bridge/script/core_side_in_script.h
+++ b/weex_core/Source/core/bridge/script/core_side_in_script.h
@@ -80,6 +80,9 @@ class CoreSideInScript : public ScriptBridge::CoreSide {
   void SetJSVersion(const char *js_version) override;
   void OnReceivedResult(long callback_id,
                         std::unique_ptr<WeexJSResult> &result) override;
+  void UpdateComponentData(const char* page_id,
+                           const char* cid,
+                           const char* json_data) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(CoreSideInScript);
diff --git a/weex_core/Source/core/bridge/script_bridge.h b/weex_core/Source/core/bridge/script_bridge.h
index 0c85e0b..7790792 100644
--- a/weex_core/Source/core/bridge/script_bridge.h
+++ b/weex_core/Source/core/bridge/script_bridge.h
@@ -84,6 +84,9 @@ class ScriptBridge {
     virtual void SetJSVersion(const char *js_version) = 0;
     virtual void OnReceivedResult(long callback_id,
                                   std::unique_ptr<WeexJSResult> &result) = 0;
+    virtual void UpdateComponentData(const char* page_id,
+                                     const char* cid,
+                                     const char* json_data) = 0;
 
     inline ScriptBridge *bridge() { return bridge_; }
 
diff --git a/weex_core/Source/core/data_render/ast.h b/weex_core/Source/core/data_render/ast.h
index 1bdfa7f..c8509f7 100644
--- a/weex_core/Source/core/data_render/ast.h
+++ b/weex_core/Source/core/data_render/ast.h
@@ -167,6 +167,8 @@ class ExpressionList : public Expression {
 
   void Insert(Handle<Expression> expr) { exprs_.push_back(expr); }
 
+  void Insert(iterator position, Handle<Expression> expr) { exprs_.insert(position, expr); }
+
   size_t Size() { return exprs_.size(); }
 
   std::vector<Handle<Expression>>& raw_list() { return exprs_; }
diff --git a/weex_core/Source/core/data_render/class_json.cc b/weex_core/Source/core/data_render/class_json.cc
index ac1e143..4d80748 100644
--- a/weex_core/Source/core/data_render/class_json.cc
+++ b/weex_core/Source/core/data_render/class_json.cc
@@ -58,7 +58,7 @@ static Value stringify(ExecState *exec_state) {
         else if (IsArray(value)) {
             json_string = ArrayToString(ValueTo<Array>(value));
         }
-        ret = exec_state->string_table()->StringFromUTF8(json_string);
+        ret = Value(exec_state->string_table()->StringFromUTF8(json_string));
         
     } while (0);
     
diff --git a/weex_core/Source/core/data_render/class_math.cc b/weex_core/Source/core/data_render/class_math.cc
index 119f1b1..9d1b282 100644
--- a/weex_core/Source/core/data_render/class_math.cc
+++ b/weex_core/Source/core/data_render/class_math.cc
@@ -24,9 +24,9 @@ static Value Ceil(ExecState* exec_state){
   }
 
   if (IsNumber(value)){
-    return static_cast<int64_t>(ceil(NumValue(value)));
+    return Value(static_cast<int64_t>(ceil(NumValue(value))));
   } else {
-    return static_cast<int64_t>(ceil(IntValue(value)));
+    return Value(static_cast<int64_t>(ceil(IntValue(value))));
   }
 }
 
@@ -41,15 +41,15 @@ static Value Floor(ExecState* exec_state){
   }
 
   if (IsNumber(value)){
-    return static_cast<int64_t>(floor(NumValue(value)));
+    return Value(static_cast<int64_t>(floor(NumValue(value))));
   } else {
-    return static_cast<int64_t>(floor(IntValue(value)));
+    return Value(static_cast<int64_t>(floor(IntValue(value))));
   }
 }
 
 
 static Value Random(ExecState* exec_state){
-  return static_cast <double> (rand()) / static_cast <double>(RAND_MAX);
+  return Value(static_cast <double> (rand()) / static_cast <double>(RAND_MAX));
 }
 
 static Value Max(ExecState* exec_state){
diff --git a/weex_core/Source/core/data_render/class_object.cc b/weex_core/Source/core/data_render/class_object.cc
index eb38ef5..720043f 100644
--- a/weex_core/Source/core/data_render/class_object.cc
+++ b/weex_core/Source/core/data_render/class_object.cc
@@ -52,7 +52,7 @@ static Value keys(ExecState *exec_state) {
             std::vector<std::string> keys = GetTableKeys(ValueTo<Table>(value));
             Array *array = ValueTo<Array>(&ret);
             for (int i = 0; i < keys.size(); i++) {
-                SetArray(array, i, exec_state->string_table()->StringFromUTF8(keys[i]));
+                SetArray(array, i, Value(exec_state->string_table()->StringFromUTF8(keys[i])));
             }
         }
         
diff --git a/weex_core/Source/core/data_render/class_regex.cc b/weex_core/Source/core/data_render/class_regex.cc
index 95204f0..3d55d38 100644
--- a/weex_core/Source/core/data_render/class_regex.cc
+++ b/weex_core/Source/core/data_render/class_regex.cc
@@ -69,7 +69,7 @@ static Value test(ExecState *exec_state) {
         }
         std::regex express(reg_str, type);
         std::smatch match;
-        ret  = std::regex_search(test_str,match,express);
+        ret  = Value(std::regex_search(test_str,match,express));
     } while (0);
 
     return ret;
@@ -115,7 +115,7 @@ static Value exec(ExecState *exec_state) {
       std::string::const_iterator iterEnd = test_str.end();
       bool succ = false;
       while (std::regex_search(iterStart,iterEnd,match,express)){
-        arr->items.push_back(exec_state->string_table()->StringFromUTF8(match[0]));
+        arr->items.push_back(Value(exec_state->string_table()->StringFromUTF8(match[0])));
         iterStart = match[0].second;
         succ = true;
       }
@@ -129,7 +129,7 @@ static Value exec(ExecState *exec_state) {
 
       if (succ){
         for (size_t i = 0; i < match.size(); ++i){
-          arr->items.push_back(exec_state->string_table()->StringFromUTF8(match[i]));
+          arr->items.push_back(Value(exec_state->string_table()->StringFromUTF8(match[i])));
         }
       } else {
         ret = Value();
diff --git a/weex_core/Source/core/data_render/class_string.cc b/weex_core/Source/core/data_render/class_string.cc
index fa8b89d..50bcb29 100644
--- a/weex_core/Source/core/data_render/class_string.cc
+++ b/weex_core/Source/core/data_render/class_string.cc
@@ -131,8 +131,8 @@ static Value replaceAll(ExecState *exec_state) {
         std::string oldstr = CStringValue(oldValue);
         std::string newstr = CStringValue(newValue);
         std::string dststr = replace_all(srcstr, oldstr, newstr);
-        ret = exec_state->string_table()->StringFromUTF8(dststr);
-
+        ret = Value(exec_state->string_table()->StringFromUTF8(dststr));
+        
     } while (0);
 
     return ret;
@@ -160,7 +160,7 @@ static Value replace(ExecState *exec_state) {
 
           std::string oldstr = CStringValue(oldValue);
           std::string dststr = replace_normal(srcstr, oldstr, newstr);
-          ret = exec_state->string_table()->StringFromUTF8(dststr);
+          ret = Value(exec_state->string_table()->StringFromUTF8(dststr));
         } else if (IsClassInstance(oldValue)){
           ClassInstance* instance = to_regex_inst(exec_state,oldValue);
           Value* reg = GetClassMember(instance, "_reg");
@@ -178,7 +178,7 @@ static Value replace(ExecState *exec_state) {
           std::regex express(reg_str, type);
 
           std::string dststr = std::regex_replace(srcstr, express, newstr,std::regex_constants::format_first_only);
-          ret = exec_state->string_table()->StringFromUTF8(dststr);
+          ret = Value(exec_state->string_table()->StringFromUTF8(dststr));
         } else{
           throw VMExecError("old caller isn't a string or regex");
         }
@@ -221,7 +221,7 @@ static Value split(ExecState *exec_state) {
             split_string<std::vector<std::string>>(src, split_array, delim);
             Array *array = ValueTo<Array>(&ret);
             for (int i = 0; i < split_array.size(); i++) {
-                Value string_value = exec_state->string_table()->StringFromUTF8(split_array[i]);
+                Value string_value(exec_state->string_table()->StringFromUTF8(split_array[i]));
                 array->items.push_back(string_value);
             }
         } else if(IsClassInstance(split)){
@@ -239,7 +239,7 @@ static Value split(ExecState *exec_state) {
 
             Array *array = ValueTo<Array>(&ret);
             for(auto st: ret_vec){
-                Value string_value = exec_state->string_table()->StringFromUTF8(st);
+                Value string_value(exec_state->string_table()->StringFromUTF8(st));
                 array->items.push_back(string_value);
             }
         } else {
@@ -273,7 +273,7 @@ static Value trim(ExecState* exec_state) {
     std::string src = CStringValue(string);
     trim(src);
 
-    Value string_value = exec_state->string_table()->StringFromUTF8(src);
+    Value string_value(exec_state->string_table()->StringFromUTF8(src));
     return string_value;
 }
 
@@ -342,7 +342,7 @@ Value encodeURIComponent(ExecState *exec_state) {
         dst = uri;
         free(uri);
     }
-    return exec_state->string_table()->StringFromUTF8(dst);
+    return Value(exec_state->string_table()->StringFromUTF8(dst));
 }
     
 std::string utf8chr(int cp)
@@ -468,9 +468,9 @@ Value search(ExecState* exec_state) {
         std::smatch match;
         bool succ  = std::regex_search(test_str,match,express);
         if (succ){
-            ret = static_cast<int64_t>(match.position(0));
+            ret = Value(static_cast<int64_t>(match.position(0)));
         } else{
-            ret = -1;
+            ret = Value(-1);
         }
     } else {
         throw VMExecError("split caller isn't a string or regex");
@@ -521,7 +521,7 @@ Value match(ExecState* exec_state) {
             std::string::const_iterator iterEnd = test_str.end();
             bool succ = false;
             while (std::regex_search(iterStart,iterEnd,match,express)){
-                arr->items.push_back(exec_state->string_table()->StringFromUTF8(match[0]));
+                arr->items.push_back(Value(exec_state->string_table()->StringFromUTF8(match[0])));
                 iterStart = match[0].second;
                 succ = true;
             }
@@ -535,7 +535,7 @@ Value match(ExecState* exec_state) {
 
             if (succ){
                 for (size_t i = 0; i < match.size(); ++i){
-                    arr->items.push_back(exec_state->string_table()->StringFromUTF8(match[i]));
+                    arr->items.push_back(Value(exec_state->string_table()->StringFromUTF8(match[i])));
                 }
             } else {
                 ret = Value();
diff --git a/weex_core/Source/core/data_render/code_generator.cc b/weex_core/Source/core/data_render/code_generator.cc
index 1cbc4e5..a472243 100644
--- a/weex_core/Source/core/data_render/code_generator.cc
+++ b/weex_core/Source/core/data_render/code_generator.cc
@@ -117,8 +117,8 @@ void CodeGenerator::Visit(StringConstant* node, void* data) {
   if (reg >= 0) {
     FuncState *func_state = func_->func_state();
     auto value = exec_state_->string_table_->StringFromUTF8(node->string());
-    int index = func_state->AddConstant(std::move(value));
-      Instruction i = CREATE_ABx(OP_LOADK, reg, index);
+    int index = func_state->AddConstant(Value(value));
+    Instruction i = CREATE_ABx(OP_LOADK, reg, index);
     func_state->AddInstruction(i);
   }
 }
@@ -134,10 +134,10 @@ void CodeGenerator::Visit(RegexConstant* node, void* data) {
     auto reg_mem_name = exec_state_->string_table_->StringFromUTF8("_reg");
     auto flag_mem_name = exec_state_->string_table_->StringFromUTF8("_flag");
 
-    int r_index = func_state->AddConstant(std::move(reg_ex));
-    int f_index = func_state->AddConstant(std::move(flag));
-    int mr_index = func_state->AddConstant(std::move(reg_mem_name));
-    int mf_index = func_state->AddConstant(std::move(flag_mem_name));
+    int r_index = func_state->AddConstant(Value(reg_ex));
+    int f_index = func_state->AddConstant(Value(flag));
+    int mr_index = func_state->AddConstant(Value(reg_mem_name));
+    int mf_index = func_state->AddConstant(Value(flag_mem_name));
     auto reg_class_index = exec_state_->global()->IndexOf("RegExp");
 
     auto mr_id = block_->NextRegisterId();
@@ -229,7 +229,7 @@ void CodeGenerator::Visit(CallExpression *stms, void *data) {
             if (stms->expr()->IsIdentifier() && stms->member() && stms->member()->IsIdentifier()) {
                 long reg_member = block_->NextRegisterId();
                 auto value = exec_state_->string_table_->StringFromUTF8(stms->member()->AsIdentifier()->GetName());
-                int tableIndex = func_state->AddConstant(std::move(value));
+                int tableIndex = func_state->AddConstant(Value(value));
                 func_state->AddInstruction(CREATE_ABx(OP_LOADK, reg_member, tableIndex));
                 long reg_class = block_->FindRegisterId(stms->expr()->AsIdentifier()->GetName());
                 if (reg_class < 0) {
@@ -427,8 +427,7 @@ void CodeGenerator::Visit(ForStatement *node, void *data) {
     int for_update_index = condition_start_index;
     if (node->update().get() != NULL) {
         for_update_index = (int)func_state->instructions().size();  // aka next one.
-        long update = block_->NextRegisterId();
-        node->update()->Accept(this, &update);
+        node->update()->Accept(this, nullptr);
     }
     block_->set_for_update_index(for_update_index);
     func_state->AddInstruction(CREATE_Ax(OP_GOTO, condition_start_index));
@@ -463,6 +462,7 @@ void CodeGenerator::Visit(FunctionStatement *node, void *data) {
     auto slot = func_->func_state()->AddInstruction(0);
     {
         FuncScope scope(this);
+        func_->func_state()->set_name(proto->GetName());
         if (is_class_func) {
             Value value;
             value.f = func_->func_state();
@@ -628,7 +628,7 @@ void CodeGenerator::Visit(ArrowFunctionStatement *node, void *data) {
 void CodeGenerator::Visit(ClassStatement *node, void *data) {
     do {
         Handle<Expression> super_expr = node->Super();
-        Value *super_value = nullptr,class_value = nullptr;
+        Value *super_value = nullptr;
         if (super_expr) {
             if (!super_expr->IsIdentifier()) {
                 throw GeneratorError("super isn't a Identifier");
@@ -651,7 +651,7 @@ void CodeGenerator::Visit(ClassStatement *node, void *data) {
             throw GeneratorError(class_name + "redefine");
             break;
         }
-        class_value = exec_state_->class_factory()->CreateClassDescriptor(super_value ? ValueTo<ClassDescriptor>(super_value) : nullptr);
+        Value class_value(exec_state_->class_factory()->CreateClassDescriptor(super_value ? ValueTo<ClassDescriptor>(super_value) : nullptr));
         exec_state_->global()->Add(class_name, class_value);
         ClassScope scope(this, &class_value);
         class_->class_name() = class_name;
@@ -1039,7 +1039,7 @@ void CodeGenerator::Visit(IntegralConstant* node, void* data) {
   if (reg >= 0) {
     FuncState* func_state = func_->func_state();
     int value = node->value();
-    int index = func_state->AddConstant(static_cast<int64_t>(value));
+    int index = func_state->AddConstant(Value(static_cast<int64_t>(value)));
     Instruction i = CREATE_ABx(OP_LOADK, reg, index);
     func_state->AddInstruction(i);
   }
@@ -1050,7 +1050,7 @@ void CodeGenerator::Visit(BooleanConstant* node, void* data) {
   if (reg >= 0) {
     FuncState* func_state = func_->func_state();
     bool value = node->pred();
-    int index = func_state->AddConstant(static_cast<bool>(value));
+    int index = func_state->AddConstant(Value(static_cast<bool>(value)));
     Instruction i = CREATE_ABx(OP_LOADK, reg, index);
     func_state->AddInstruction(i);
   }
@@ -1061,7 +1061,7 @@ void CodeGenerator::Visit(DoubleConstant* node, void* data) {
   if (reg >= 0) {
     FuncState* func_state = func_->func_state();
     double value = node->value();
-    int index = func_state->AddConstant(static_cast<double>(value));
+    int index = func_state->AddConstant(Value(static_cast<double>(value)));
     Instruction i = CREATE_ABx(OP_LOADK, reg, index);
     func_state->AddInstruction(i);
   }
@@ -1111,7 +1111,7 @@ void CodeGenerator::Visit(ObjectConstant *node, void *data) {
                             long key = block_->NextRegisterId();
                             iter->second->Accept(this, &item);
                             auto value = exec_state_->string_table_->StringFromUTF8(iter->first);
-                            int keyIndex = func_state->AddConstant(std::move(value));
+                            int keyIndex = func_state->AddConstant(Value(value));
                             func_state->AddInstruction(CREATE_ABx(OP_LOADK, key, keyIndex));
                             func_state->AddInstruction(CREATE_ABC(OP_SETTABLE, ret, key, item));
                         }
@@ -1131,7 +1131,7 @@ void CodeGenerator::Visit(ObjectConstant *node, void *data) {
                 auto ktemp = (*it).second;
                 ktemp->Accept(this, &item);
                 auto value = exec_state_->string_table_->StringFromUTF8(it->first);
-                int keyIndex = func_state->AddConstant(std::move(value));
+                int keyIndex = func_state->AddConstant(Value(value));
                 func_state->AddInstruction(CREATE_ABx(OP_LOADK, key, keyIndex));
                 func_state->AddInstruction(CREATE_ABC(OP_SETTABLE, ret, key, item));
             }
@@ -1171,7 +1171,7 @@ void CodeGenerator::Visit(ClassProperty *node, void *data) {
             }
             func_state->AddInstruction(CREATE_ABx(OP_GETGLOBAL, lhs, index));
             auto constant = exec_state_->string_table_->StringFromUTF8(node->name());
-            index = func_state->AddConstant(std::move(constant));
+            index = func_state->AddConstant(Value(constant));
             func_state->AddInstruction(CREATE_ABx(OP_LOADK, rhs, index));
             func_state->AddInstruction(CREATE_ABC(OP_GETMEMBERVAR, lhs, lhs, rhs));
             if (node->init()) {
@@ -1209,7 +1209,7 @@ void CodeGenerator::Visit(MemberExpression *node, void *data) {
         left->Accept(this, &ret);
         long right = block_->NextRegisterId();
         auto value = exec_state_->string_table_->StringFromUTF8(node->member()->AsIdentifier()->GetName());
-        int tableIndex = func_state->AddConstant(std::move(value));
+        int tableIndex = func_state->AddConstant(Value(value));
         func_state->AddInstruction(CREATE_ABx(OP_LOADK, right, tableIndex));
         if (!node->ProduceRValue()) {
             func_state->AddInstruction(CREATE_ABC(OP_GETMEMBERVAR, ret, ret, right));
@@ -1223,7 +1223,7 @@ void CodeGenerator::Visit(MemberExpression *node, void *data) {
         left->Accept(this, &ret);
         long right = block_->NextRegisterId();
         auto value = exec_state_->string_table_->StringFromUTF8(node->member()->AsIdentifier()->GetName());
-        int tableIndex = func_state->AddConstant(std::move(value));
+        int tableIndex = func_state->AddConstant(Value(value));
         func_state->AddInstruction(CREATE_ABx(OP_LOADK, right, tableIndex));
         if (!node->ProduceRValue()) {
             func_state->AddInstruction(CREATE_ABC(OP_GETMEMBERVAR, ret, ret, right));
@@ -1260,7 +1260,7 @@ void CodeGenerator::Visit(Identifier *node, void *data) {
 
       FuncState* func_state = func_->func_state();
       auto value = exec_state_->string_table_->StringFromUTF8(node->GetName());
-      int tableIndex = func_state->AddConstant(std::move(value));
+      int tableIndex = func_state->AddConstant(Value(value));
 
       func_state->AddInstruction(
           CREATE_ABx(OP_LOADK, right, tableIndex));
@@ -1278,12 +1278,10 @@ void CodeGenerator::Visit(PrefixExpression *node, void *data) {
     long ret = data == nullptr ? block_->NextRegisterId()
                              : *static_cast<long *>(data);
     Handle<Expression> expr = node->expr();
-    long reg = -1;
+    long reg = block_->NextRegisterId();
     if (expr->IsIdentifier()) {
         reg = block_->FindRegisterId(expr->AsIdentifier()->GetName());
-    }
-    else {
-        reg = block_->NextRegisterId();
+    } else {
         expr->Accept(this, &reg);
     }
     PrefixOperation operation = node->op();
@@ -1566,8 +1564,8 @@ long CodeGenerator::BlockCnt::FindRegisterId(const std::string &name) {
             ValueRef *ref = parent()->FindValueRef(name, reg_ref);
             if (ref) {
                 BlockCnt *root_block = this;
-                while (root_block->children() && root_block->children()->func_state() == func_state_)
-                {
+                while (root_block->children() &&
+                       root_block->children()->func_state() == func_state_) {
                     root_block = root_block->children();
                 }
                 reg_ref = root_block->NextRegisterId();
diff --git a/weex_core/Source/core/data_render/exec_state.cc b/weex_core/Source/core/data_render/exec_state.cc
index 6ba2054..5016c43 100644
--- a/weex_core/Source/core/data_render/exec_state.cc
+++ b/weex_core/Source/core/data_render/exec_state.cc
@@ -274,6 +274,8 @@ void ExecState::CallFunction(Value *func, size_t argc, Value *ret) {
         if (ret) {
             *ret = result;
         }
+        // back to the top of params for clear register
+        *stack_->top() = func + 1;
         stack_->reset();
         frames_.pop_back();
     }
@@ -292,6 +294,8 @@ void ExecState::CallFunction(Value *func, size_t argc, Value *ret) {
         frames_.push_back(frame);
         resetArguments(func, argc);
         vm_->RunFrame(this, frame, ret);
+        // back to the top of params for clear register
+        *stack_->top() = func + 1;
         stack_->reset();
         frames_.pop_back();
     }
diff --git a/weex_core/Source/core/data_render/exec_state.h b/weex_core/Source/core/data_render/exec_state.h
index 398e73b..10dcce8 100644
--- a/weex_core/Source/core/data_render/exec_state.h
+++ b/weex_core/Source/core/data_render/exec_state.h
@@ -131,6 +131,7 @@ class FuncState {
   inline bool is_class_func() { return is_class_func_; }
   inline ClassInstance * &class_inst() { return class_inst_; }
   inline int &argc() { return argc_; }
+  inline const std::string &name() { return name_; }
   inline std::vector<long> &args() { return args_; }
   std::vector<FuncState *> all_childrens() {
       std::vector<FuncState *> all_childrens;
@@ -141,12 +142,15 @@ class FuncState {
       }
       return all_childrens;
   }
+
   inline std::vector<ValueRef *> &in_closure() { return in_closure_; }
   inline std::vector<ValueRef *> &out_closure() { return out_closure_; }
   inline int super_index() const { return super_index_; }
   inline void set_super_index(int super_index) { super_index_ = super_index; }
   inline std::vector<int32_t>& in_closure_refs() { return in_closure_refs_; }
   inline std::vector<int32_t>& out_closure_refs() { return out_closure_refs_; }
+  inline void set_name(const std::string& name) {name_ = name;}
+
  private:
   std::vector<Instruction> instructions_;
   std::vector<Value> constants_;
@@ -161,6 +165,7 @@ class FuncState {
   bool is_class_func_{false};
   ClassInstance *class_inst_{nullptr};
   int argc_{0};
+  std::string name_{""};
 };
         
 // TODO Each Func should contain a stack whose size is 256
@@ -191,6 +196,8 @@ class ExecState {
   ValueRef *FindRef(int index);
   void Register(const std::string& name, CFunction function);
   void Register(const std::string& name, Value value);
+  void AddEvent(const std::vector<std::string>& event) {event_queue_.push_back(event);}
+  void ClearEventQueue() {event_queue_.clear();}
   inline std::vector<ValueRef *> &refs() { return refs_; };
   inline Variables *global() { return global_.get(); }
   inline void reset(FuncState *func_state) { func_state_.reset(func_state); }
@@ -202,6 +209,9 @@ class ExecState {
   inline uint32_t global_compile_index() { return global_compile_index_; }
   inline uint32_t class_compile_index() { return class_compile_index_; }
   inline uint32_t string_compile_index() { return string_compile_index_; }
+  inline bool exec_js_finished() const {return exec_js_finished_;}
+  inline void set_exec_js_finished(bool exec_js_finished) {exec_js_finished_ = exec_js_finished;}
+  inline const std::vector<std::vector<std::string>>& event_queue() const {return event_queue_;}
   inline std::unordered_map<std::string, long>& global_variables() { return global_variables_; }
  private:
   friend class VM;
@@ -223,6 +233,8 @@ class ExecState {
   uint32_t global_compile_index_{0};
   uint32_t class_compile_index_{0};
   uint32_t string_compile_index_{0};
+  bool exec_js_finished_ = false;
+  std::vector<std::vector<std::string>> event_queue_;
 };
 
 }  // namespace data_render
diff --git a/weex_core/Source/core/data_render/exec_state_section.cc b/weex_core/Source/core/data_render/exec_state_section.cc
index c40df1c..b5754a0 100644
--- a/weex_core/Source/core/data_render/exec_state_section.cc
+++ b/weex_core/Source/core/data_render/exec_state_section.cc
@@ -1723,6 +1723,10 @@ uint32_t SectionFunction::size() {
             if (func_state->argc() > 0) {
                 size += GetFTLVLength(kValueFunctionArgs, sizeof(int32_t) * func_state->argc());
             }
+            if (!func_state->name().empty()) {
+                uint32_t length = static_cast<uint32_t>(func_state->name().length());
+                size += GetFTLVLength(kValueFunctionName, length);
+            }
             if (func_state->in_closure().size() > 0) {
                 size += GetFTLVLength(kValueFunctionInClosure, sizeof(int32_t) * (uint32_t)func_state->in_closure().size());
             }
@@ -1804,6 +1808,12 @@ bool SectionFunction::encoding() {
                     break;
                 }
             }
+            if (!func_state->name().empty()) {
+                uint32_t length = static_cast<uint32_t>(func_state->name().length());
+                if (!Section::encoding(kValueFunctionName, length, (uint8_t *)func_state->name().c_str())) {
+                    break;
+                }
+            }
             if (func_state->in_closure().size() > 0) {
                 size_t size = sizeof(int32_t) * func_state->in_closure().size();
                 int32_t *buffer = (int32_t *)malloc(size);
@@ -1958,6 +1968,22 @@ bool SectionFunction::decoding() {
                         func_state->argc() = readcnt;
                         break;
                     }
+                    case kValueFunctionName:
+                    {
+                        char *pstr = (char *)malloc(readbytes + 1);
+                        if (!pstr) {
+                            throw DecoderError("decoding read function low memory error");
+                            break;
+                        }
+                        memset(pstr, 0, readbytes + 1);
+                        if (stream->Read(pstr, 1, readbytes) != readbytes) {
+                            throw DecoderError("decoding read function error");
+                            break;
+                        }
+                        func_state->set_name(pstr);
+                        free(pstr);
+                        break;
+                    }
                     case kValueFunctionInstructions:
                     {
                         uint8_t *buffer = (uint8_t *)malloc(readbytes);
@@ -2106,13 +2132,24 @@ uint32_t SectionGlobalConstants::size() {
             break;
         }
         size += GetFTLVLength(kValueGlobalConstantsSize, sizeof(int32_t));
-        uint32_t constant_length = 0;
         for (uint32_t i = compile_index; i < global->size(); i++) {
+            size += GetFTLVLength(kValueGlobalConstantsValue, sizeof(int32_t));
             Value *value = global->Find(compile_index);
-            constant_length += GetValueLength(value);
+            uint32_t length = GetValueLength(value);
+            size += GetFTLVLength(kValueGlobalConstantsValue, length);
+
+            const std::map<std::string, int>& global_map =  global->map();
+            for (auto it : global_map) {
+                if (it.second == compile_index + i) {
+                    if (!it.first.empty()) {
+                        uint32_t length = static_cast<uint32_t>(it.first.length());
+                        size += GetFTLVLength(kValueGlobalConstantsName, length);
+                        break;
+                    }
+                }
+            }
         }
-        size += GetFTLVLength(kValueGlobalConstantsPayload, constant_length);
-        
+        size += GetFTLVLength(kValueGlobalConstantsFinished, sizeof(uint8_t));
     } while (0);
 
     return size;
@@ -2135,33 +2172,40 @@ bool SectionGlobalConstants::encoding() {
         if (!Section::encoding(kValueGlobalConstantsSize, sizeof(uint32_t), &constants_count)) {
             break;
         }
-        uint32_t constants_payload_length = 0;
-        for (int i = 0; i < constants_count; i++) {
-            Value *value = global->Find(compile_index + i);
-            constants_payload_length += GetValueLength(value);
-        }
-        uint8_t *buffer = (uint8_t *)malloc(constants_payload_length);
-        if (!buffer) {
-            throw EncoderError("low memory error");
-            break;
-        }
-        uint8_t *write_buffer = buffer;
-        uint32_t remain_length = constants_payload_length;
         for (int i = 0; i < constants_count; i++) {
             Value *value = global->Find(compile_index + i);
             uint32_t length = GetValueLength(value);
-            uint32_t bytes_write = Section::encodingValueToBuffer(write_buffer, remain_length, value);
+            uint8_t *buffer = (uint8_t *)malloc(length);
+            if (!buffer) {
+                throw EncoderError("low memory error");
+                break;
+            }
+
+            uint32_t bytes_write = Section::encodingValueToBuffer(buffer, length, value);
             if (bytes_write != length) {
                 throw EncoderError("encoding global constants value error");
                 break;
             }
-            remain_length -= bytes_write;
-            write_buffer += bytes_write;
-        }
-        if (!Section::encoding(kValueGlobalConstantsPayload, constants_payload_length, buffer)) {
-            break;
+            if (!Section::encoding(kValueGlobalConstantsValue, length, buffer)) {
+                throw EncoderError("encoding global constants value error");
+                break;
+            }
+            const std::map<std::string, int>& global_map =  global->map();
+            for (auto it : global_map) {
+                if (it.second == compile_index + i) {
+                    if (!it.first.empty()) {
+                        uint32_t length = static_cast<uint32_t>(it.first.length());
+                        if (!Section::encoding(kValueGlobalConstantsName, length, (uint8_t *)it.first.c_str())) {
+                            throw DecoderError("encoding global constants name  error");
+                            break;
+                        }
+                        break;
+                    }
+                }
+            }
+            free(buffer);
         }
-        free(buffer);
+
         finished = true;
         
     } while (0);
@@ -2186,25 +2230,7 @@ bool SectionGlobalConstants::decoding() {
         if (!readbytes || target != kValueGlobalConstantsSize || !constants_count) {
             break;
         }
-        if ((readbytes = stream->ReadTarget(&target, NULL, NULL)) == 0) {
-            throw DecoderError("decoding global constants target error");
-            break;
-        }
-        if (target != kValueGlobalConstantsPayload) {
-            break;
-        }
-        uint8_t *buffer = (uint8_t *)malloc(readbytes);
-        if (!buffer) {
-            throw DecoderError("low memory error");
-            break;
-        }
-        if (stream->Read(buffer, 1, readbytes) != readbytes) {
-            throw DecoderError("decoding global constants payload error");
-            break;
-        }
-        uint8_t *read_buffer = buffer;
-        uint32_t remain_length = readbytes;
-        uint32_t bytes_read = 0;
+
         Variables *global = decoder()->exec_state()->global();
         if (global->IndexOf("__weex_data__") < 0) {
             global->Set("__weex_data__", Value());
@@ -2212,21 +2238,75 @@ bool SectionGlobalConstants::decoding() {
         if (global->IndexOf("_init_data") < 0) {
             global->Set("_init_data", Value());
         }
+
+        bool read_target = true;
         for (int i = 0; i < constants_count; i++) {
+            if (read_target) {
+                if ((readbytes = stream->ReadTarget(&target, NULL, NULL)) == 0) {
+                    throw DecoderError("decoding global constants target error");
+                    break;
+                }
+            }
+            read_target = true;
+            if (target != kValueGlobalConstantsValue) {
+                throw DecoderError("decoding global constants target error");
+                break;
+            }
+            uint8_t *buffer = (uint8_t *)malloc(readbytes);
+            if (!buffer) {
+                throw DecoderError("low memory error");
+                break;
+            }
+            if (stream->Read(buffer, 1, readbytes) != readbytes) {
+                throw DecoderError("decoding global constants payload error");
+                break;
+            }
             Value value;
-            if (!(bytes_read = decodingValueFromBuffer(read_buffer, remain_length, &value))) {
-                throw DecoderError("decoding function constants payload error");
+            if (!decodingValueFromBuffer(buffer, readbytes, &value)) {
+                throw DecoderError("decoding global constants value error");
                 break;
             }
-            read_buffer += bytes_read;
-            remain_length -= bytes_read;
-            global->Add(value);
-        }
-        if (remain_length != 0) {
-            throw DecoderError("decoding function constants payload error");
-            break;
+            free(buffer);
+            if ((readbytes = stream->ReadTarget(&target, NULL, NULL)) == 0) {
+                throw DecoderError("decoding global constants target error");
+                break;
+            }
+            switch (target) {
+                case kValueGlobalConstantsName:
+                {
+                    char *name = (char *)malloc(readbytes + 1);
+                    if (!name) {
+                        throw DecoderError("decoding global constants low memory error");
+                        break;
+                    }
+                    memset(name, 0, readbytes + 1);
+                    if (stream->Read(name, 1, readbytes) != readbytes) {
+                        throw DecoderError("decoding global constants name error");
+                        break;
+                    }
+                    global->Add(name, value);
+                    free(name);
+                    break;
+                }
+                case kValueGlobalConstantsValue:
+                {
+                    global->Add(value);
+                    read_target = false;
+                    break;
+                }
+                case SECTION_VALUE_FINISHED:
+                {
+                    break;
+                }
+                default:
+                {
+                    if (stream->Seek(readbytes, SEEK_CUR) < 0) {
+                        throw DecoderError("decoding global constants error");
+                    }
+                    break;
+                }
+            }
         }
-        free(buffer);
         finished = true;
         
     } while (0);
diff --git a/weex_core/Source/core/data_render/exec_state_section.h b/weex_core/Source/core/data_render/exec_state_section.h
index 2989ba1..3770dfd 100644
--- a/weex_core/Source/core/data_render/exec_state_section.h
+++ b/weex_core/Source/core/data_render/exec_state_section.h
@@ -150,6 +150,7 @@ public:
         kValueFunctionSuper,
         kValueFunctionClass,
         kValueFunctionArgs,
+        kValueFunctionName,
         kValueFunctionInClosure,
         kValueFunctionOutClosure,
         kValueFunctionInstructions,
@@ -174,7 +175,9 @@ class SectionGlobalConstants : public Section {
 public:
     enum SectionKey {
         kValueGlobalConstantsSize,
-        kValueGlobalConstantsPayload,
+        kValueGlobalConstantsName,
+        kValueGlobalConstantsValue,
+        kValueGlobalConstantsFinished = 255,
     };
     SectionGlobalConstants(ExecStateEncoder *encoder) : Section(encoder) {}
     SectionGlobalConstants(ExecStateDecoder *decoder, uint32_t length) : Section(decoder, length) {}
diff --git a/weex_core/Source/core/data_render/object.cc b/weex_core/Source/core/data_render/object.cc
index 38f5814..fee0d2d 100644
--- a/weex_core/Source/core/data_render/object.cc
+++ b/weex_core/Source/core/data_render/object.cc
@@ -128,7 +128,7 @@ bool ValueStrictEquals(const Value *a, const Value *b) {
     else if (IsInt(a)) {
         return IntValue(a) == IntValue(b);
     }
-    else if (IsBool(a)) {
+    else if (IsBool(a) && IsBool(b)) {
         return BoolValue(a) == BoolValue(b);
     }
     else if (ToNum(a, d1) && ToNum(b, d2)) {
diff --git a/weex_core/Source/core/data_render/object.h b/weex_core/Source/core/data_render/object.h
index b551ca3..44df5f2 100644
--- a/weex_core/Source/core/data_render/object.h
+++ b/weex_core/Source/core/data_render/object.h
@@ -100,16 +100,16 @@ struct Value {
   Type type;
 
   Value() : type(NIL) {}
-    
-  Value(int value) : i(value), type(INT) {}
 
-  Value(int64_t value) : i(value), type(INT) {}
+  explicit Value(int value) : i(value), type(INT) {}
+
+  explicit Value(int64_t value) : i(value), type(INT) {}
 
-  Value(double value) : n(value), type(NUMBER) {}
+  explicit Value(double value) : n(value), type(NUMBER) {}
 
   explicit Value(bool value) : b(value), type(BOOL) {}
 
-  Value(String *value) : str(value), type(STRING) {}
+  explicit Value(String *value) : str(value), type(STRING) {}
     
   explicit Value(FuncState *func) : f(func), type(FUNC) {}
     
@@ -210,6 +210,8 @@ struct Value {
     friend bool operator!=(const Value &left, const Value &right) {
         return !(left == right);
     }
+    explicit operator bool() const noexcept
+    { return !(type == NIL); }
 };
     
 typedef struct Array {
@@ -623,19 +625,43 @@ inline void ArrayCopy(Value &src, Value &dest) {
 }
 
 inline void TableCopy(Value &src, Value &dest) {
-    Table *st = ValueTo<Table>(&src);
-    Table *dt = ValueTo<Table>(&dest);
-    for (auto iter = st->map.begin(); iter != st->map.end(); iter++) {
-        GCRetain(&iter->second);
-        dt->map[iter->first] = iter->second;
+  if (IsNil(&src)) {
+    return;
+  }
+  Table *st = ValueTo<Table>(&src);
+  Table *dt = ValueTo<Table>(&dest);
+  for (auto st_it = st->map.begin(); st_it != st->map.end(); st_it++) {
+    GCRetain(&st_it->second);
+    auto dt_it = dt->map.find(st_it->first);
+    if (dt_it != dt->map.end()) {
+      dt_it->second = st_it->second;
+    } else {
+      dt->map.insert({st_it->first, st_it->second});
     }
+  }
 }
 
-inline void TableMapAddAll(Table *src, Table *dest) {
-  for (auto iter = src->map.begin(); iter != src->map.end(); iter++) {
-    GCRetain(&iter->second);
-    dest->map[iter->first] = iter->second;
+inline bool TableAddAll(Value &src, Value &dest) {
+  bool updated = false;
+  if (IsNil(&src)) {
+    return updated;
+  }
+  Table *st = ValueTo<Table>(&src);
+  Table *dt = ValueTo<Table>(&dest);
+  for (auto st_it = st->map.begin(); st_it != st->map.end(); st_it++) {
+    GCRetain(&st_it->second);
+    auto dt_it = dt->map.find(st_it->first);
+    if (dt_it != dt->map.end()) {
+      if (dt_it->second != st_it->second) {
+        dt_it->second = st_it->second;
+        updated = true;
+      }
+    } else {
+      dt->map.insert({st_it->first, st_it->second});
+      updated = true;
+    }
   }
+  return updated;
 }
 
 }  // namespace data_render
diff --git a/weex_core/Source/core/data_render/parser.cc b/weex_core/Source/core/data_render/parser.cc
index 38a1815..fd8f6ef 100644
--- a/weex_core/Source/core/data_render/parser.cc
+++ b/weex_core/Source/core/data_render/parser.cc
@@ -18,19 +18,24 @@
  */
 
 #include "core/data_render/parser.h"
-#include <sstream>
 #include <cstdlib>
+#include <sstream>
 #include "base/string_util.h"
 #include "core/data_render/ast_factory.h"
 #include "core/data_render/rax_parser_builder.h"
 #include "core/data_render/rax_parser_context.h"
-#include "third_party/json11/json11.hpp"
 #include "core/data_render/statement.h"
+#include "third_party/json11/json11.hpp"
 
 namespace weex {
 namespace core {
 namespace data_render {
 
+static const char kCreateComponentRecursively[] =
+    "__createComponentRecursively";
+static const char kCreateBodyFunction[] = "main";
+static const char kAttrRepeatControl[] = "[[repeat]]";
+
 struct ASTParser final {
   /* State */
   const json11::Json& json_;
@@ -49,8 +54,7 @@ struct ASTParser final {
   }
 
   int GetTemplateId(const json11::Json& component) {
-    json11::Json json_template_id =
-        component["template_id"].type() == Json::Type::NUMBER;
+    json11::Json json_template_id = component["templateId"];
     if (json_template_id.type() == Json::Type::NUMBER) {
       return json_template_id.int_value();
     } else {
@@ -58,7 +62,24 @@ struct ASTParser final {
     }
   }
 
-    void AddAppendChildCall(json11::Json& json, Handle<Identifier>& parent_identifier,
+  inline void SetAttributeStatement(std::vector<Handle<Expression>> args,
+                                    Handle<BlockStatement>& block) {
+    Handle<Expression> set_attr_func_id = factory_->NewIdentifier("setAttr");
+    Handle<CallExpression> call_func =
+        factory_->NewCallExpression(set_attr_func_id, args);
+    block->PushExpression(call_func);
+  }
+
+  inline void AddEventStatement(std::vector<Handle<Expression>> args,
+                                Handle<BlockStatement>& block) {
+    Handle<Expression> set_attr_func_id = factory_->NewIdentifier("addEvent");
+    Handle<CallExpression> call_func =
+        factory_->NewCallExpression(set_attr_func_id, args);
+    block->PushExpression(call_func);
+  }
+
+  void AddAppendChildCall(json11::Json& json,
+                          Handle<Identifier>& parent_identifier,
                           Handle<Identifier>& child_identifier) {
     Handle<BlockStatement> statement = stacks_[stacks_.size() - 1];
 
@@ -71,10 +92,12 @@ struct ASTParser final {
     statement->PushExpression(call_append_expr);
   }
 
-    void AddSetClassListCall(json11::Json& json, Handle<weex::core::data_render::Identifier> child_identifier,
-                           const std::string& prefix) {
+  void AddSetClassListCall(
+      json11::Json& json,
+      Handle<weex::core::data_render::Identifier> child_identifier,
+      const std::string& prefix) {
     std::string wrap_prefix;
-    if (!prefix.empty()) {
+    if (!prefix.empty() && prefix.compare(kCreateBodyFunction) != 0) {
       wrap_prefix = "_" + prefix + "_";
     }
     json11::Json class_list = json["classList"];
@@ -87,8 +110,8 @@ struct ASTParser final {
         for (int i = 0; i < class_list.array_items().size(); i++) {
           json11::Json class_style = class_list[i];
           if (class_style.is_string()) {
-            args.push_back(
-                factory_->NewStringConstant(wrap_prefix + class_style.string_value()));
+            args.push_back(factory_->NewStringConstant(
+                wrap_prefix + class_style.string_value()));
           } else {
             args.push_back(factory_->NewBinaryExpression(
                 BinaryOperation::kAddition,
@@ -102,6 +125,35 @@ struct ASTParser final {
     }
   }
 
+  void AddEventForVNode(
+      const json11::Json& events,
+      Handle<weex::core::data_render::Identifier> child_identifier) {
+    if (!events.is_array()) return;
+    for (auto it = events.array_items().begin();
+         it != events.array_items().end(); it++) {
+      auto event = *it;
+      if (event.is_object()) {
+        auto event_type = event["type"];
+        auto params = event["params"];
+        Handle<StringConstant> event_constant =
+            factory_->NewStringConstant(event_type.string_value());
+        std::vector<Handle<Expression>> args{child_identifier, event_constant};
+        if (params.is_array()) {
+          for (auto jt = params.array_items().begin();
+               jt != params.array_items().end(); jt++) {
+            args.push_back(ParseExpression(*jt));
+          }
+        }
+        AddEventStatement(args, stacks_[stacks_.size() - 1]);
+      } else if (event.is_string()) {
+        Handle<StringConstant> event_constant =
+            factory_->NewStringConstant(event.string_value());
+        AddEventStatement({child_identifier, event_constant},
+                          stacks_[stacks_.size() - 1]);
+      }
+    }
+  }
+
   ParseResult Parse() {
     ASTParseError error = UNKOWN_ERROR;
     do {
@@ -121,7 +173,8 @@ struct ASTParser final {
       stacks_.push_back(chunk);
       auto& component = json["components"];
       if (component.is_array()) {
-        for (auto it = component.array_items().begin(); it != component.array_items().end(); it++) {
+        for (auto it = component.array_items().begin();
+             it != component.array_items().end(); it++) {
           if (!it->is_object()) {
             continue;
           }
@@ -148,7 +201,7 @@ struct ASTParser final {
         break;
       }
       RAXParserBuilder builder(match.string_value());
-      RAXParser *parser = builder.parser();
+      RAXParser* parser = builder.parser();
       Handle<Expression> expr = parser->ParseExpression();
       Handle<Expression> if_block =
           MakeHandle<BlockStatement>(factory_->NewExpressionList());
@@ -169,7 +222,9 @@ struct ASTParser final {
       json11::Json index = repeat["iterator1"];
       Handle<DeclarationList> for_init = factory_->NewDeclarationList();
       // var index=0
-      for_init->Append(factory_->NewDeclaration(index.is_null() ? "index" : index.string_value(), factory_->NewIntegralConstant(0)));
+      for_init->Append(factory_->NewDeclaration(
+          index.is_null() ? "index" : index.string_value(),
+          factory_->NewIntegralConstant(0)));
       json11::Json expression = repeat["for"];
       if (!expression.is_string()) {
         break;
@@ -179,34 +234,32 @@ struct ASTParser final {
         break;
       }
       RAXParserBuilder builder(expression.string_value());
-      RAXParser *parser = builder.parser();
+      RAXParser* parser = builder.parser();
       Handle<Expression> list_expr = parser->ParseExpression();
-      Handle<Identifier> index_var =
-          factory_->NewIdentifier(index.is_null() ? "index" : index.string_value());
+      Handle<Identifier> index_var = factory_->NewIdentifier(
+          index.is_null() ? "index" : index.string_value());
       // expr[index]
       Handle<MemberExpression> indexMember = factory_->NewMemberExpression(
           MemberAccessKind::kIndex, list_expr, index_var);
       // var iter = expr[index]
       for_init->Append(
           factory_->NewDeclaration(alias.string_value(), indexMember));
-      Handle<Identifier> size_of_func_id =
-          factory_->NewIdentifier("sizeof");
+      Handle<Identifier> size_of_func_id = factory_->NewIdentifier("sizeof");
       // sizeof(expr)
       Handle<CallExpression> size_of_call =
-        factory_->NewCallExpression(size_of_func_id, {list_expr});
+          factory_->NewCallExpression(size_of_func_id, {list_expr});
 
       // index<sizeof(expr)
-      Handle<Expression> for_condition = factory_->NewBinaryExpression(BinaryOperation::kLessThan, index_var, size_of_call);
+      Handle<Expression> for_condition = factory_->NewBinaryExpression(
+          BinaryOperation::kLessThan, index_var, size_of_call);
       // index++
-      Handle<Expression> index_update = factory_->NewPrefixExpression(PrefixOperation::kIncrement, index_var);
+      Handle<Expression> index_update =
+          factory_->NewPrefixExpression(PrefixOperation::kIncrement, index_var);
       // iter = expr[index]
       Handle<Expression> alias_update = factory_->NewAssignExpression(
           factory_->NewIdentifier(alias.string_value()),
-          factory_->NewMemberExpression(
-              MemberAccessKind::kIndex,
-              list_expr, index_var
-          )
-      );
+          factory_->NewMemberExpression(MemberAccessKind::kIndex, list_expr,
+                                        index_var));
       std::vector<Handle<Expression>> updates;
       updates.push_back(index_update);
       updates.push_back(alias_update);
@@ -214,9 +267,8 @@ struct ASTParser final {
 
       Handle<Expression> for_block =
           MakeHandle<BlockStatement>(factory_->NewExpressionList());
-      for_expr =
-          factory_->NewForStatement(ForKind::kForOf, for_init,
-                                    for_condition, for_update, for_block);
+      for_expr = factory_->NewForStatement(
+          ForKind::kForOf, for_init, for_condition, for_update, for_block);
       if (!for_expr) {
         break;
       }
@@ -247,19 +299,60 @@ struct ASTParser final {
     return exprs;
   }
 
+  inline Handle<Expression> ParseExpression(const json11::Json& json) {
+    if (json.is_string()) {
+      return factory_->NewStringConstant(json.string_value());
+    } if (json.is_number()) {
+        return factory_->NewIntegralConstant(json.number_value());
+    } else {
+      return ParseBindingExpression(json);
+    }
+  }
+
   Handle<Expression> ParseBindingExpression(const json11::Json& json) {
     const json11::Json& exp_str = json["@binding"];
     if (exp_str.is_string()) {
       RAXParserBuilder builder(exp_str.string_value());
-      RAXParser *parser = builder.parser();
+      RAXParser* parser = builder.parser();
       return parser->ParseExpression();
-    }
-    else {
+    } else {
       return factory_->NewNullConstant();
     }
   }
 
-  //function createComponent_xxx(nodeId, this){
+  std::string ParseCreateNodeInComponentFunction(
+      json11::Json& template_object, const std::string& component_name) {
+    std::string function_name("createNodeInComponent_" + component_name);
+
+    // Declare function createNodeInComponent_xxx(this)
+    std::vector<std::string> proto_args;
+    proto_args.push_back("this");
+    proto_args.push_back("component");
+    proto_args.push_back(kCreateComponentRecursively);
+    Handle<FunctionPrototype> func_proto =
+        factory_->NewFunctionPrototype(function_name, proto_args);
+    Handle<BlockStatement> func_body =
+        factory_->NewBlockStatement(factory_->NewExpressionList());
+
+    stacks_.push_back(func_body);
+
+    // ParseNode
+    ParseNode(template_object, true, component_name);
+
+    // Declare return
+    func_body->statements()->Insert(
+        factory_->NewReturnStatement(factory_->NewIdentifier("child")));
+    stacks_.pop_back();
+
+    Handle<FunctionStatement> func_decl =
+        factory_->NewFunctionStatement(func_proto, func_body);
+    Handle<BlockStatement> chunk = stacks_.front();
+    // Declare createNodeInComponent function in global
+    chunk->statements()->Insert(func_decl);
+    return function_name;
+  }
+
+  // function createComponent_xxx(nodeId, this){
   //  //initialState
   //  this = {
   //    count: this.start
@@ -274,118 +367,153 @@ struct ASTParser final {
   //
   //  //return function
   //  return child;
-  void ParseComponentFunction(json11::Json& json) {
+  std::string ParseComponentFunction(json11::Json& json) {
     auto& name = json["name"];
-    auto& initial_state = json["initialState"];
     json11::Json template_obj = json["template"];
     int template_id = GetTemplateId(json);
 
-    Handle<BlockStatement> chunk = stacks_.back();
-
     if (!name.is_string() || !template_obj.is_object()) {
-      return;
+      return "";
     }
 
-    std::string function_name("createComponent_" + name.string_value());
+    return ParseComponentFunction(template_obj, name.string_value(),
+                                  template_id, false);
+  }
+
+  std::string ParseComponentFunction(json11::Json& template_obj,
+                                     const std::string& template_name,
+                                     int template_id, bool is_body) {
+    Handle<BlockStatement> chunk = stacks_.back();
+
+    std::string function_name("createComponent_" + template_name);
 
-    //function createComponent_xxx(nodeId, this)
+    // Make function createComponent_xxx(this)
     std::vector<std::string> proto_args;
-    proto_args.push_back("nodeId");
     proto_args.push_back("this");
+    proto_args.push_back(kCreateComponentRecursively);
     Handle<FunctionPrototype> func_proto =
         factory_->NewFunctionPrototype(function_name, proto_args);
     Handle<BlockStatement> func_body =
         factory_->NewBlockStatement(factory_->NewExpressionList());
 
-    //{
     stacks_.push_back(func_body);
-    //initialState
-    //  this = {
-    //    count: this.start
-    //  }
-    if (initial_state.is_object() && initial_state.object_items().size() > 0) {
-      ProxyObject initial_obj;
-      for (auto it = initial_state.object_items().begin();
-           it != initial_state.object_items().end(); it++) {
-        const auto& key = it->first;
-        const auto& value = it->second;
-        Handle<Expression> expr_value;
-        if (value.is_string()) {
-          expr_value = factory_->NewStringConstant(value.string_value());
-        } else {
-          expr_value = ParseBindingExpression(value);
-        }
-        initial_obj.insert({key, expr_value});
-      }
-      func_body->statements()->Insert(factory_->NewAssignExpression(
-          factory_->NewIdentifier("this"),
-          factory_->NewObjectConstant(initial_obj)
-      ));
-    }
+
     func_body->statements()->Insert(factory_->NewDeclaration(
         "template_id", factory_->NewIntegralConstant(template_id)));
     func_body->statements()->Insert(factory_->NewDeclaration(
-        "template_name", factory_->NewStringConstant(name.string_value())));
-
-    //ParseNode
-    ParseNode(template_obj, true, name.string_value());
+        "template_name", factory_->NewStringConstant(template_name)));
 
-    //return function
-    func_body->statements()->Insert(factory_->NewReturnStatement(factory_->NewIdentifier("child")));
+    std::vector<Handle<Expression>> merge_args;
+    Handle<Identifier> component_data = factory_->NewMemberExpression(
+        MemberAccessKind::kDot, factory_->NewIdentifier("_components_data"),
+        factory_->NewIdentifier(template_name));
+    Handle<Declaration> data_declaration =
+        factory_->NewDeclaration("data", component_data);
+    Handle<Identifier> component_props = factory_->NewMemberExpression(
+        MemberAccessKind::kDot, factory_->NewIdentifier("_components_props"),
+        factory_->NewIdentifier(template_name));
+    Handle<Declaration> props_declaration =
+        factory_->NewDeclaration("props", component_props);
+    Handle<Identifier> component_computed = factory_->NewMemberExpression(
+        MemberAccessKind::kDot, factory_->NewIdentifier("_components_computed"),
+        factory_->NewIdentifier(template_name));
+    Handle<Declaration> computed_declaration =
+        factory_->NewDeclaration("computed", component_computed);
+    func_body->PushExpression(data_declaration);
+    func_body->PushExpression(props_declaration);
+    func_body->PushExpression(computed_declaration);
+
+    // Update props
+    merge_args.clear();
+    merge_args.push_back(factory_->NewIdentifier("props"));
+    merge_args.push_back(factory_->NewIdentifier("this"));
+    func_body->PushExpression(factory_->NewAssignExpression(
+        factory_->NewIdentifier("props"),
+        factory_->NewCallExpression(factory_->NewIdentifier("merge"),
+                                    merge_args)));
+
+    // Declare createNodeInComponent function in global
+    const std::string& create_node_func =
+        ParseCreateNodeInComponentFunction(template_obj, template_name);
+
+    // Component Node call createComponent
+    Handle<Expression> func = factory_->NewIdentifier("createComponent");
+    std::vector<Handle<Expression>> args;
+    args.push_back(factory_->NewIdentifier("template_id"));
+    args.push_back(factory_->NewIdentifier("template_name"));
+    args.push_back(factory_->NewStringConstant(create_node_func));
+    Handle<Declaration> component_declaration = factory_->NewDeclaration(
+        "component", factory_->NewCallExpression(func, args));
+    func_body->statements()->Insert(component_declaration);
+    args.clear();
+    args.push_back(factory_->NewIdentifier("component"));
+    args.push_back(factory_->NewIdentifier("props"));
+    args.push_back(factory_->NewIdentifier("data"));
+    func_body->statements()->Insert(factory_->NewCallExpression(
+        factory_->NewIdentifier("saveComponentPropsAndData"), args));
+
+    // if (PreventCreateComponentRecursively) {
+    //    this = merge(props, this);
+    //    this = merge(data, this);
+    //    createNodeInComponent(this);
+    // }
+    args.clear();
+    auto if_expression_list = factory_->NewExpressionList();
+    // merge props
+    if_expression_list->Insert(factory_->NewAssignExpression(
+        factory_->NewIdentifier("this"), factory_->NewIdentifier("props")));
+    // merge data
+    merge_args.clear();
+    merge_args.push_back(factory_->NewIdentifier("data"));
+    merge_args.push_back(factory_->NewIdentifier("this"));
+    if_expression_list->Insert(factory_->NewAssignExpression(
+        factory_->NewIdentifier("this"),
+        factory_->NewCallExpression(factory_->NewIdentifier("merge"),
+                                    merge_args)));
+    // merge computed
+    merge_args.clear();
+    merge_args.push_back(factory_->NewIdentifier("computed"));
+    merge_args.push_back(factory_->NewIdentifier("this"));
+    if_expression_list->Insert(factory_->NewAssignExpression(
+        factory_->NewIdentifier("this"),
+        factory_->NewCallExpression(factory_->NewIdentifier("merge"),
+                                    merge_args)));
+
+    args.clear();
+    args.push_back(factory_->NewIdentifier("this"));
+    args.push_back(factory_->NewIdentifier("component"));
+    args.push_back(factory_->NewIdentifier(kCreateComponentRecursively));
+    auto call_create_node = factory_->NewCallExpression(
+        factory_->NewIdentifier(create_node_func), args);
+    if_expression_list->Insert(call_create_node);
+    auto if_block = factory_->NewBlockStatement(if_expression_list);
+    auto if_stat = factory_->NewIfStatement(
+        factory_->NewIdentifier(kCreateComponentRecursively), if_block);
+    func_body->statements()->Insert(if_stat);
+
+    // return function
+    func_body->statements()->Insert(
+        factory_->NewReturnStatement(factory_->NewIdentifier("component")));
     stacks_.pop_back();
-    //}
+
+    // Declare createComponent function in global
     Handle<FunctionStatement> func_decl =
         factory_->NewFunctionStatement(func_proto, func_body);
     chunk->statements()->Insert(func_decl);
+    return function_name;
   }
 
-  //function main(this);
+  // function main(this);
   bool ParseBodyFunction(json11::Json& body) {
-    std::vector<std::string> proto_args;
-    proto_args.push_back("this");
-    Handle<FunctionPrototype> main_func_proto =
-        factory_->NewFunctionPrototype("main", proto_args);
-    Handle<BlockStatement> main_func_body =
-        factory_->NewBlockStatement(factory_->NewExpressionList());
-    //{
-    stacks_.push_back(main_func_body);
-    // var parent = null;
-    main_func_body->PushExpression(factory_->NewDeclaration("parent"));
-    main_func_body->PushExpression(factory_->NewDeclaration(
-        "template_id", factory_->NewIntegralConstant(GetTemplateId(body))));
-    main_func_body->PushExpression(factory_->NewDeclaration(
-        "template_name", factory_->NewStringConstant("body")));
-    // body is considered as a component
-    ParseNode(body, true, "");
-
-    stacks_.pop_back();
-    //}
-    Handle<FunctionStatement> main_func_decl = factory_->NewFunctionStatement(main_func_proto,
-                                                                              main_func_body);
+    const std::string& main =
+        ParseComponentFunction(body, kCreateBodyFunction, 0, true);
     Handle<BlockStatement> chunk = stacks_[stacks_.size() - 1];
-
-    //function main(this);
-    chunk->statements()->Insert(main_func_decl);
-
     std::vector<Handle<Expression>> args;
-    std::vector<Handle<Expression>> merge_args;
-
-    merge_args.push_back(factory_->NewIdentifier("_data_main"));
-    merge_args.push_back(factory_->NewIdentifier("_init_data"));
-
-    //merge(_data_main,_init_data)
-    args.push_back(
-        factory_->NewCallExpression(
-            factory_->NewIdentifier("merge"),
-            merge_args
-        )
-    );
-
-    //main(merge(_data_main,_init_data)
-    chunk->statements()->Insert(factory_->NewCallExpression(
-        factory_->NewIdentifier("main"),
-        args
-    ));
+    args.push_back(factory_->NewIdentifier("_init_data"));
+    args.push_back(factory_->NewBooleanConstant(true));
+    // main(merge(_data_main,_init_data)
+    chunk->statements()->Insert(
+        factory_->NewCallExpression(factory_->NewIdentifier(main), args));
     return true;
   }
 
@@ -394,8 +522,7 @@ struct ASTParser final {
         factory_->NewIdentifier("parent");
     static Handle<Identifier> child_identifier =
         factory_->NewIdentifier("child");
-    static Handle<Identifier> attr_identifier =
-        factory_->NewIdentifier("attr");
+    static Handle<Identifier> attr_identifier = factory_->NewIdentifier("attr");
 
     json11::Json control = json["control"];
     std::vector<Handle<Expression>> control_exprs;
@@ -407,14 +534,14 @@ struct ASTParser final {
     json11::Json component_alias = json["componentAlias"];
 
     if (node_id.is_string() && tag_name.is_string()) {
-      const std::string& component_real_name = component_alias[tag_name.string_value()].string_value();
-
+      const std::string& component_real_name =
+          component_alias[tag_name.string_value()].string_value();
 
       Handle<Expression> call_expr = nullptr;
       Handle<BlockStatement> statement = stacks_[stacks_.size() - 1];
       std::vector<Handle<Expression>> args;
 
-      //var attr = { key1:value1 }
+      // var attr = { key1:value1 }
       ProxyObject attr_obj;
       json11::Json attributes = json["attributes"];
       if (attributes.is_object()) {
@@ -433,78 +560,40 @@ struct ASTParser final {
       }
 
       Handle<ObjectConstant> attr_init = factory_->NewObjectConstant(attr_obj);
-      // merge data props into attr_decl
-      // attr = merge(merge(data, props), attr)
-      Handle<Identifier> component_data = factory_->NewMemberExpression(
-          MemberAccessKind::kDot, factory_->NewIdentifier("_components_data"),
-          factory_->NewIdentifier("template_name"));
-      Handle<Identifier> component_props = factory_->NewMemberExpression(
-          MemberAccessKind::kDot, factory_->NewIdentifier("_components_props"),
-          factory_->NewIdentifier("template_name"));
-      std::vector<Handle<Expression>> merge_args1;
-      merge_args1.push_back(component_data);
-      merge_args1.push_back(component_props);
-      std::vector<Handle<Expression>> merge_args2;
-      merge_args2.push_back(factory_->NewCallExpression(
-          factory_->NewIdentifier("merge"), merge_args1));
-      merge_args2.push_back(attr_init);
-      Handle<Declaration> attr_decl = factory_->NewDeclaration(
-          "attr", factory_->NewCallExpression(factory_->NewIdentifier("merge"),
-                                              merge_args2));
-      statement->PushExpression(attr_decl);
 
       // var child = createComponent_xxx("node_id", attr);
       {
-        //createComponent_xxx("node_id", attr))
-        Handle<Expression> func = factory_->NewIdentifier("createComponent_" + component_real_name);
+        // createComponent_xxx("node_id", attr))
+        Handle<Expression> func =
+            factory_->NewIdentifier("createComponent_" + component_real_name);
 
-        args.push_back(ParseNodeId(control, control_exprs, node_id.string_value()));
-        args.push_back(attr_identifier);
+        args.push_back(attr_init);
+        args.push_back(factory_->NewIdentifier(kCreateComponentRecursively));
 
         // var child = createComponent_xxx("node_id", attr);
         call_expr = factory_->NewCallExpression(func, args);
         Handle<Declaration> child_declaration =
             factory_->NewDeclaration("child", call_expr);
         statement->PushExpression(child_declaration);
-
-        // addChildComponent(component, child)
-        args.clear();
-        Handle<Identifier> component_identifier =
-            factory_->NewIdentifier("component");
-        args.push_back(component_identifier);
-        args.push_back(child_identifier);
-        statement->PushExpression(factory_->NewCallExpression(
-            factory_->NewIdentifier("appendChildComponent"), args));
-
-        // saveComponentDataAndProps(component, data, props)
-        args.clear();
-        args.push_back(child_identifier);
-        args.push_back(component_data);
-        args.push_back(component_props);
-        statement->PushExpression(factory_->NewCallExpression(
-                factory_->NewIdentifier("saveComponentDataAndProps"), args));
       }
 
-      //appendChild(parent, child);
+      // appendChild(parent, child);
       AddAppendChildCall(json, parent_identifier, child_identifier);
-
-      //setClassList(child, class_name);
-      AddSetClassListCall(json, child_identifier, component_name);
     }
     for (int i = 0; i < control_exprs.size(); i++) {
-        stacks_.pop_back();
+      stacks_.pop_back();
     }
     return true;
   }
-  Handle<Expression> ParseNodeId(const json11::Json& body,
-                                 const std::vector<Handle<Expression>>& control_exprs,
-                                 const std::string& node_id) {
+  Handle<Expression> ParseNodeId(
+      const json11::Json& body,
+      const std::vector<Handle<Expression>>& control_exprs,
+      const std::string& node_id) {
     Handle<Expression> node_id_expr = nullptr;
     node_id_expr = this->factory_->NewStringConstant(node_id);
     return node_id_expr;
   }
 
-
   // Code Detail:
   //    var parent = nil;
   //    var child = createElement(tag_name, node_id);
@@ -548,7 +637,8 @@ struct ASTParser final {
   //        setClassList(child, class_name);
   //      end for / end if
   //    }
-  bool ParseNode(json11::Json& json, bool component_root, const std::string& component_name) {
+  bool ParseNode(json11::Json& json, bool component_root,
+                 const std::string& component_name) {
     static Handle<Identifier> parent_identifier =
         factory_->NewIdentifier("parent");
     static Handle<Identifier> child_identifier =
@@ -559,11 +649,19 @@ struct ASTParser final {
       std::vector<Handle<Expression>> control_exprs;
       if (control.is_object()) {
         control_exprs = ParseControl(control);
+        if (!control["repeat"].is_null()) {
+          SetAttributeStatement(
+              {child_identifier,
+               factory_->NewStringConstant(kAttrRepeatControl),
+               factory_->NewStringConstant("")},
+              stacks_[stacks_.size() - 1]);
+        }
       }
       json11::Json node_id = json["nodeId"];
       json11::Json tag_name = json["tagName"];
       json11::Json ref = json11::Json("");
-      if (json["attributes"].is_object() && json["attributes"]["ref"].is_string()) {
+      if (json["attributes"].is_object() &&
+          json["attributes"]["ref"].is_string()) {
         ref = json["attributes"]["ref"];
       }
       Handle<Expression> node_id_expr = nullptr;
@@ -573,43 +671,24 @@ struct ASTParser final {
         std::vector<Handle<Expression>> args;
 
         // var child = createElement(tag_name, node_id, ref);
-        // or
-        // var child = createComponent(template_id, tag_name, node_id, ref);
         {
-            Handle<Expression> func;
-            node_id_expr = ParseNodeId(control, control_exprs, node_id.string_value());
-            if (!component_root) {
-                // Common Node call createElement function
-                func = factory_->NewIdentifier("createElement");
-                args.push_back(
-                        factory_->NewStringConstant(tag_name.string_value()));
-                args.push_back(node_id_expr);
-                args.push_back(factory_->NewStringConstant(ref.string_value()));
-                call_expr = factory_->NewCallExpression(func, args);
-            } else {
-                // Component Node call createComponent
-                Handle<Expression> func =
-                        factory_->NewIdentifier("createComponent");
-                args.push_back(
-                        factory_->NewIdentifier("template_id"));
-                args.push_back(
-                        factory_->NewIdentifier("template_name"));
-                args.push_back(
-                        factory_->NewStringConstant(tag_name.string_value()));
-                args.push_back(node_id_expr);
-                args.push_back(factory_->NewStringConstant(ref.string_value()));
-                call_expr = factory_->NewCallExpression(func, args);
-            }
-            Handle<Declaration> child_declaration =
-                    factory_->NewDeclaration("child", call_expr);
-            statement->PushExpression(child_declaration);
-            if (component_root) {
-                // One createComponent method has one component field for
-                // build component tree
-                Handle<Declaration> component_declaration =
-                        factory_->NewDeclaration("component", child_identifier);
-                statement->PushExpression(component_declaration);
-            }
+          Handle<Expression> func = factory_->NewIdentifier("createElement");
+          node_id_expr =
+              ParseNodeId(control, control_exprs, node_id.string_value());
+          args.push_back(factory_->NewStringConstant(tag_name.string_value()));
+          args.push_back(node_id_expr);
+          args.push_back(factory_->NewStringConstant(ref.string_value()));
+          call_expr = factory_->NewCallExpression(func, args);
+          Handle<Declaration> child_declaration =
+              factory_->NewDeclaration("child", call_expr);
+          statement->PushExpression(child_declaration);
+          if (component_root) {
+            args.clear();
+            args.push_back(factory_->NewIdentifier("component"));
+            args.push_back(child_identifier);
+            statement->PushExpression(factory_->NewCallExpression(
+                factory_->NewIdentifier("setComponentRoot"), args));
+          }
         }
         if (!component_root) {
           // appendChild(parent, child);
@@ -631,19 +710,34 @@ struct ASTParser final {
           args.push_back(child_identifier);
           args.push_back(factory_->NewStringConstant(key));
           if (value.is_string()) {
-            args.push_back(
-                    factory_->NewStringConstant(value.string_value()));
+            args.push_back(factory_->NewStringConstant(value.string_value()));
           } else {
             args.push_back(ParseBindingExpression(value));
           }
 
           Handle<Expression> set_style_func_expr =
-                  factory_->NewIdentifier("setStyle");
+              factory_->NewIdentifier("setStyle");
           Handle<CallExpression> call_func =
-                  factory_->NewCallExpression(set_style_func_expr, args);
+              factory_->NewCallExpression(set_style_func_expr, args);
           Handle<BlockStatement> statement = stacks_[stacks_.size() - 1];
           statement->PushExpression(call_func);
         }
+      } else if (style.is_array()) {
+        auto items = style.array_items();
+        for (auto it = items.begin(); it != items.end(); ++it) {
+          auto item = *it;
+          if (item.is_object()) {
+            std::vector<Handle<Expression>> args;
+            args.push_back(child_identifier);
+            args.push_back(ParseBindingExpression(item));
+            Handle<Expression> set_style_func_expr =
+                    factory_->NewIdentifier("setStyle");
+            Handle<CallExpression> call_func =
+                    factory_->NewCallExpression(set_style_func_expr, args);
+            Handle<BlockStatement> statement = stacks_[stacks_.size() - 1];
+            statement->PushExpression(call_func);
+          }
+        }
       }
 
       // setAttr(child, key, value)
@@ -653,25 +747,34 @@ struct ASTParser final {
         for (auto it = items.begin(); it != items.end(); ++it) {
           const auto& key = it->first;
           const auto& value = it->second;
-          std::vector<Handle<Expression>> args;
-          args.push_back(child_identifier);
-          args.push_back(factory_->NewStringConstant(key));
+          Handle<Expression> value_statements;
           if (value.is_string()) {
-            args.push_back(
-                factory_->NewStringConstant(value.string_value()));
+            value_statements =
+                factory_->NewStringConstant(value.string_value());
+          } else if (value.is_array()) {
+            for (auto jt = value.array_items().begin();
+                 jt != value.array_items().end(); jt++) {
+              if (value_statements) {
+                value_statements = factory_->NewBinaryExpression(
+                    BinaryOperation::kAddition, value_statements,
+                    ParseExpression(*jt));
+              } else {
+                value_statements = ParseExpression(*jt);
+              }
+            }
           } else {
-            args.push_back(ParseBindingExpression(value));
+            value_statements = ParseBindingExpression(value);
           }
-
-          Handle<Expression> set_attr_func_id =
-              factory_->NewIdentifier("setAttr");
-          Handle<CallExpression> call_func =
-              factory_->NewCallExpression(set_attr_func_id, args);
-          Handle<BlockStatement> statement = stacks_[stacks_.size() - 1];
-          statement->PushExpression(call_func);
+          SetAttributeStatement(
+              {child_identifier, factory_->NewStringConstant(key),
+               value_statements},
+              stacks_[stacks_.size() - 1]);
         }
       }
 
+      // addEvent
+      AddEventForVNode(json["event"], child_identifier);
+
       // new block for appending grandson
       // {
       //    var parent = child;
diff --git a/weex_core/Source/core/data_render/string_table.h b/weex_core/Source/core/data_render/string_table.h
index 5d1dddd..568c023 100644
--- a/weex_core/Source/core/data_render/string_table.h
+++ b/weex_core/Source/core/data_render/string_table.h
@@ -34,7 +34,7 @@ class String {
   explicit String(const std::string &str);
   ~String();
 
-  char *c_str() { return str_.get(); }
+  char *c_str() const { return str_.get(); }
 
   std::size_t length() { return length_; }
 
diff --git a/weex_core/Source/core/data_render/vm.cc b/weex_core/Source/core/data_render/vm.cc
index 000fa4d..b9331df 100644
--- a/weex_core/Source/core/data_render/vm.cc
+++ b/weex_core/Source/core/data_render/vm.cc
@@ -646,7 +646,7 @@ void VM::RunFrame(ExecState *exec_state, Frame frame, Value *ret) {
             if (IsValueRef(b)) {
                 b = b->var;
             }
-            if (!IsClassInstance(b) && !IsClass(b) && !IsArray(b) && !IsTable(b) && !IsString(b)) {
+            if (!IsClassInstance(b) && !IsClass(b) && !IsArray(b) && !IsTable(b) && !IsString(b) && !IsNil(b)) {
                 throw VMExecError("Type Error For Class Instance Or Class With OP_CODE [OP_GETMEMBER]");
             }
             if (!IsString(c)) {
@@ -699,10 +699,11 @@ void VM::RunFrame(ExecState *exec_state, Frame frame, Value *ret) {
                 Variables *funcs = ValueTo<ClassDescriptor>(class_desc)->funcs_.get();
                 index = funcs->IndexOf(var_name);
                 if (index < 0) {
-                    throw VMExecError("Can't Find String Func " + var_name + " With OP_CODE [OP_GETMEMBER]");
+                    SetNil(a);
+                } else {
+                    Value *func = funcs->Find(index);
+                    *a = *func;
                 }
-                Value *func = funcs->Find(index);
-                *a = *func;
             }
             else if (IsTable(b)) {
                 if (op == OP_GETMEMBER) {
@@ -721,6 +722,9 @@ void VM::RunFrame(ExecState *exec_state, Frame frame, Value *ret) {
                     }
                 }
             }
+            else if (IsNil(b)) {
+                SetNil(a);
+            }
             else {
                 // only can find class static funcs;
                 Variables *statics = ValueTo<ClassDescriptor>(b)->statics_.get();
@@ -889,10 +893,13 @@ void VM::RunFrame(ExecState *exec_state, Frame frame, Value *ret) {
                 Value *ret = GetTableValue(ValueTo<Table>(b), *c);
                 if (!IsNil(ret)) {
                     *a = *ret;
-                }
-                else {
+                } else {
                     SetNil(a);
                 }
+            } else if (IsString(b)) {
+                //LOGE("type String can not get from index");
+            } else if (IsNil(b)) {
+                SetNil(a);
             }
             else {
                 throw VMExecError("Unsupport Type Error With OP_CODE [OP_GETINDEX]");
diff --git a/weex_core/Source/core/data_render/vnode/android/conversion.cc b/weex_core/Source/core/data_render/vnode/android/conversion.cc
new file mode 100644
index 0000000..9248dd1
--- /dev/null
+++ b/weex_core/Source/core/data_render/vnode/android/conversion.cc
@@ -0,0 +1,81 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#ifdef OS_ANDROID
+
+#include "core/data_render/vnode/android/conversion.h"
+#include "android/utils/params_utils.h"
+#include "core/data_render/exec_state.h"
+#include "core/data_render/object.h"
+#include "core/manager/weex_core_manager.h"
+#include "wson/wson.h"
+#include "wson/wson_parser.h"
+
+namespace weex {
+namespace core {
+namespace data_render {
+
+json11::Json Conversion::GenJSON(const Value* v) {
+  switch (v->type) {
+    case Value::Type::NUMBER:
+      return v->n;
+    case Value::Type::STRING:
+      return v->str->c_str();
+    case Value::Type::INT:
+      return static_cast<int>(v->i);
+    case Value::Type::BOOL:
+      return v->b;
+    case Value::Type::ARRAY: {
+      Array* array = ValueTo<Array>(v);
+      std::vector<json11::Json> json_array;
+      for (auto it = array->items.begin(); it != array->items.end(); it++) {
+        json_array.push_back(GenJSON(&*it));
+      }
+      return json_array;
+    }
+    case Value::Type::TABLE: {
+      Table* table = ValueTo<Table>(v);
+      std::map<std::string, json11::Json> json_table;
+      for (auto it = table->map.begin(); it != table->map.end(); it++) {
+        json_table.insert({it->first, GenJSON(&it->second)});
+      }
+      return json_table;
+    }
+    case Value::Type::NIL:
+      return nullptr;
+  }
+}
+
+VALUE_WITH_TYPE* Conversion::GenValueWithType(const char* event_str) {
+  VALUE_WITH_TYPE* event = getValueWithTypePtr();
+  event->type = ParamsType::BYTEARRAY;
+  auto buffer = wson_buffer_new();
+  wson_push_type_uint8_string(
+      buffer, reinterpret_cast<const uint8_t*>(event_str), strlen(event_str));
+  event->value.byteArray = genWeexByteArray(
+      static_cast<const char*>(buffer->data), buffer->position);
+  buffer->data = nullptr;
+  wson_buffer_free(buffer);
+  return event;
+}
+
+}  // namespace data_render
+}  // namespace core
+}  // namespace weex
+
+#endif
\ No newline at end of file
diff --git a/weex_core/Source/core/data_render/vnode/vnode_render_context.cc b/weex_core/Source/core/data_render/vnode/android/conversion.h
similarity index 64%
copy from weex_core/Source/core/data_render/vnode/vnode_render_context.cc
copy to weex_core/Source/core/data_render/vnode/android/conversion.h
index 3f6c6ed..e3f9120 100644
--- a/weex_core/Source/core/data_render/vnode/vnode_render_context.cc
+++ b/weex_core/Source/core/data_render/vnode/android/conversion.h
@@ -16,19 +16,30 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+#ifdef OS_ANDROID
 
-#include "core/data_render/vnode/vnode_render_context.h"
+#ifndef CORE_DATA_RENDER_VNODE_ANDROID_CONVERSION_H_
+#define CORE_DATA_RENDER_VNODE_ANDROID_CONVERSION_H_
+
+#include <string>
+#include <unordered_map>
+#include <vector>
+#include "include/WeexApiHeader.h"
+#include "third_party/json11/json11.hpp"
 
 namespace weex {
 namespace core {
 namespace data_render {
+class Value;
+class Conversion {
+ public:
+  static json11::Json GenJSON(const Value* v);
+  static VALUE_WITH_TYPE* GenValueWithType(const char* event_str);
+};
 
-VNodeRenderContext::VNodeRenderContext()
-    : page_id_(), root_(nullptr), raw_json_(), script_() {}
-
-VNodeRenderContext::~VNodeRenderContext() {}
-
-void VNodeRenderContext::Reset() { root_ = nullptr; }
 }  // namespace data_render
 }  // namespace core
-}  // namespace weex
\ No newline at end of file
+}  // namespace weex
+
+#endif  // CORE_DATA_RENDER_VNODE_ANDROID_CONVERSION_H_
+#endif
diff --git a/weex_core/Source/core/data_render/vnode/android/vcomponent_lifecycle_listener.cc b/weex_core/Source/core/data_render/vnode/android/vcomponent_lifecycle_listener.cc
new file mode 100644
index 0000000..cc707fb
--- /dev/null
+++ b/weex_core/Source/core/data_render/vnode/android/vcomponent_lifecycle_listener.cc
@@ -0,0 +1,265 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#ifdef OS_ANDROID
+
+#include "core/data_render/vnode/vcomponent_lifecycle_listener.h"
+#include "android/utils/params_utils.h"
+#include "core/data_render/exec_state.h"
+#include "core/data_render/vnode/android/conversion.h"
+#include "core/manager/weex_core_manager.h"
+#include "wson/wson.h"
+
+namespace weex {
+namespace core {
+namespace data_render {
+
+static const char* kMethodOnComponentEvent = "callJS";
+static const char* kComponentHook = "componentHook";
+static const char* kLifecycle = "lifecycle";
+static const char* kKeyMethod = "method";
+static const char* kKeyArgs = "args";
+static const char* kEventOnCreated = "created";
+static const char* kEventOnUpdated = "updated";
+static const char* kEventOnDestroyed = "destroyed";
+static int kNonParentId = -1;
+
+void GenWSONValue(wson_buffer* buffer, Value* value);
+void GenWSONValue(wson_buffer* buffer, Table* t);
+void GenWSONValue(wson_buffer* buffer, int32_t i);
+void GenWSONArray(wson_buffer* buffer, Array* array);
+void GenWSONTable(wson_buffer* buffer, Table* table);
+
+void GenWSONValue(wson_buffer* buffer, const std::string& str);
+template <typename Type>
+void GenWSONValue(wson_buffer* buffer, const std::vector<Type>& vector);
+template <typename Type>
+void GenWSONValue(wson_buffer* buffer,
+                  const std::unordered_map<std::string, Type>& ref_map);
+
+void GenWSONValue(wson_buffer* buffer, Value* value) {
+  switch (value->type) {
+    case Value::Type::ARRAY:
+      return GenWSONArray(buffer, ValueTo<Array>(value));
+    case Value::Type::TABLE:
+      return GenWSONTable(buffer, ValueTo<Table>(value));
+    case Value::Type::INT:
+      wson_push_type_long(buffer, value->i);
+      break;
+    case Value::Type::NUMBER:
+      wson_push_type_double(buffer, value->n);
+      break;
+    case Value::Type::STRING:
+      wson_push_type_uint8_string(
+          buffer, reinterpret_cast<const uint8_t*>(value->str->c_str()),
+          strlen(value->str->c_str()));
+      break;
+    case Value::Type::BOOL:
+      wson_push_type_boolean(buffer, value->b);
+      break;
+    default:
+      wson_push_type_null(buffer);
+      break;
+  }
+}
+
+void GenWSONArray(wson_buffer* buffer, Array* array) {
+  wson_push_type_array(buffer, array->items.size());
+  for (auto it = array->items.begin(); it != array->items.end(); it++) {
+    GenWSONValue(buffer, &*it);
+  }
+}
+
+void GenWSONTable(wson_buffer* buffer, Table* table) {
+  wson_push_type_map(buffer, table->map.size());
+  for (auto it = table->map.begin(); it != table->map.end(); it++) {
+    if (it->first.empty()) continue;
+    // Use utf16 as wson only support utf16 as key in map
+    auto utf16_key = weex::base::to_utf16(const_cast<char*>(it->first.c_str()),
+                                          it->first.size());
+    wson_push_uint(buffer, utf16_key.size() * sizeof(uint16_t));
+    wson_push_bytes(buffer, utf16_key.c_str(),
+                    utf16_key.size() * sizeof(uint16_t));
+    GenWSONValue(buffer, &it->second);
+  }
+}
+
+void GenWSONValue(wson_buffer* buffer, Table* t) { GenWSONTable(buffer, t); }
+
+void GenWSONValue(wson_buffer* buffer, int32_t i) {
+  wson_push_type_int(buffer, i);
+}
+
+void GenWSONValue(wson_buffer* buffer, const std::string& str) {
+  wson_push_type_uint8_string(
+      buffer, reinterpret_cast<const uint8_t*>(str.c_str()), str.size());
+}
+
+template <typename Type>
+void GenWSONValue(wson_buffer* buffer, const std::vector<Type>& vector) {
+  wson_push_type_array(buffer, vector.size());
+  for (auto it = vector.begin(); it != vector.end(); it++) {
+    GenWSONValue(buffer, *it);
+  }
+}
+
+template <typename Type>
+void GenWSONValue(wson_buffer* buffer,
+                  const std::unordered_map<std::string, Type>& ref_map) {
+  wson_push_type_map(buffer, ref_map.size());
+  for (auto it = ref_map.begin(); it != ref_map.end(); it++) {
+    if (it->first.empty()) continue;
+    // Use utf16 as wson only support utf16 as key in map
+    auto utf16_key = weex::base::to_utf16(const_cast<char*>(it->first.c_str()),
+                                          it->first.size());
+    wson_push_uint(buffer, utf16_key.size() * sizeof(uint16_t));
+    wson_push_bytes(buffer, utf16_key.c_str(),
+                    utf16_key.size() * sizeof(uint16_t));
+    GenWSONValue(buffer, it->second);
+  }
+}
+
+static void UnpackAndGenWSONValue(wson_buffer* buffer) {}
+
+template <typename T>
+static void UnpackAndGenWSONValue(wson_buffer* buffer, T arg) {
+  GenWSONValue(buffer, std::forward<T>(arg));
+}
+
+template <typename T, typename... Args>
+static void UnpackAndGenWSONValue(wson_buffer* buffer, T arg, Args... args) {
+  GenWSONValue(buffer, std::forward<T>(arg));
+  UnpackAndGenWSONValue(buffer, args...);
+}
+
+template <typename... Args>
+static void GenParamsForCallJS(std::vector<VALUE_WITH_TYPE*>& params,
+                               VComponent* component, const char* event,
+                               int32_t id, size_t argc_inside,
+                               Args... args_inside) {
+  auto page_id = component->exec_state()->context()->page_id();
+  // page_id
+  params.push_back(Conversion::GenValueWithType(page_id.c_str()));
+
+  // args -> { method: 'componentHook', args: [ id, 'lifecycle',
+  // event, [args_inside ] }
+  VALUE_WITH_TYPE* args = getValueWithTypePtr();
+  args->type = ParamsType::BYTEARRAY;
+  auto buffer = wson_buffer_new();
+  wson_push_type_array(buffer, 1);
+  wson_push_type_map(buffer, 2);
+  // key -> method
+  auto utf16_key_method =
+      weex::base::to_utf16(const_cast<char*>(kKeyMethod), strlen(kKeyMethod));
+  wson_push_uint(buffer, utf16_key_method.size() * sizeof(uint16_t));
+  wson_push_bytes(buffer, utf16_key_method.c_str(),
+                  utf16_key_method.size() * sizeof(uint16_t));
+  // value -> 'componentHook'
+  wson_push_type_uint8_string(buffer,
+                              reinterpret_cast<const uint8_t*>(kComponentHook),
+                              strlen(kComponentHook));
+  // key -> args
+  auto utf16_key_args =
+      weex::base::to_utf16(const_cast<char*>(kKeyArgs), strlen(kKeyArgs));
+  wson_push_uint(buffer, utf16_key_args.size() * sizeof(uint16_t));
+  wson_push_bytes(buffer, utf16_key_args.c_str(),
+                  utf16_key_args.size() * sizeof(uint16_t));
+  // value -> [ id, 'lifecycle', event, [ args_inside ] ]
+  {
+    wson_push_type_array(buffer, 4);
+    // templateId
+    wson_push_type_int(buffer, id);
+    // 'lifecycle'
+    wson_push_type_uint8_string(buffer,
+                                reinterpret_cast<const uint8_t*>(kLifecycle),
+                                strlen(kLifecycle));
+    // lifecycle
+    wson_push_type_uint8_string(buffer, reinterpret_cast<const uint8_t*>(event),
+                                strlen(event));
+    // array -> [ args_inside ]
+    {
+      wson_push_type_array(buffer, argc_inside);
+      for (int i = 0; i < argc_inside; i++) {
+        UnpackAndGenWSONValue(buffer, args_inside...);
+      }
+    }
+  }
+
+  args->value.byteArray = genWeexByteArray(
+      static_cast<const char*>(buffer->data), buffer->position);
+  buffer->data = nullptr;
+  wson_buffer_free(buffer);
+  params.push_back(args);
+}
+
+void VComponentLifecycleListener::OnCreated(
+    VComponent* component, Table* data, Table* props,
+    const std::unordered_map<std::string, VComponent::VNodeRefs>& ref_map) {
+  std::vector<VALUE_WITH_TYPE*> params;
+  // parentId
+  int parentId = kNonParentId;
+  if (component->parent() != NULL) {
+    parentId = component->parent()->component()->id();
+  }
+  // [pageId, args]
+  //
+  // args -> { method: 'componentHook', args: [ templateId, 'lifecycle',
+  // lifecycle, [componentId, parentId, data, props, refList] ] }
+  GenParamsForCallJS(params, component, kEventOnCreated,
+                     component->template_id(), 5, component->id(), parentId,
+                     data, props, ref_map);
+  auto page_id = component->exec_state()->context()->page_id();
+  WeexCore::WeexCoreManager::Instance()->script_bridge()->script_side()->ExecJS(
+      page_id.c_str(), "", kMethodOnComponentEvent, params);
+  freeParams(params);
+}
+
+void VComponentLifecycleListener::OnUpdated(
+    VComponent* component, Table* props,
+    const std::unordered_map<std::string, VComponent::VNodeRefs>& ref_map) {
+  auto page_id = component->exec_state()->context()->page_id();
+
+  std::vector<VALUE_WITH_TYPE*> params;
+  // [pageId, args]
+  //
+  // args -> { method: 'componentHook', args: [ componentId, 'lifecycle',
+  // lifecycle, [props, refList] ] }
+  GenParamsForCallJS(params, component, kEventOnUpdated, component->id(), 2,
+                     props, ref_map);
+  WeexCore::WeexCoreManager::Instance()->script_bridge()->script_side()->ExecJS(
+      page_id.c_str(), "", kMethodOnComponentEvent, params);
+  freeParams(params);
+}
+
+void VComponentLifecycleListener::OnDestroyed(VComponent* component) {
+  auto page_id = component->exec_state()->context()->page_id();
+  std::vector<VALUE_WITH_TYPE*> params;
+  // [pageId, args]
+  //
+  // args -> { method: 'componentHook', args: [ componentId, 'lifecycle',
+  // lifecycle, [] ] }
+  GenParamsForCallJS(params, component, kEventOnDestroyed, component->id(), 0);
+  WeexCore::WeexCoreManager::Instance()->script_bridge()->script_side()->ExecJS(
+      page_id.c_str(), "", kMethodOnComponentEvent, params);
+  freeParams(params);
+}
+}  // namespace data_render
+}  // namespace core
+}  // namespace weex
+
+#endif
\ No newline at end of file
diff --git a/weex_core/Source/core/data_render/vnode/android/vnode_on_event_listener.cc b/weex_core/Source/core/data_render/vnode/android/vnode_on_event_listener.cc
new file mode 100644
index 0000000..a8229da
--- /dev/null
+++ b/weex_core/Source/core/data_render/vnode/android/vnode_on_event_listener.cc
@@ -0,0 +1,112 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#ifdef OS_ANDROID
+
+#include "core/data_render/vnode/vnode_on_event_listener.h"
+#include "android/utils/params_utils.h"
+#include "core/data_render/exec_state.h"
+#include "core/data_render/vnode/android/conversion.h"
+#include "core/data_render/vnode/vcomponent.h"
+#include "core/manager/weex_core_manager.h"
+#include "include/WeexApiHeader.h"
+#include "third_party/json11/json11.hpp"
+
+namespace weex {
+namespace core {
+namespace data_render {
+static const char* kMethodCallJS = "callJS";
+static const char* kMethodFireEvent = "fireEvent";
+static const char* kKeyMethod = "method";
+static const char* kKeyArgs = "args";
+static const char* kKeyParams = "params";
+
+void VNodeOnEventListener::OnEvent(VNode* node, const std::string& event,
+                                   const std::string& json_args,
+                                   const std::string dom_changes,
+                                   const VNode::Params& param_list) {
+  auto page_id = node->component()->exec_state()->context()->page_id();
+  std::vector<VALUE_WITH_TYPE*> params;
+  // page_id
+  params.push_back(Conversion::GenValueWithType(page_id.c_str()));
+
+  // args -> { method: 'fireEvent', args: [ref, "nodeEvent", args , domChanges, {params: [ {"templateId": templateId, "componentId": id, "type": type, "params" : [...]} ]}] }
+  VALUE_WITH_TYPE* args = getValueWithTypePtr();
+  args->type = ParamsType::JSONSTRING;
+  std::vector<json11::Json> args_object_list;
+  std::map<std::string, json11::Json> args_object;
+  // method: 'FireEvent'
+  args_object.insert({kKeyMethod, kMethodFireEvent});
+
+  std::vector<json11::Json> args_in_args_object;
+  // ref TODO make sure the difference between node id and ref
+  if (!node->ref().empty()) {
+    args_in_args_object.push_back(node->ref());
+  } else {
+    args_in_args_object.push_back(node->node_id());
+  }
+  // type -> "nodeEvent"
+  args_in_args_object.push_back("nodeEvent");
+  // args
+  std::string error;
+  args_in_args_object.push_back(json11::Json::parse(json_args, error));
+  // domChanges
+  args_in_args_object.push_back(json11::Json::parse(dom_changes, error));
+  // params -> [ {"templateId": templateId, "componentId": id, "type": type, "params" : [...]} ]
+  std::map<std::string, json11::Json> params_object;
+  std::vector<json11::Json> array_in_params_object;
+  {
+    std::map<std::string, json11::Json> inner_object;
+    // templateId
+    inner_object.insert({"templateId", node->component()->template_id()});
+    // componentId
+    inner_object.insert({"componentId", node->component()->id()});
+    // type
+    inner_object.insert({"type", event});
+    // params
+    std::vector<json11::Json> array_in_inner_object;
+    for (auto it = param_list.begin(); it != param_list.end(); it++) {
+      array_in_inner_object.push_back(Conversion::GenJSON(&*it));
+    }
+    inner_object.insert({kKeyParams, array_in_inner_object});
+    array_in_params_object.push_back(inner_object);
+  }
+  params_object.insert({kKeyParams, array_in_params_object});
+  args_in_args_object.push_back(params_object);
+  args_object.insert({kKeyArgs, args_in_args_object});
+  args_object_list.push_back(args_object);
+
+  json11::Json final_json(args_object_list);
+  auto temp = final_json.dump();
+  auto final_json_str = temp.c_str();
+  auto utf16_key = weex::base::to_utf16(const_cast<char*>(final_json_str),
+                                        strlen(final_json_str));
+  args->value.string = genWeexString(
+      reinterpret_cast<const uint16_t*>(utf16_key.c_str()), utf16_key.size());
+  params.push_back(args);
+
+  WeexCore::WeexCoreManager::Instance()->script_bridge()->script_side()->ExecJS(
+      page_id.c_str(), "", kMethodCallJS, params);
+  freeParams(params);
+}
+
+}  // namespace data_render
+}  // namespace core
+}  // namespace weex
+
+#endif
\ No newline at end of file
diff --git a/weex_core/Source/core/data_render/vnode/ios/vcomponent_lifecycle_listener.mm b/weex_core/Source/core/data_render/vnode/ios/vcomponent_lifecycle_listener.mm
new file mode 100644
index 0000000..d47303f
--- /dev/null
+++ b/weex_core/Source/core/data_render/vnode/ios/vcomponent_lifecycle_listener.mm
@@ -0,0 +1,77 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "core/data_render/vnode/vcomponent_lifecycle_listener.h"
+#include "core/manager/weex_core_manager.h"
+#include "core/data_render/vnode/vnode_render_manager.h"
+#import "WXSDKManager.h"
+#import "WXConvertUtility.h"
+
+namespace weex {
+namespace core {
+namespace data_render {
+
+void VComponentLifecycleListener::OnCreated(
+    VComponent* component, Table* data, Table* props,
+    const std::unordered_map<std::string, VComponent::VNodeRefs>& ref_map) {
+    std::string page_id = component->exec_state()->context()->page_id();
+    NSString *instanceId = NSSTRING(page_id.c_str());
+    WXSDKInstance *instance = [WXSDKManager instanceForID:instanceId];
+    if (!instance) {
+        return;
+    }
+
+    int template_id = component->template_id();
+    int component_id = component->id();
+    int parent_id = -1;
+    if (component->parent()) {
+        parent_id = component->parent()->component()->id();
+    }
+
+    [[WXSDKManager bridgeMgr] callJSMethod:@"callJS" args:@[instanceId, @[@{@"method":@"componentHook", @"args":@[[NSNumber numberWithInt:template_id], @"lifecycle", @"created", @[[NSNumber numberWithInt:component_id],[NSNumber numberWithInt:parent_id], NSDICTIONARY(data), NSDICTIONARY(props), NSDICTIONARY(ref_map)]]}]]];
+}
+
+void VComponentLifecycleListener::OnUpdated(
+    VComponent* component, Table* props, const std::unordered_map<std::string, VComponent::VNodeRefs>& ref_map) {
+    std::string page_id = component->exec_state()->context()->page_id();
+    NSString *instanceId = NSSTRING(page_id.c_str());
+    WXSDKInstance *instance = [WXSDKManager instanceForID:instanceId];
+    if (!instance) {
+        return;
+    }
+
+    int component_id = component->id();
+    [[WXSDKManager bridgeMgr] callJSMethod:@"callJS" args:@[instanceId, @[@{@"method":@"componentHook", @"args":@[[NSNumber numberWithInt:component_id], @"lifecycle", @"updated", @[NSDICTIONARY(props), NSDICTIONARY(ref_map)]]}]]];
+}
+
+void VComponentLifecycleListener::OnDestroyed(VComponent* component) {
+    std::string page_id = component->exec_state()->context()->page_id();
+    NSString *instanceId = NSSTRING(page_id.c_str());
+    WXSDKInstance *instance = [WXSDKManager instanceForID:instanceId];
+    if (!instance) {
+        return;
+    }
+
+    int component_id = component->id();
+    [[WXSDKManager bridgeMgr] callJSMethod:@"callJS" args:@[instanceId, @[@{@"method":@"componentHook", @"args":@[[NSNumber numberWithInt:component_id], @"lifecycle", @"destroyed", @[]]}]]];
+}
+
+}  // namespace data_render
+}  // namespace core
+}  // namespace weex
diff --git a/weex_core/Source/core/data_render/vnode/ios/vnode_on_event_listener.mm b/weex_core/Source/core/data_render/vnode/ios/vnode_on_event_listener.mm
new file mode 100644
index 0000000..7a7fcb7
--- /dev/null
+++ b/weex_core/Source/core/data_render/vnode/ios/vnode_on_event_listener.mm
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "core/data_render/vnode/vnode_on_event_listener.h"
+#include "core/data_render/vnode/vcomponent.h"
+#include "core/data_render/vnode/vnode_render_manager.h"
+#import "WXSDKManager.h"
+#import "WXConvertUtility.h"
+#import "WXUtility.h"
+
+namespace weex {
+namespace core {
+namespace data_render {
+
+void VNodeOnEventListener::OnEvent(VNode *node, const std::string &event,
+                                            const std::string &json_args, const std::string dom_changes,
+                                            const VNode::Params &params)
+ {
+    std::string page_id = node->component()->exec_state()->context()->page_id();
+    NSString *instanceId = NSSTRING(page_id.c_str());
+    WXSDKInstance *instance = [WXSDKManager instanceForID:instanceId];
+    if (!instance) {
+        return;
+    }
+    int template_id = node->component()->template_id();
+    int component_id = node->component()->id();
+
+    [[WXSDKManager bridgeMgr] callJSMethod:@"callJS" args:@[instanceId, @[@{@"method":@"fireEvent", @"args":@[NSSTRING(node->ref().empty() ? node->node_id().c_str() : node->ref().c_str()), @"nodeEvent", [WXUtility objectFromJSON:NSSTRING(json_args.c_str())], NSSTRING(dom_changes.c_str()), @{@"params":@[@{@"templateId":[NSNumber numberWithInt:template_id], @"componentId":[NSNumber numberWithInt:component_id],@"type":NSSTRING(event.c_str()), @"params": NSARRAY(params)}]}]}]]];
+  }
+
+}  // namespace data_render
+}  // namespace core
+}  // namespace weex
diff --git a/weex_core/Source/core/data_render/vnode/vcomponent.cc b/weex_core/Source/core/data_render/vnode/vcomponent.cc
index f885cc7..c4243dc 100644
--- a/weex_core/Source/core/data_render/vnode/vcomponent.cc
+++ b/weex_core/Source/core/data_render/vnode/vcomponent.cc
@@ -19,6 +19,8 @@
 
 #include "core/data_render/vnode/vcomponent.h"
 #include "core/data_render/exec_state.h"
+#include "vnode_render_manager.h"
+
 namespace weex {
 namespace core {
 namespace data_render {
@@ -27,21 +29,21 @@ namespace data_render {
 static int g_component_id = 0;
 
 VComponent::VComponent(ExecState *exec_state, int template_id,
-                       const std::string &name, const std::string &tag_name,
-                       const std::string &node_id, const std::string &ref)
-    : VNode(tag_name, node_id, ref),
-      exec_state_(exec_state),
+                       const std::string &name, const std::string &func_name)
+    : VNode("", "", ""),
+      is_dirty_(false),
+      has_dispatch_created_(false),
+      has_moved_(false),
       id_(g_component_id++),
       template_id_(template_id),
       name_(name),
-      // This function name definition rule is in parser.cc
-      func_name_("createComponent_" + name),
-      data_(nullptr),
-      props_(nullptr),
+      func_name_(func_name),
+      data_(exec_state->class_factory()->CreateTable()),
+      props_(exec_state->class_factory()->CreateTable()),
       listener_(nullptr),
-      dirty_(false),
-      children_(),
-      parent_(nullptr) {}
+      old_root_vnode_(nullptr),
+      root_vnode_(nullptr),
+      exec_state_(exec_state) {}
 
 VComponent::~VComponent() {}
 
@@ -85,56 +87,199 @@ static bool Equals(Value a, Value b) {
   return true;
 }
 
-void VComponent::Compare(VComponent *old_component) {
+static void BuildRefsInner(
+    std::unordered_map<std::string, VComponent::VNodeRefs> &ref_map,
+    VNode *node, bool in_for_loop) {
+  if (node->attributes()->find("[[repeat]]") != node->attributes()->end()) {
+    in_for_loop = true;
+  }
+  if (!node->ref().empty()) {
+    VComponent::VNodeRef ref;
+    ref.insert({"ref", node->render_object_ref()});
+    auto it = ref_map.find(node->ref());
+    if (it != ref_map.end()) {
+      if (!in_for_loop) {
+        return;
+      }
+      it->second.push_back(ref);
+    } else {
+      VComponent::VNodeRefs refs;
+      refs.push_back(ref);
+      ref_map.insert({node->ref(), refs});
+    }
+  }
+  // Record { ref : node } in context
+  node->component()->exec_state()->context()->AddVNode(node->render_object_ref(), node);
+  if (node->child_list()->size() > 0 && !node->IsVirtualComponent()) {
+    for (auto it = node->child_list()->begin(); it != node->child_list()->end();
+         it++) {
+      BuildRefsInner(ref_map, *it, in_for_loop);
+    }
+  }
+}
+
+static void DetachVNodesInContext(VNode *node) {
+  // Remove { ref : node } in context
+  if (!node || node->IsVirtualComponent()) return;;
+  auto context = node->component()->exec_state()->context();
+  auto record = context->GetVNode(node->render_object_ref());
+  if (record != node) {
+    context->RemoveVNode(node->render_object_ref());
+  }
+  if (node->child_list()->size() > 0 && !node->IsVirtualComponent()) {
+    for (auto it = node->child_list()->begin(); it != node->child_list()->end();
+         it++) {
+      DetachVNodesInContext(*it);
+    }
+  }
+}
+
+void VComponent::BuildRefMap() {
+  ref_map_.clear();
+  BuildRefsInner(ref_map_, root_vnode(), false);
+}
+
+bool VComponent::Equal(VComponent *old_component) {
   VComponent *new_component = this;
-  if (old_component == new_component) return;
+  if (old_component == new_component) return true;
   // Mainly compare props
-  for (auto it = old_component->props_->map.begin();
-       it != old_component->props_->map.end(); ++it) {
+  Table *old_table = ValueTo<Table>(&old_component->props_);
+  Table *new_table = ValueTo<Table>(&new_component->props_);
+  if (updated_props_.type == Value::Type::NIL) {
+    updated_props_ = exec_state_->class_factory()->CreateTable();
+  } else {
+    ValueTo<Table>(&updated_props_)->map.clear();
+  }
+  bool equal = true;
+  for (auto it = old_table->map.begin(); it != old_table->map.end(); ++it) {
     auto old_value = it->second;
-    auto new_value = new_component->props_->map[it->first];
+    auto new_value = new_table->map[it->first];
     if (old_value.type != new_value.type || !Equals(old_value, new_value)) {
-      updated_props_[it->first] = new_value;
-      dirty_ = true;
+      ValueTo<Table>(&updated_props_)->map.insert({it->first, new_value});
+      equal = false;
     }
   }
+  return equal;
+}
+
+void VComponent::MoveTo(VComponent *new_component) {
+  new_component->has_dispatch_created_ = has_dispatch_created_;
+  new_component->id_ = id_;
+  new_component->SetRootNode(root_vnode_.release());
+  new_component->data_ = data_;
+  if (!new_component->Equal(this)) {
+    new_component->UpdateData();
+  }
+  exec_state_->context()->RemoveComponent(id_);
+  exec_state_->context()->AddComponent(new_component->id(), new_component);
+  has_moved_ = true;
 }
 
-void VComponent::UpdateData(std::unordered_map<std::string, Value> datas) {
+void VComponent::UpdateData() {
+  // Merge data and props
   Value new_value = exec_state_->class_factory()->CreateTable();
-  TableMapAddAll(props_, ValueTo<Table>(&new_value));
-  TableMapAddAll(data_, ValueTo<Table>(&new_value));
-  //Value new_component = exec_state_->Call(func_name_, {new_value}).cptr;
+  TableAddAll(props_, new_value);
+  TableAddAll(data_, new_value);
+
+  Value component;
+  component.cptr = this;
+  component.type = Value::CPTR;
+  exec_state_->Call(func_name_, {new_value, component, Value(false)});
+  VNodeRenderManager::GetInstance()->PatchVNode(
+      exec_state_, old_root_vnode_.get(), root_vnode_.get());
+
+  TravelVComponentsWithFunc(&VComponent::DispatchDestroyed,
+                            old_root_vnode_.get());
+  old_root_vnode_.reset(nullptr);
+  if (has_dispatch_created_) {
+    is_dirty_ = true;
+    DispatchUpdated();
+  }
+}
+
+void VComponent::UpdateData(Value *data) {
+  if (data->type == Value::Type::TABLE && TableAddAll(*data, data_)) {
+    UpdateData();
+  }
+}
+
+// TODO Depth-first traversal
+void VComponent::TravelVComponentsWithFunc(TravelTreeFunc func, VNode *root) {
+  if (!root) return;
+  std::vector<VNode *> list;
+  list.push_back(root);
+  VNode *node = nullptr;
+  while (!list.empty()) {
+    node = list.front();
+    list.erase(list.begin());
+    if (node->IsVirtualComponent()) {
+      (static_cast<VComponent *>(node)->*func)();
+      continue;
+    }
+    for (auto it = node->child_list()->begin(); it != node->child_list()->end();
+         it++) {
+      list.push_back(*it);
+    }
+  }
 }
 
 void VComponent::DispatchCreated() {
-  for (auto it = children_.begin(); it != children_.end(); ++it) {
-    (*it)->DispatchCreated();
+  if (has_dispatch_created_) return;
+  BuildRefMap();
+  if (listener_) {
+    listener_->OnCreated(this, ValueTo<Table>(&data_), ValueTo<Table>(&props_),
+                         ref_map_);
   }
+  TravelVComponentsWithFunc(&VComponent::DispatchCreated, root_vnode());
+  has_dispatch_created_ = true;
 }
 
 void VComponent::DispatchUpdated() {
-  if (dirty_) {
-    for (auto it = children_.begin(); it != children_.end(); ++it) {
-      if ((*it)->dirty_) {
-        (*it)->DispatchUpdated();
-      }
+  if (!has_dispatch_created_) {
+    DispatchCreated();
+    return;
+  }
+  if (!is_dirty_) return;
+  BuildRefMap();
+  if (listener_) {
+    if (updated_props_.type == Value::Type::NIL) {
+      updated_props_ = exec_state_->class_factory()->CreateTable();
     }
-    dirty_ = false;
+    listener_->OnUpdated(this, ValueTo<Table>(&updated_props_), ref_map_);
   }
+  TravelVComponentsWithFunc(&VComponent::DispatchUpdated, root_vnode());
+  is_dirty_ = false;
 }
 
 void VComponent::DispatchDestroyed() {
-  for (auto it = children_.begin(); it != children_.end(); ++it) {
-    (*it)->DispatchDestroyed();
+  if (listener_ && !has_moved_) {
+    listener_->OnDestroyed(this);
   }
+  TravelVComponentsWithFunc(&VComponent::DispatchDestroyed, root_vnode());
+  if (!has_moved_) {
+    exec_state_->context()->RemoveComponent(id_);
+  }
+  DetachVNodesInContext(root_vnode());
 }
 
-void VComponent::AppendChildComponent(VComponent *child) {
-  children_.push_back(child);
-  child->parent_ = this;
+void VComponent::SetRootNode(VNode *node) {
+  if (root_vnode_) {
+    old_root_vnode_ = std::move(root_vnode_);
+  }
+  root_vnode_.reset(node);
+  if (root_vnode_) {
+    root_vnode_->set_component(this);
+  }
 }
 
+void VComponent::SetData(Value *data) { TableCopy(*data, data_); }
+
+void VComponent::SetProps(Value *props) { TableCopy(*props, props_); }
+
+void VComponent::DispatchAttachedToParent() {}
+
+void VComponent::DispatchDetachedFromParent() { DispatchDestroyed(); }
+
 }  // namespace data_render
 }  // namespace core
 }  // namespace weex
diff --git a/weex_core/Source/core/data_render/vnode/vcomponent.h b/weex_core/Source/core/data_render/vnode/vcomponent.h
index 884148c..927a3a4 100644
--- a/weex_core/Source/core/data_render/vnode/vcomponent.h
+++ b/weex_core/Source/core/data_render/vnode/vcomponent.h
@@ -26,55 +26,84 @@
 namespace weex {
 namespace core {
 namespace data_render {
-// VComponent is a VNode
 class VComponent : public VNode {
  public:
+  typedef std::unordered_map<std::string, std::string> VNodeRef;
+  typedef std::vector<VNodeRef> VNodeRefs;
   class LifecycleListener {
-    virtual void OnCreated(VComponent* component,
-                           std::unordered_map<std::string, Value> datas,
-                           std::unordered_map<std::string, Value> props) = 0;
-    virtual void OnUpdated(VComponent* component,
-                           std::unordered_map<std::string, Value> props) = 0;
+   public:
+    virtual ~LifecycleListener() {}
+    virtual void OnCreated(
+        VComponent* component, Table* data, Table* props,
+        const std::unordered_map<std::string, VNodeRefs>& ref_map) = 0;
+    virtual void OnUpdated(
+        VComponent* component, Table* props,
+        const std::unordered_map<std::string, VNodeRefs>& ref_map) = 0;
     virtual void OnDestroyed(VComponent* component) = 0;
   };
   VComponent(ExecState* exec_state, int template_id, const std::string& name,
-             const std::string& tag_name, const std::string& node_id,
-             const std::string& ref);
+             const std::string& func_name);
   ~VComponent();
-  void UpdateData(std::unordered_map<std::string, Value> datas);
-  void DispatchCreated();
-  void DispatchUpdated();
-  void DispatchDestroyed();
-  void Compare(VComponent* component);
-
-  void AppendChildComponent(VComponent* child);
+  void UpdateData();
+  void UpdateData(Value* datas);
+  inline bool IsSameNode(VComponent* old_component) {
+    return template_id_ == old_component->template_id_;
+  }
+  void MoveTo(VComponent* new_component);
 
-  inline void set_lifecycle_listener(LifecycleListener* listener) {
-    listener_ = listener;
+  inline const std::string render_object_ref() const override {
+    if (root_vnode_.get()) {
+      return root_vnode_->render_object_ref();
+    }
+    return "";
   }
 
   inline int id() { return id_; }
   inline int template_id() { return template_id_; }
-  VComponent* parent() { return parent_; }
-  inline void set_data(Table* data) { data_ = data; }
-  inline void set_props(Table* props) { props = props_; }
+  inline ExecState* exec_state() { return exec_state_; }
+  void SetData(Value* data);
+  void SetProps(Value* props);
+  inline VNode* root_vnode() { return root_vnode_.get(); }
+  void SetRootNode(VNode* node);
+  bool IsVirtualComponent() const override { return true; }
+
+  void DispatchCreated();
+  void DispatchUpdated();
+  void DispatchDestroyed();
+
+  inline void set_life_cycle_listener(
+      std::unique_ptr<LifecycleListener> listener) {
+    listener_ = std::move(listener);
+  }
 
  private:
+  typedef void (VComponent::*TravelTreeFunc)();
+  void TravelVComponentsWithFunc(TravelTreeFunc func, VNode* root);
+
+  void BuildRefMap();
+  bool Equal(VComponent* old_component);
+  void DispatchAttachedToParent() override;
+  void DispatchDetachedFromParent() override;
+
+  bool is_dirty_;
+  bool has_dispatch_created_;
+  bool has_moved_;
+  // unique id for unique component
   int id_;
+  // Unique id for unique template, a template to multiple component
   int template_id_;
+  // Unique template name
   std::string name_;
-  // For invoke function in vm to create component
+  // For invoke function in vm to create nodes in component
   std::string func_name_;
   // Save data and props for diff and update
-  Table* data_;
-  Table* props_;
-  std::unordered_map<std::string, Value> updated_props_;
-  // Ptr should handle by outside
-  LifecycleListener* listener_;
-  // Mark if this component is a new one after diff & patch
-  bool dirty_;
-  std::vector<VComponent*> children_;
-  VComponent* parent_;
+  Value data_;
+  Value props_;
+  Value updated_props_;
+  std::unique_ptr<LifecycleListener> listener_;
+  std::unordered_map<std::string, VNodeRefs> ref_map_;
+  std::unique_ptr<VNode> old_root_vnode_;
+  std::unique_ptr<VNode> root_vnode_;
   ExecState* exec_state_;
 };
 }  // namespace data_render
diff --git a/weex_core/Source/core/data_render/vnode/vnode_render_context.cc b/weex_core/Source/core/data_render/vnode/vcomponent_lifecycle_listener.h
similarity index 57%
copy from weex_core/Source/core/data_render/vnode/vnode_render_context.cc
copy to weex_core/Source/core/data_render/vnode/vcomponent_lifecycle_listener.h
index 3f6c6ed..3cd6c71 100644
--- a/weex_core/Source/core/data_render/vnode/vnode_render_context.cc
+++ b/weex_core/Source/core/data_render/vnode/vcomponent_lifecycle_listener.h
@@ -17,18 +17,25 @@
  * under the License.
  */
 
-#include "core/data_render/vnode/vnode_render_context.h"
+#ifndef CORE_DATA_RENDER_VNODE_VCOMPONENT_LIFECYCLE_LISTENER_H_
+#define CORE_DATA_RENDER_VNODE_VCOMPONENT_LIFECYCLE_LISTENER_H_
+
+#include "core/data_render/vnode/vcomponent.h"
 
 namespace weex {
 namespace core {
 namespace data_render {
-
-VNodeRenderContext::VNodeRenderContext()
-    : page_id_(), root_(nullptr), raw_json_(), script_() {}
-
-VNodeRenderContext::~VNodeRenderContext() {}
-
-void VNodeRenderContext::Reset() { root_ = nullptr; }
+class VComponentLifecycleListener : public VComponent::LifecycleListener {
+  void OnCreated(
+      VComponent* component, Table* data, Table* props,
+      const std::unordered_map<std::string, VComponent::VNodeRefs>& ref_map);
+  void OnUpdated(
+      VComponent* component, Table* props,
+      const std::unordered_map<std::string, VComponent::VNodeRefs>& ref_map);
+  void OnDestroyed(VComponent* component);
+};
 }  // namespace data_render
 }  // namespace core
-}  // namespace weex
\ No newline at end of file
+}  // namespace weex
+
+#endif  // CORE_DATA_RENDER_VNODE_VCOMPONENT_LIFECYCLE_LISTENER_H_
diff --git a/weex_core/Source/core/data_render/vnode/vnode.cc b/weex_core/Source/core/data_render/vnode/vnode.cc
index d34cfc7..219ca1c 100644
--- a/weex_core/Source/core/data_render/vnode/vnode.cc
+++ b/weex_core/Source/core/data_render/vnode/vnode.cc
@@ -16,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+#include "core/data_render/object.h"
 #include "core/render/node/factory/render_creator.h"
 #include "core/data_render/vnode/vnode.h"
 
@@ -24,7 +25,7 @@ namespace core {
 namespace data_render {
 
 VNode::VNode(const std::string &tag_name, const std::string &node_id,
-             const std::string &ref) {
+             const std::string &ref)  {
   ref_ = ref;
   tag_name_ = tag_name;
   node_id_ = node_id;
@@ -32,6 +33,8 @@ VNode::VNode(const std::string &tag_name, const std::string &node_id,
   styles_ = new std::map<std::string, std::string>();
   attributes_ = new std::map<std::string, std::string>();
   events_ = new std::map<std::string, void *>();
+  event_params_map_.reset(new EventParamsMap);
+  on_event_listener_.reset();
 }
 
 VNode::~VNode() {
@@ -50,12 +53,24 @@ VNode::~VNode() {
       delete events_;
       events_ = nullptr;
   }
-  for (auto it = child_list_.begin(); it != child_list_.end(); it++) {
-    VNode *&reference = *it;
-    if (reference != nullptr) {
-      delete reference;
-      *it = nullptr;
-    }
+//  for (auto it = child_list_.begin(); it != child_list_.end(); it++) {
+//    VNode *&reference = *it;
+//    if (reference != nullptr) {
+//      delete reference;
+//      *it = nullptr;
+//    }
+//  }
+}
+
+void VNode::OnEvent(const std::string &event, const std::string args,
+                    const std::string dom_changes) {
+  if (!on_event_listener_) return;
+
+  auto it = event_params_map_->find(event);
+  if (it == event_params_map_->end()) return;
+  auto params_list = it->second;
+  for (auto it = params_list.begin(); it != params_list.end(); it++) {
+    on_event_listener_->OnEvent(this, event, args, dom_changes, *it);
   }
 }
 
@@ -97,26 +112,32 @@ VNode *VNode::FindNode(const std::string &render_object_ref) {
     return node;
 }
 
-void VNode::AddEvent(const std::string &event, const std::string &function,
-                     const std::vector<std::string> &params) {
-  //todo
+void VNode::AddEvent(const std::string &event,
+                     const std::vector<Value> &params) {
+  auto it = event_params_map_->find(event);
+  if (it != event_params_map_->end()) {
+    it->second.push_back(params);
+  } else {
+    event_params_map_->insert({event, {params}});
+  }
 }
-    
+
 void VNode::AddChild(VNode *child) {
   child->parent_ = this;
+  child->component_ = component_;
   child_list_.push_back(child);
+  child->DispatchAttachedToParent();
 }
     
 void VNode::InsertChild(VNode *child, int index) {
-    do {
-        child->parent_ = this;
-        if (index < child_list_.size()) {
-            child_list_.insert(child_list_.begin() + index, child);
-            break;
-        }
-        child_list_.push_back(child);
-        
-    } while (0);
+  if (!child) return;
+  child->parent_ = this;
+  if (index < child_list_.size()) {
+    child_list_.insert(child_list_.begin() + index, child);
+  } else {
+    child_list_.push_back(child);
+  }
+  child->DispatchAttachedToParent();
 }
 
 void VNode::RemoveChild(VNode *child) {
@@ -124,6 +145,7 @@ void VNode::RemoveChild(VNode *child) {
   auto it = child_list_.begin();
   for (; it != child_list_.end(); ++it) {
     if (*it == child) {
+      child->DispatchDetachedFromParent();
       VNode *&reference = *it;
       child_list_.erase(it);
       if (reference != nullptr) {
diff --git a/weex_core/Source/core/data_render/vnode/vnode.h b/weex_core/Source/core/data_render/vnode/vnode.h
index bcc09e3..8cda5e5 100644
--- a/weex_core/Source/core/data_render/vnode/vnode.h
+++ b/weex_core/Source/core/data_render/vnode/vnode.h
@@ -22,15 +22,32 @@
 #include <map>
 #include <string>
 #include <vector>
+#include <unordered_set>
+#include <unordered_map>
+#include <memory>
 #include "core/render/node/render_object.h"
 
 namespace weex {
 namespace core {
 namespace data_render {
-class VNode;
+class VComponent;
+class Value;
 
 class VNode {
  public:
+  typedef std::vector<Value> Params;
+  typedef std::vector<Params> ParamsList;
+  typedef std::unordered_map<std::string, ParamsList> EventParamsMap;
+
+  class OnEventListener {
+   public:
+    virtual ~OnEventListener() {}
+    virtual void OnEvent(VNode *node, const std::string &event,
+                         const std::string &json_args,
+                         const std::string dom_changes,
+                         const Params &params) = 0;
+  };
+
   VNode(const std::string &tag_name, const std::string &node_id,
         const std::string &ref);
 
@@ -40,10 +57,12 @@ class VNode {
 
   void SetAttribute(const std::string &key, const std::string &value);
 
-  void AddEvent(const std::string &event, const std::string &function,
-                const std::vector<std::string> &params);
+  void AddEvent(const std::string &event,
+                const std::vector<Value> &params);
   void AddEvent(const std::string &event, void *func, void *inst);
 
+  void AddOnEventListener();
+
   void AddChild(VNode *child);
 
   void RemoveChild(VNode *child);
@@ -59,7 +78,7 @@ class VNode {
 
   inline const std::string &ref() const { return ref_; }
 
-  inline const std::string &render_object_ref() const {
+  virtual inline const std::string render_object_ref() const {
     return render_object_ref_;
   }
 
@@ -67,7 +86,7 @@ class VNode {
     render_object_ref_ = std::move(ref);
   }
   inline void *& inst() { return inst_; }
-  inline const VNode *parent() const { return parent_; }
+  inline VNode *parent() const { return parent_; }
 
   inline std::vector<VNode *> *child_list() { return &child_list_; }
 
@@ -80,14 +99,37 @@ class VNode {
     return events_;
   }
 
+  inline EventParamsMap *event_params_map() const {
+    return event_params_map_.get();
+  }
+
+  void OnEvent(const std::string &event, const std::string args,
+               const std::string dom_changes);
+
+  inline void set_on_event_listener(std::unique_ptr<OnEventListener> listener) {
+    on_event_listener_ = std::move(listener);
+  }
+
   inline bool HasChildren() { return !child_list_.empty(); }
 
+  inline void set_component(VComponent* c) {
+    component_ = c;
+  }
+
+  inline VComponent* component() {
+    return component_;
+  }
+
+  virtual bool IsVirtualComponent() const { return false; }
+
  private:
   std::string tag_name_;
   // Not unique
   std::string node_id_;
   // Should be unique
   std::string ref_;
+  // Context of vnode
+  VComponent* component_ = nullptr;
   // Ref point to RenderObject is set when PatchVNode or ParseVNode2RenderObject
   std::string render_object_ref_;
 
@@ -96,9 +138,16 @@ class VNode {
   std::vector<VNode *> child_list_;
   std::map<std::string, std::string> *styles_;
   std::map<std::string, std::string> *attributes_;
+  // This events if record event with func from vm
   std::map<std::string, void *> *events_;
+  // This events if record event with value from vm
+  std::unique_ptr<EventParamsMap> event_params_map_;
+  std::unique_ptr<OnEventListener> on_event_listener_;
+
   void MapInsertOrAssign(std::map<std::string, std::string> *target_map,
                          const std::string &key, const std::string &value);
+  inline virtual void DispatchAttachedToParent() {}
+  inline virtual void DispatchDetachedFromParent() {}
 };
 
 }  // namespace data_render
diff --git a/weex_core/Source/core/data_render/vnode/vnode_exec_env.cc b/weex_core/Source/core/data_render/vnode/vnode_exec_env.cc
index 7fe2edc..e2d3fe4 100644
--- a/weex_core/Source/core/data_render/vnode/vnode_exec_env.cc
+++ b/weex_core/Source/core/data_render/vnode/vnode_exec_env.cc
@@ -29,6 +29,8 @@
 #include "core/data_render/js_common_function.h"
 #include "core/data_render/vnode/vcomponent.h"
 #include "core/data_render/vnode/vnode_render_manager.h"
+#include "core/data_render/vnode/vcomponent_lifecycle_listener.h"
+#include "core/data_render/vnode/vnode_on_event_listener.h"
 #include "base/LogDefines.h"
 
 namespace weex {
@@ -58,7 +60,11 @@ static Value Merge(ExecState *exec_state) {
     }
     Value *lhs = exec_state->GetArgument(0);
     Value *rhs = exec_state->GetArgument(1);
-    if (!IsTable(lhs) && !IsTable(rhs)) {
+    if (IsTable(lhs) && IsNil(rhs)) {
+        return *lhs;
+    } else if (IsNil(lhs) && IsTable(rhs)) {
+        return *rhs;
+    } else if (!IsTable(lhs) && !IsTable(rhs)) {
         return Value();
     }
     Value new_value = exec_state->class_factory()->CreateTable();
@@ -227,71 +233,50 @@ static Value AppendUrlParam(ExecState *exec_state) {
 }
 
 // saveComponentDataAndProps(component, data, props);
-static Value SaveComponentDataAndProps(ExecState* exec_state) {
+static Value saveComponentPropsAndData(ExecState *exec_state) {
   VComponent *component = exec_state->GetArgument(0)->type == Value::Type::NIL ?
                     nullptr : reinterpret_cast<VComponent *>(exec_state->GetArgument(0)->cptr);
-  Value *data = exec_state->GetArgument(1);
-  Value *props = exec_state->GetArgument(2);
+  Value *props = exec_state->GetArgument(1);
+  Value *data = exec_state->GetArgument(2);
   if (component) {
-      component->set_data(ValueTo<Table>(data));
-      component->set_props(ValueTo<Table>(props));
+      component->SetData(data);
+      component->SetProps(props);
   }
   return Value();
 }
 
-// appendChildComponent(parent, child);
-static Value AppendChildComponent(ExecState* exec_state) {
-  VNode *parent = exec_state->GetArgument(0)->type == Value::Type::NIL ?
-                    nullptr : reinterpret_cast<VNode *>(exec_state->GetArgument(0)->cptr);
-  VNode *child = reinterpret_cast<VNode *>(exec_state->GetArgument(1)->cptr);
-  if (parent && child) {
-      static_cast<VComponent *>(parent)->AppendChildComponent(static_cast<VComponent *>(child));
+// setComponentRoot(component, node);
+static Value SetComponentRoot(ExecState* exec_state) {
+  VComponent *component = exec_state->GetArgument(0)->type == Value::Type::NIL ?
+                    nullptr : reinterpret_cast<VComponent *>(exec_state->GetArgument(0)->cptr);
+  VNode* node = exec_state->GetArgument(1)->type == Value::Type::NIL ?
+                nullptr : reinterpret_cast<VNode *>(exec_state->GetArgument(1)->cptr);
+  if (component && node) {
+      component->SetRootNode(node);
   }
   return Value();
 }
 
-// createComponent(template_id, "template_name", "tag_name", "id", ref);
+// createComponent(template_id, "template_name", func_name);
 static Value CreateComponent(ExecState* exec_state) {
   int template_id = 0;
-  if (exec_state->GetArgument(0)->type == Value::Type::NUMBER) {
+  if (exec_state->GetArgument(0)->type == Value::Type::INT) {
     template_id = static_cast<int>(exec_state->GetArgument(0)->i);
   }
   auto template_name = exec_state->GetArgument(1)->str;
-  Value* arg_node_id = exec_state->GetArgument(3);
-  std::string node_id;
-  if (IsString(arg_node_id)) {
-    node_id = CStringValue(arg_node_id);
-  } else if (IsInt(arg_node_id)) {
-    std::ostringstream os;
-    os << IntValue(arg_node_id);
-    node_id = "vn_" + os.str();
-  } else {
-    throw VMExecError("CreateElement only support int for string");
-  }
-  std::string tag_name = exec_state->GetArgument(2)->str->c_str();
-  std::string ref = "";
-  if (exec_state->GetArgumentCount() > 4 &&
-      exec_state->GetArgument(4)->type == Value::Type::STRING) {
-    ref = exec_state->GetArgument(4)->str->c_str();
-  }
-  LOGD("[VM][VNode][CreateDocument]: %s  %s\n", node_id.c_str(), tag_name.c_str());
-  VComponent* component = NULL;
-  if (tag_name == "root") {
-    component = new VComponent(exec_state, template_id, template_name->c_str(),
-                               "div", node_id, ref);
-    if (exec_state->context()->root() == nullptr) {
-      exec_state->context()->set_root(component);
-    }
-  } else {
-    component = new VComponent(exec_state, template_id, template_name->c_str(),
-                               tag_name, node_id, ref);
-  }
-  if (exec_state->context()->root() == nullptr) {
-    exec_state->context()->set_root(component);
-  }
+  auto func_name = exec_state->GetArgument(2)->str;
+  VComponent* component = new VComponent(
+      exec_state, template_id, template_name->c_str(), func_name->c_str());
   Value result;
   result.type = Value::Type::CPTR;
   result.cptr = component;
+  if (exec_state->context()->root() == nullptr) {
+    exec_state->context()->set_root(component);
+  }
+  component->set_life_cycle_listener(
+      std::unique_ptr<VComponent::LifecycleListener>(
+          new VComponentLifecycleListener));
+  exec_state->context()->AddComponent(component->id(), component);
   return result;
 }
     
@@ -313,8 +298,6 @@ static Value UpdateElement(ExecState *exec_state) {
     
     return Value();
 }
-    
-static size_t g_node_id = 0;
 
 // createElement("tag_name", "id", ref);
 static Value CreateElement(ExecState *exec_state) {
@@ -333,10 +316,7 @@ static Value CreateElement(ExecState *exec_state) {
         throw VMExecError("CreateElement only support int for string");
     }
     std::string node_id,ref;
-    std::ostringstream os;
-    os << g_node_id++;
-    node_id = "vn_" + os.str();
-    ref = arg_id_str;
+    node_id = arg_id_str;
     if (exec_state->GetArgumentCount() > 2 && exec_state->GetArgument(2)->type == Value::Type::STRING) {
         ref = exec_state->GetArgument(2)->str->c_str();
     }
@@ -545,10 +525,7 @@ static Value SetClassList(ExecState* exec_state) {
 }
 
 // setStyle(node, key, value);
-static Value SetStyle(ExecState* exec_state) {
-  VNode* node = reinterpret_cast<VNode*>(exec_state->GetArgument(0)->cptr);
-  Value* key = exec_state->GetArgument(1);
-  Value* value = exec_state->GetArgument(2);
+inline static Value SetStyle(VNode *node, Value *key, Value *value) {
   if (node == nullptr || key->type != Value::Type::STRING ||
       value->type == Value::Type::NIL) {
     return Value();
@@ -557,6 +534,54 @@ static Value SetStyle(ExecState* exec_state) {
   return Value();
 }
 
+// setStyle(node, style);
+inline static Value SetStyle(VNode *node, Value *style) {
+  if (node == nullptr || style->type != Value::Type::TABLE) {
+    return Value();
+  }
+  auto style_map = ValueTo<Table>(style)->map;
+  for (auto it = style_map.begin(); it != style_map.end(); it++) {
+    node->SetStyle(it->first, ToString(&it->second));
+  }
+  return Value();
+}
+
+// setStyle(node, key, value);
+// or
+// setStyle(node, style);
+static Value SetStyle(ExecState *exec_state) {
+  VNode *node = reinterpret_cast<VNode *>(exec_state->GetArgument(0)->cptr);
+  auto length = exec_state->GetArgumentCount();
+  if (length == 3) {
+    Value *key = exec_state->GetArgument(1);
+    Value *value = exec_state->GetArgument(2);
+    SetStyle(node, key, value);
+  } else if (length == 2) {
+    Value *style = exec_state->GetArgument(1);
+    SetStyle(node, style);
+  }
+  return Value();
+}
+
+// addEvent(node, event, value);
+static Value AddEvent(ExecState* exec_state) {
+  VNode* node = reinterpret_cast<VNode*>(exec_state->GetArgument(0)->cptr);
+  Value *event = exec_state->GetArgument(1);
+  size_t argc = exec_state->GetArgumentCount() - 2;
+  std::vector<Value> args;
+  for (uint i = 0; i < argc; i++) {
+    Value *params = exec_state->GetArgument(2 + i);
+    args.push_back(*params);
+  }
+  if (node == nullptr || event->type != Value::Type::STRING) {
+    return Value();
+  }
+  node->AddEvent(event->str->c_str(), args);
+  node->set_on_event_listener(
+      std::unique_ptr<VNodeOnEventListener>(new VNodeOnEventListener));
+  return Value();
+}
+
 void VNodeExecEnv::ImportExecEnv(ExecState *state) {
     state->Register("sizeof", SizeOf);
     state->Register("slice", Slice);
@@ -566,8 +591,8 @@ void VNodeExecEnv::ImportExecEnv(ExecState *state) {
     state->Register("createElement", CreateElement);
     state->Register("updateElement", UpdateElement);
     state->Register("createComponent", CreateComponent);
-    state->Register("saveComponentDataAndProps", SaveComponentDataAndProps);
-    state->Register("appendChildComponent", AppendChildComponent);
+    state->Register("saveComponentPropsAndData", saveComponentPropsAndData);
+    state->Register("setComponentRoot", SetComponentRoot);
     state->Register("appendChild", AppendChild);
     state->Register("encodeURIComponent", encodeURIComponent);
     state->Register("encodeURI", encodeURIComponent);
@@ -575,6 +600,7 @@ void VNodeExecEnv::ImportExecEnv(ExecState *state) {
     state->Register("setProps", SetProps);
     state->Register("setClassList", SetClassList);
     state->Register("setStyle", SetStyle);
+    state->Register("addEvent", AddEvent);
     state->Register("__callNativeModule", CallNativeModule);
     // __registerModules deprecated in sversion 5.8 +
     state->Register("__registerModules", RegisterModules);
@@ -664,17 +690,31 @@ json11::Json ValueToJSON(const Value& value) {
 void VNodeExecEnv::ParseData(ExecState* state) {
   const json11::Json& json = state->context()->raw_json();
   Variables* global = state->global();
-  const json11::Json& data = json["data"];
-  Value value = JSONToValue(state, data);
-  if (value.type != Value::Type::TABLE) {
-    value = state->class_factory()->CreateTable();
-  }
-  global->Add("_data_main", value);
 
   // Set component data and props
   Value components_data = state->class_factory()->CreateTable();
   Value components_props = state->class_factory()->CreateTable();
-  const json11::Json& components_obj = json["components"];
+  Value components_computed = state->class_factory()->CreateTable();
+
+  // main means body
+  Value key(state->string_table()->StringFromUTF8("main"));
+  auto main_data = JSONToValue(state, json["data"]);
+  if (main_data.type != Value::Type::TABLE) {
+      main_data = state->class_factory()->CreateTable();
+  }
+  SetTableValue(ValueTo<Table>(&components_data), &key, main_data);
+  auto main_props = JSONToValue(state, json["props"]);
+  if (main_props.type != Value::Type::TABLE) {
+      main_props = state->class_factory()->CreateTable();
+  }
+  SetTableValue(ValueTo<Table>(&components_props), &key, main_props);
+  auto main_computed = JSONToValue(state, json["computed"]);
+  if (main_computed.type != Value::Type::TABLE) {
+      main_computed = state->class_factory()->CreateTable();
+  }
+  SetTableValue(ValueTo<Table>(&components_computed), &key, main_computed);
+
+  const json11::Json &components_obj = json["components"];
   if (components_obj.is_array()) {
     for (auto it = components_obj.array_items().begin();
          it != components_obj.array_items().end(); it++) {
@@ -683,14 +723,23 @@ void VNodeExecEnv::ParseData(ExecState* state) {
         continue;
       }
       auto temp_data = JSONToValue(state, (*it)["data"]);
+      if (temp_data.type != Value::Type::TABLE) {
+          temp_data = state->class_factory()->CreateTable();
+      }
       Value key(state->string_table()->StringFromUTF8(name.string_value()));
       SetTableValue(ValueTo<Table>(&components_data), &key, temp_data);
       auto temp_props = JSONToValue(state, (*it)["props"]);
+        if (temp_props.type != Value::Type::TABLE) {
+            temp_props = state->class_factory()->CreateTable();
+        }
       SetTableValue(ValueTo<Table>(&components_props), &key, temp_props);
+      auto temp_computed = JSONToValue(state, (*it)["computed"]);
+      SetTableValue(ValueTo<Table>(&components_computed), &key, temp_computed);
     }
   }
   global->Add("_components_data", components_data);
   global->Add("_components_props", components_props);
+  global->Add("_components_computed", components_computed);
 }
 
 void VNodeExecEnv::ImportExecData(ExecState *state, const std::string& init_data_str) {
diff --git a/weex_core/Source/core/data_render/vnode/vnode_render_context.cc b/weex_core/Source/core/data_render/vnode/vnode_on_event_listener.h
similarity index 65%
copy from weex_core/Source/core/data_render/vnode/vnode_render_context.cc
copy to weex_core/Source/core/data_render/vnode/vnode_on_event_listener.h
index 3f6c6ed..3c974ab 100644
--- a/weex_core/Source/core/data_render/vnode/vnode_render_context.cc
+++ b/weex_core/Source/core/data_render/vnode/vnode_on_event_listener.h
@@ -17,18 +17,23 @@
  * under the License.
  */
 
-#include "core/data_render/vnode/vnode_render_context.h"
+#ifndef CORE_DATA_RENDER_VNODE_VNODE_ON_EVENT_LISTENER_H_
+#define CORE_DATA_RENDER_VNODE_VNODE_ON_EVENT_LISTENER_H_
+
+#include "core/data_render/vnode/vnode.h"
 
 namespace weex {
 namespace core {
 namespace data_render {
 
-VNodeRenderContext::VNodeRenderContext()
-    : page_id_(), root_(nullptr), raw_json_(), script_() {}
-
-VNodeRenderContext::~VNodeRenderContext() {}
+class VNodeOnEventListener : public VNode::OnEventListener {
+  void OnEvent(VNode *node, const std::string &event,
+               const std::string &json_args, const std::string dom_changes,
+               const VNode::Params &params);
+};
 
-void VNodeRenderContext::Reset() { root_ = nullptr; }
 }  // namespace data_render
 }  // namespace core
-}  // namespace weex
\ No newline at end of file
+}  // namespace weex
+
+#endif  // CORE_DATA_RENDER_VNODE_VNODE_ON_EVENT_LISTENER_H_
diff --git a/weex_core/Source/core/data_render/vnode/vnode_render_context.cc b/weex_core/Source/core/data_render/vnode/vnode_render_context.cc
index 3f6c6ed..158e7ea 100644
--- a/weex_core/Source/core/data_render/vnode/vnode_render_context.cc
+++ b/weex_core/Source/core/data_render/vnode/vnode_render_context.cc
@@ -24,7 +24,12 @@ namespace core {
 namespace data_render {
 
 VNodeRenderContext::VNodeRenderContext()
-    : page_id_(), root_(nullptr), raw_json_(), script_() {}
+    : page_id_(),
+      root_(nullptr),
+      raw_json_(),
+      script_(),
+      vcomponent_trees_(),
+      vnode_trees_() {}
 
 VNodeRenderContext::~VNodeRenderContext() {}
 
diff --git a/weex_core/Source/core/data_render/vnode/vnode_render_context.h b/weex_core/Source/core/data_render/vnode/vnode_render_context.h
index b0a760a..456b1b5 100644
--- a/weex_core/Source/core/data_render/vnode/vnode_render_context.h
+++ b/weex_core/Source/core/data_render/vnode/vnode_render_context.h
@@ -53,6 +53,40 @@ class VNodeRenderContext {
       script_json_ = script_json;
   }
 
+  inline void AddComponent(int ref, VComponent *component) {
+    vcomponent_trees_.insert({ref, component});
+  }
+
+  inline void RemoveComponent(int ref) {
+    vcomponent_trees_.erase(ref);
+  }
+
+  inline VComponent* GetComponent(int ref) {
+    auto it = vcomponent_trees_.find(ref);
+    return it != vcomponent_trees_.end() ? it->second : nullptr;
+  }
+
+  inline void RemoveVNode(const std::string& ref) {
+    auto it = vnode_trees_.find(ref);
+    if (it != vnode_trees_.end()) {
+      vnode_trees_.erase(it);
+    }
+  }
+
+  inline void AddVNode(const std::string& ref, VNode* node) {
+    auto it = vnode_trees_.find(ref);
+    if (it != vnode_trees_.end()) {
+      vnode_trees_[ref] = node;
+    } else {
+      vnode_trees_.insert({ref, node});
+    }
+  }
+
+  inline VNode* GetVNode(const std::string &ref) {
+    auto it = vnode_trees_.find(ref);
+    return it != vnode_trees_.end() ? it->second : nullptr;
+  }
+
  private:
   // node context
   std::string page_id_;
@@ -62,6 +96,8 @@ class VNodeRenderContext {
   // script to execute
   std::string script_;
   std::map<std::string, json11::Json> style_json_;
+  std::unordered_map<int, VComponent *> vcomponent_trees_;
+  std::unordered_map<std::string, VNode*> vnode_trees_;
   json11::Json script_json_;
 };
 }  // namespace data_render
diff --git a/weex_core/Source/core/data_render/vnode/vnode_render_manager.cc b/weex_core/Source/core/data_render/vnode/vnode_render_manager.cc
index eb016cb..9736d4b 100644
--- a/weex_core/Source/core/data_render/vnode/vnode_render_manager.cc
+++ b/weex_core/Source/core/data_render/vnode/vnode_render_manager.cc
@@ -17,19 +17,22 @@
  * under the License.
  */
 
+#include "core/data_render/vnode/vnode_render_manager.h"
 #include <chrono>
 #include <sstream>
-#include "core/data_render/vnode/vnode_render_manager.h"
+#include "base/make_copyable.h"
+#include "base/string_util.h"
+#include "core/bridge/platform_bridge.h"
 #include "core/data_render/common_error.h"
-#include "core/data_render/exec_state_binary.h"
 #include "core/data_render/exec_state.h"
+#include "core/data_render/exec_state_binary.h"
 #include "core/data_render/string_table.h"
 #include "core/data_render/vnode/vnode.h"
 #include "core/data_render/vnode/vnode_exec_env.h"
 #include "core/manager/weex_core_manager.h"
+#include "core/network/http_module.h"
 #include "core/render/manager/render_manager.h"
 #include "core/render/node/factory/render_creator.h"
-#include "core/bridge/platform_bridge.h"
 
 #define VRENDER_LOG true
 
@@ -60,11 +63,17 @@ WeexCore::RenderObject* ParseVNode2RenderObject(VNode* vnode,
                                                 WeexCore::RenderObject* parent, bool isRoot,
                                                 int index,
                                                 const string& pageId) {
+  if (vnode->IsVirtualComponent()) {
+    VComponent* component = static_cast<VComponent*>(vnode);
+    if (component->root_vnode() == nullptr) {
+      component->UpdateData();
+    }
+    return ParseVNode2RenderObject(component->root_vnode(), parent, isRoot,
+                                   index, pageId);
+  }
   std::string ref_str;
   if (isRoot) {
     ref_str = "_root";
-  } else if (!vnode->node_id().empty()) {
-    ref_str = vnode->node_id();
   } else {
     ref_str = base::to_string(ref_id++);
   }
@@ -87,14 +96,19 @@ WeexCore::RenderObject* ParseVNode2RenderObject(VNode* vnode,
     render_object->AddAttr(it->first, it->second);
   }
 
-  // event,todo
+  // event
   std::map<std::string, void *> *events = vnode->events();
   for (auto iter = events->begin(); iter != events->end(); iter++) {
       render_object->events()->insert(iter->first);
   }
+  auto event_params_map = vnode->event_params_map();
+  for (auto it = event_params_map->begin(); it != event_params_map->end();
+       it++) {
+    render_object->events()->insert(it->first);
+  }
 
   // child
-  vector<VNode*>* children = (const_cast<VNode*>(vnode))->child_list();
+  vector<VNode*>* children = vnode->child_list();
   for (int i = 0; i < children->size(); i++) {
     ParseVNode2RenderObject((*children)[i], render_object, false, i, pageId);
   }
@@ -165,14 +179,14 @@ void VNodeRenderManager::InitVM() {
   }
 }
 
-void VNodeRenderManager::CreatePage(const std::string &input, const std::string &page_id, const  std::string &options, const std::string &init_data) {
-    std::string err = CreatePageWithContent(input, page_id, options, init_data);
+void VNodeRenderManager::CreatePage(const std::string &input, const std::string &page_id, const  std::string &options, const std::string &init_data, std::function<void(const char*)> exec_js) {
+    std::string err = CreatePageWithContent(input, page_id, options, init_data, exec_js);
     if (!err.empty()) {
         WeexCore::WeexCoreManager::Instance()->getPlatformBridge()->platform_side()->ReportException(page_id.c_str(), nullptr, err.c_str());
     }
 }
 
-std::string VNodeRenderManager::CreatePageWithContent(const std::string &input, const std::string &page_id, const std::string &options, const std::string &init_data) {
+std::string VNodeRenderManager::CreatePageWithContent(const std::string &input, const std::string &page_id, const std::string &options, const std::string &init_data, std::function<void(const char*)> exec_js) {
     InitVM();
 #ifdef DEBUG
     auto start = std::chrono::steady_clock::now();
@@ -214,14 +228,72 @@ std::string VNodeRenderManager::CreatePageWithContent(const std::string &input,
     if (exec_state->context()->root() == NULL) {
         return err;
     }
+
     CreatePageInternal(page_id, exec_state->context()->root());
 #ifdef DEBUG
     auto duration_post = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start);
     LOGD("DATA_RENDER, All time %lld\n", duration_post.count());
 #endif
+    DownloadAndExecScript(exec_state, page_id, exec_js);
     return err;
 }
-    
+
+void VNodeRenderManager::DownloadAndExecScript(
+    ExecState* exec_state, const std::string& page_id,
+    std::function<void(const char*)> exec_js) {
+  // If script exists in json, run script into js vm
+  const json11::Json& script_array =
+    exec_state->context()->script_json();
+  if (script_array.is_array()) {
+    for (auto it = script_array.array_items().begin();
+         it != script_array.array_items().end(); it++) {
+      const json11::Json& script_obj = *it;
+      auto src = script_obj["src"];
+      auto content = script_obj["content"];
+      auto callback1 = weex::base::MakeCopyable(
+          [page_id = page_id, exec_js = exec_js, exec_state = exec_state](const char* result) {
+            exec_js(result);
+            auto root =
+                VNodeRenderManager::GetInstance()->GetRootVNode(page_id);
+            if (root && root->IsVirtualComponent()) {
+              static_cast<weex::core::data_render::VComponent*>(root)
+                  ->DispatchCreated();
+
+                //fire event
+                exec_state->set_exec_js_finished(true);
+                const std::vector<std::vector<std::string>>& event_queue = exec_state->event_queue();
+                for (auto args : event_queue) {
+                    VNodeRenderManager::GetInstance()->FireEvent(args[0], args[1], args[2], args[3], args[4]);
+                }
+                exec_state->ClearEventQueue();
+            }
+          });
+      // callback2, a wrap for callback1, will be post to script thread to
+      // execute callback1
+      auto callback2 = weex::base::MakeCopyable([callback = callback1](
+                                                    const std::string& result) {
+#ifdef OS_ANDROID
+        WeexCoreManager::Instance()->script_thread()->message_loop()->PostTask(
+            weex::base::MakeCopyable([result = std::move(result), callback]() {
+              callback(result.c_str());
+            }));
+#else
+          callback(result.c_str());
+#endif
+      });
+      // If script is a url, first download the script, else run script
+      // directly.
+      if (content.is_string() && !content.string_value().empty()) {
+        callback1(const_cast<char*>(content.string_value().c_str()));
+      } else if (src.is_string()) {
+        network::HttpModule http_module;
+        http_module.Send(page_id.c_str(), src.string_value().c_str(),
+                         callback2);
+      }
+    }
+  }
+}
+
 bool VNodeRenderManager::RequireModule(ExecState *exec_state, std::string &name, std::string &result)
 {
     bool finished = false;
@@ -262,7 +334,7 @@ void VNodeRenderManager::ExecuteRegisterModules(ExecState *exec_state, std::vect
     } while (0);
 }
 
-std::string VNodeRenderManager::CreatePageWithContent(const uint8_t *contents, size_t length, const std::string &page_id, const std::string &options, const std::string &init_data) {
+std::string VNodeRenderManager::CreatePageWithContent(const uint8_t *contents, size_t length, const std::string &page_id, const std::string &options, const std::string &init_data,  std::function<void(const char*)> exec_js) {
     InitVM();
 #ifdef DEBUG
     auto start = std::chrono::steady_clock::now();
@@ -295,11 +367,12 @@ std::string VNodeRenderManager::CreatePageWithContent(const uint8_t *contents, s
     auto duration_post = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start);
     LOGD("[DATA_RENDER], All time:[%lld]\n", duration_post.count());
 #endif
+    DownloadAndExecScript(exec_state, page_id, exec_js);
     return err;
 }
 
-void VNodeRenderManager::CreatePage(const char *contents, size_t length, const std::string& page_id, const std::string& options, const std::string& init_data) {
-    string err = CreatePageWithContent((const uint8_t *)contents, length, page_id, options, init_data);
+void VNodeRenderManager::CreatePage(const char *contents, size_t length, const std::string& page_id, const std::string& options, const std::string& init_data, std::function<void(const char*)> exec_js) {
+    string err = CreatePageWithContent((const uint8_t *)contents, length, page_id, options, init_data, exec_js);
     if (!err.empty()) {
         WeexCore::WeexCoreManager::Instance()->getPlatformBridge()->platform_side()->ReportException(page_id.c_str(), nullptr, err.c_str());
     }
@@ -313,6 +386,18 @@ bool VNodeRenderManager::RefreshPage(const std::string& page_id,
             break;
         }
         ExecState *exec_state = it->second;
+        // If component exsit, refresh by component
+        auto it_vnode = vnode_trees_.find(page_id);
+        if (it_vnode == vnode_trees_.end()) {
+            return false;
+        }
+        if (it_vnode->second->IsVirtualComponent()) {
+            auto component = static_cast<VComponent*>(it_vnode->second);
+            Value data = StringToValue(exec_state, init_data);
+            component->UpdateData(&data);
+            return true;
+        }
+        // Otherwise re-execute
         VNodeExecEnv::ImportExecData(exec_state, init_data);
         std::string err;
         exec_state->context()->Reset();
@@ -325,9 +410,9 @@ bool VNodeRenderManager::RefreshPage(const std::string& page_id,
         }
         RefreshPageInternal(page_id, exec_state->context()->root());
         WeexCore::WeexCoreManager::Instance()
-        ->getPlatformBridge()
-        ->platform_side()
-        ->RefreshFinish(page_id.c_str(), nullptr, "");
+            ->getPlatformBridge()
+            ->platform_side()
+            ->RefreshFinish(page_id.c_str(), nullptr, "");
         return true;
         
     } while (0);
@@ -347,17 +432,38 @@ bool VNodeRenderManager::ClosePage(const std::string& page_id) {
   return true;
 }
         
-void VNodeRenderManager::FireEvent(const std::string &page_id, const std::string &ref, const std::string &event,const std::string &args) {
+void VNodeRenderManager::FireEvent(const std::string &page_id, const std::string &ref, const std::string &event,const std::string &args,const std::string &dom_changes) {
     do {
         auto iter = exec_states_.find(page_id);
         if (iter == exec_states_.end()) {
             break;
         }
+        if (!iter->second->exec_js_finished()) {
+            std::vector<std::string> fire_event = {page_id, ref, event, args, dom_changes};
+            iter->second->AddEvent(fire_event);
+            break;
+        }
         auto node = vnode_trees_.find(page_id);
         if (node == vnode_trees_.end()) {
             break;
         }
+        // TODO merge two way to fire event
+        {
+            // First way to fire event from VNode::OnEvent
+            auto vnode = iter->second->context()->GetVNode(ref);
+            if (vnode) {
+                auto hit_test = vnode->event_params_map()->find(event);
+                if (hit_test != vnode->event_params_map()->end()) {
+                    // If vnode has eat event, return.
+                    vnode->OnEvent(event, args, dom_changes);
+                    return;
+                }
+            }
+        }
+
+        // Second way to fire event from call vm func
         auto vnode = node->second->FindNode(ref);
+        if (vnode == nullptr)
         if (!vnode) {
             break;
         }
@@ -436,21 +542,35 @@ void VNodeRenderManager::WXLogNative(ExecState *exec_state, const std::string &i
     }
 }
 
+void VNodeRenderManager::UpdateComponentData(const std::string& page_id,
+                                             const char* cid,
+                                             const std::string& json_data) {
+  ExecState* exec_state = GetExecState(page_id);
+  if (!exec_state) return;
+  VComponent* component = exec_state->context()->GetComponent(atoi(cid));
+  if (component) {
+    Value value(StringToValue(exec_state, json_data));
+    component->UpdateData(&value);
+  }
+}
+
 void VNodeRenderManager::PatchVNode(ExecState *exec_state, VNode *v_node, VNode *new_node) {
-    do {
-        for (auto iter = exec_states_.begin(); iter != exec_states_.end(); iter++) {
-            if (iter->second == exec_state) {
-                Patch(iter->first, v_node, new_node);
-                break;
-            }
+    for (auto iter = exec_states_.begin(); iter != exec_states_.end(); iter++) {
+        if (iter->second == exec_state) {
+            Patch(iter->first, v_node, new_node);
+            break;
         }
-        
-    } while (0);
+    }
 }
-    
+
 bool SameNode(VNode* a, VNode* b) {
-  return a->tag_name() == b->tag_name() &&
-         a->ref() == b->ref();  // todo to be more accurate
+  if (a->IsVirtualComponent() && b->IsVirtualComponent()) {
+    return static_cast<VComponent*>(a)->IsSameNode(static_cast<VComponent*>(b));
+  } else {
+    // todo to be more accurate
+    return a->tag_name() == b->tag_name() && a->ref() == b->ref() &&
+           a->IsVirtualComponent() == b->IsVirtualComponent();
+  }
 }
 
 inline VNode* GetOrNull(vector<VNode*>& vec, int index) {
@@ -498,10 +618,10 @@ void UpdateChildren(const string& page_id, VNode* old_node, VNode* new_node) {
     ref_list.push_back((*begin));
   }
 
-  unsigned int old_start = 0;
-  unsigned int old_end = static_cast<unsigned int >(old_children.size()) - 1;
-  unsigned int new_start = 0;
-  unsigned int new_end = static_cast<unsigned int >(new_children.size()) - 1;
+  int old_start = 0;
+  int old_end = static_cast<int>(old_children.size()) - 1;
+  int new_start = 0;
+  int new_end = static_cast<int>(new_children.size()) - 1;
   VNode* old_start_node = GetOrNull(old_children, old_start);
   VNode* old_end_node = GetOrNull(old_children, old_end);
   VNode* new_start_node = GetOrNull(new_children, new_start);
@@ -546,7 +666,7 @@ void UpdateChildren(const string& page_id, VNode* old_node, VNode* new_node) {
         ref_to_index = new map<string, unsigned int>();
         for (unsigned int i = old_start; i <= old_end; ++i) {
           auto vnode = GetOrNull(old_children, i);
-          if (vnode == nullptr) {
+          if (vnode == nullptr || vnode->ref().empty()) {
             continue;
           }
           ref_to_index->insert({vnode->ref(), i});
@@ -623,7 +743,7 @@ void CreateAndInsertElm(const string& page_id, VNode* node,
 int MoveToBackOfRef(vector<VNode*>& ref_list, const VNode* move_ref,
                     const VNode* anchor_ref) {
   auto move_pos = IndexOf(ref_list, move_ref);
-  int index = static_cast<int>(std::distance(ref_list.begin(), move_pos));
+  auto anchor_pos = IndexOf(ref_list, anchor_ref);
   if (move_pos == ref_list.end()) {
 #if VRENDER_LOG
     LOGE("[VRenderManager] moveToBackOfRef movePos == refList.end() ref: %s",
@@ -631,9 +751,6 @@ int MoveToBackOfRef(vector<VNode*>& ref_list, const VNode* move_ref,
 #endif
     return -1;  // wtf!
   }
-  VNode* value = *move_pos;
-  ref_list.erase(move_pos);
-  auto anchor_pos = IndexOf(ref_list, anchor_ref);
   if (anchor_pos == ref_list.end()) {
 #if VRENDER_LOG
     LOGE("[VRenderManager] moveToBackOfRef anchorPos == refList.end() ref: %s",
@@ -641,14 +758,17 @@ int MoveToBackOfRef(vector<VNode*>& ref_list, const VNode* move_ref,
 #endif
     return -1;  // wtf
   }
-  ref_list.insert(++anchor_pos, value);
+  int index = static_cast<int>(std::distance(ref_list.begin(), anchor_pos));
+  VNode* value = *move_pos;
+  ref_list.erase(move_pos);
+  ref_list.insert(anchor_pos, value);
   return index;
 }
 
 int MoveToFrontOfRef(vector<VNode*>& ref_list, const VNode* move_ref,
                      const VNode* anchor_ref) {
   auto move_pos = IndexOf(ref_list, move_ref);
-  int index = static_cast<int>(std::distance(ref_list.begin(), move_pos));
+  auto anchor_pos = IndexOf(ref_list, anchor_ref);
   if (move_pos == ref_list.end()) {
 #if VRENDER_LOG
     LOGE("[VRenderManager] moveToFrontOfRef movePos == refList.end() ref: %s",
@@ -656,9 +776,6 @@ int MoveToFrontOfRef(vector<VNode*>& ref_list, const VNode* move_ref,
 #endif
     return -1;  // wtf!
   }
-  VNode* value = *move_pos;
-  ref_list.erase(move_pos);
-  auto anchor_pos = IndexOf(ref_list, anchor_ref);
   if (anchor_pos == ref_list.end()) {
 #if VRENDER_LOG
     LOGE("[VRenderManager] moveToFrontOfRef anchorPos == refList.end() ref: %s",
@@ -666,6 +783,9 @@ int MoveToFrontOfRef(vector<VNode*>& ref_list, const VNode* move_ref,
 #endif
     return -1;  // wtf
   }
+  int index = static_cast<int>(std::distance(ref_list.begin(), anchor_pos));
+  VNode* value = *move_pos;
+  ref_list.erase(move_pos);
   ref_list.insert(anchor_pos, value);
   return index;
 }
@@ -728,7 +848,6 @@ vector<pair<string, string>>* CompareMap(const map<string, string>& oldMap,
   auto p_vec = new vector<pair<string, string>>();
   for (auto it = newMap.cbegin(); it != newMap.cend(); it++) {
     auto pos = oldMap.find(it->first);
-
     if (pos == oldMap.end() || pos->second != it->second) {
       // key not exist, or value not same
       p_vec->push_back({it->first, it->second});
@@ -737,7 +856,6 @@ vector<pair<string, string>>* CompareMap(const map<string, string>& oldMap,
 
   for (auto it = oldMap.cbegin(); it != oldMap.cend(); it++) {
     auto pos = newMap.find(it->first);
-
     if (pos == newMap.end()) {
       // key not exist, remove //todo check if this is correct
       p_vec->push_back({it->first, ""});
@@ -745,8 +863,70 @@ vector<pair<string, string>>* CompareMap(const map<string, string>& oldMap,
   }
   return p_vec;
 };
- 
+
+void CompareAndApplyEvents1(const std::string& page_id, VNode* old_node,
+                            VNode* new_node) {
+  std::map<std::string, void*> old_events = *old_node->events();
+  std::map<std::string, void*> new_events = *new_node->events();
+
+  for (auto it = old_events.cbegin(); it != old_events.cend(); it++) {
+    auto pos = new_events.find(it->first);
+    if (pos == new_events.end()) {
+      new_events.erase(pos);
+    }
+  }
+  for (auto it = new_events.cbegin(); it != new_events.cend(); it++) {
+    auto pos = old_events.find(it->first);
+    if (pos == old_events.end()) {
+      old_events.erase(pos);
+    }
+  }
+  for (auto it = old_events.cbegin(); it != old_events.cend(); it++) {
+    RenderManager::GetInstance()->RemoveEvent(
+        page_id, new_node->render_object_ref(), it->first);
+  }
+  for (auto it = new_events.cbegin(); it != new_events.cend(); it++) {
+    RenderManager::GetInstance()->AddEvent(
+        page_id, new_node->render_object_ref(), it->first);
+  }
+}
+
+void CompareAndApplyEvents2(const std::string& page_id, VNode* old_node,
+                            VNode* new_node) {
+  VNode::EventParamsMap old_events = *old_node->event_params_map();
+  VNode::EventParamsMap new_events = *new_node->event_params_map();
+
+  for (auto it = old_events.cbegin(); it != old_events.cend(); it++) {
+    auto pos = new_events.find(it->first);
+
+    if (pos == new_events.end()) {
+      new_events.erase(pos);
+    }
+  }
+  for (auto it = new_events.cbegin(); it != new_events.cend(); it++) {
+    auto pos = old_events.find(it->first);
+
+    if (pos == old_events.end()) {
+      old_events.erase(pos);
+    }
+  }
+  for (auto it = old_events.cbegin(); it != old_events.cend(); it++) {
+    RenderManager::GetInstance()->RemoveEvent(
+        page_id, new_node->render_object_ref(), it->first);
+  }
+  for (auto it = new_events.cbegin(); it != new_events.cend(); it++) {
+    RenderManager::GetInstance()->AddEvent(
+        page_id, new_node->render_object_ref(), it->first);
+  }
+}
+
 void PatchVNode(const string& page_id, VNode* old_node, VNode* new_node) {
+  if (old_node->IsVirtualComponent()) {
+    static_cast<VComponent*>(old_node)
+        ->MoveTo(static_cast<VComponent*>(new_node));
+    return;
+  }
+
   // patch render object link
   new_node->set_render_object_ref(old_node->render_object_ref());
 
@@ -754,8 +934,7 @@ void PatchVNode(const string& page_id, VNode* old_node, VNode* new_node) {
   auto p_vec = CompareMap(*(old_node->attributes()), *(new_node->attributes()));
   if (p_vec->size() > 0) {
       RenderManager::GetInstance()->UpdateAttr(page_id, new_node->render_object_ref(), p_vec);
-  }
-  else {
+  } else {
       delete p_vec;
       p_vec = nullptr;
   }
@@ -763,14 +942,14 @@ void PatchVNode(const string& page_id, VNode* old_node, VNode* new_node) {
   p_vec = CompareMap(*(old_node->styles()), *(new_node->styles()));
   if (p_vec->size()) {
       RenderManager::GetInstance()->UpdateStyle(page_id, new_node->render_object_ref(), p_vec);
-  }
-  else {
+  } else {
       delete p_vec;
       p_vec = nullptr;
   }
 
-  // compare event
-  // todo
+  // compare and apply event
+  CompareAndApplyEvents1(page_id, old_node, new_node);
+  CompareAndApplyEvents2(page_id, old_node, new_node);
 
   // compare children
   if (old_node->HasChildren() && new_node->HasChildren()) {
@@ -785,32 +964,39 @@ void PatchVNode(const string& page_id, VNode* old_node, VNode* new_node) {
     int index = 0;
     for (auto it = new_node->child_list()->cbegin();
          it != new_node->child_list()->cend(); it++) {
-      WeexCore::RenderObject *root = VNode2RenderObject(*it, page_id);
+      WeexCore::RenderObject *child_node = ParseVNode2RenderObject(*it, nullptr, false, 0, page_id);
       RenderManager::GetInstance()->AddRenderObject(
-          page_id, (*it)->parent()->render_object_ref(), index, root);
+                                                      page_id, (*it)->parent()->render_object_ref(), index, child_node);
       ++index;
     }
   }
 }
 
 void Patch(const string& page_id, VNode *old_node, VNode *new_node) {
-    if (old_node->parent() == NULL || SameNode(old_node, new_node)) {
+    if (!old_node) {
+        ParseVNode2RenderObject(new_node, nullptr, false, 0, page_id);
+    } else if (old_node->parent() == NULL || SameNode(old_node, new_node)) {
         // root must be the same;
         PatchVNode(page_id, old_node, new_node);
-    }
-    else {
-        VNode *parent = (VNode *)old_node->parent();
-        vector<VNode *> &old_children = *parent->child_list();
+    } else {
         WeexCore::RenderObject *new_render_object = ParseVNode2RenderObject(new_node, nullptr, false, 0, page_id);
-        auto pos = std::find(old_children.begin(), old_children.end(), old_node);
-        int index = static_cast<int>(std::distance(old_children.begin(), pos));
-        parent->InsertChild(new_node, index);
-        RenderManager::GetInstance()->AddRenderObject(page_id, parent->render_object_ref(), index, new_render_object);
-        parent->RemoveChild(old_node);
-        RenderManager::GetInstance()->RemoveRenderObject(page_id, old_node->render_object_ref());
+        VNode *parent = (VNode *)old_node->parent();
+        if (!parent && old_node->component()) {
+            parent = const_cast<VNode*>(old_node->component()->parent());
+            old_node = old_node->component();
+        }
+        if (parent) {
+            vector<VNode *> &old_children = *parent->child_list();
+            auto pos = std::find(old_children.begin(), old_children.end(), old_node);
+            int index = static_cast<int>(std::distance(old_children.begin(), pos));
+            parent->InsertChild(new_node, index);
+            RenderManager::GetInstance()->AddRenderObject(page_id, parent->render_object_ref(), index, new_render_object);
+            parent->RemoveChild(old_node);
+            RenderManager::GetInstance()->RemoveRenderObject(page_id, old_node->render_object_ref());
+        }
     }
 }
-    
+
 }  // namespace data_render
 }  // namespace core
 }  // namespace weex
diff --git a/weex_core/Source/core/data_render/vnode/vnode_render_manager.h b/weex_core/Source/core/data_render/vnode/vnode_render_manager.h
index 85cb3b8..cf33330 100644
--- a/weex_core/Source/core/data_render/vnode/vnode_render_manager.h
+++ b/weex_core/Source/core/data_render/vnode/vnode_render_manager.h
@@ -34,6 +34,7 @@ namespace weex {
 namespace core {
 namespace data_render {
 
+class HttpModule;
 class VNodeRenderManager {
  friend class VNode;
  private:
@@ -42,18 +43,19 @@ class VNodeRenderManager {
   ~VNodeRenderManager() {}
 
  public:
-  void CreatePage(const std::string &input, const std::string &page_id, const std::string &options, const std::string &init_data);
+  void CreatePage(const std::string &input, const std::string &page_id, const std::string &options, const std::string &init_data, std::function<void(const char*)> exec_js);
 
-  void CreatePage(const char *contents, size_t length, const std::string& page_id, const std::string& options, const std::string& init_data);
+  void CreatePage(const char *contents, size_t length, const std::string& page_id, const std::string& options, const std::string& init_data, std::function<void(const char*)> exec_js);
 
   bool RefreshPage(const std::string &page_id, const std::string &init_data);
   bool ClosePage(const std::string &page_id);
-  void FireEvent(const std::string &page_id, const std::string &ref, const std::string &event,const std::string &args);
+  void FireEvent(const std::string &page_id, const std::string &ref, const std::string &event,const std::string &args,const std::string &dom_changes);
   void ExecuteRegisterModules(ExecState *exec_state, std::vector<std::string>& registers);
   void RegisterModules(const std::string &modules) { modules_.push_back(modules); }
   bool RequireModule(ExecState *exec_state, std::string &name, std::string &result);
   void PatchVNode(ExecState *exec_state, VNode *v_node, VNode *new_node);
   void CallNativeModule(ExecState *exec_state, const std::string &module, const std::string &method, const std::string &args, int argc = 0);
+  void UpdateComponentData(const std::string& page_id, const char* cid, const std::string& json_data);
   void WXLogNative(ExecState *exec_state, const std::string &info);
   static VNodeRenderManager *GetInstance() {
     if (!g_instance) {
@@ -62,20 +64,39 @@ class VNodeRenderManager {
     return g_instance;
   }
 
+  inline ExecState *GetExecState(const std::string &instance_id) {
+    auto it = exec_states_.find(instance_id);
+    return it != exec_states_.end() ? it->second : nullptr;
+  }
+
+  inline VNode *GetRootVNode(const std::string &instance_id) {
+    auto it = vnode_trees_.find(instance_id);
+    return it != vnode_trees_.end() ? it->second : nullptr;
+  }
+
  private:
   void InitVM();
   bool CreatePageInternal(const std::string &page_id, VNode *v_node);
   bool RefreshPageInternal(const std::string &page_id, VNode *new_node);
   bool ClosePageInternal(const std::string &page_id);
+  void DownloadAndExecScript(ExecState *exec_state, const std::string &page_id,
+                             std::function<void(const char *)> exec_js);
 
-  std::string CreatePageWithContent(const uint8_t *contents, size_t length, const std::string &page_id, const std::string &options, const std::string &init_data);
-  std::string CreatePageWithContent(const std::string &input, const std::string &page_id, const std::string &options, const std::string &init_data);
+  std::string CreatePageWithContent(const uint8_t *contents, size_t length,
+                                    const std::string &page_id,
+                                    const std::string &options,
+                                    const std::string &init_data,
+                                    std::function<void(const char*)> exec_js);
+  std::string CreatePageWithContent(const std::string &input,
+                                    const std::string &page_id,
+                                    const std::string &options,
+                                    const std::string &init_data,
+                                    std::function<void(const char *)> exec_js);
 
   static VM *g_vm;
   static VNodeRenderManager *g_instance;
 
   std::map<std::string, VNode *> vnode_trees_;
-  std::unordered_map<int, VComponent *> vcomponent_tree_;
   std::map<std::string, ExecState *> exec_states_;
   std::vector<std::string> modules_;
 };
diff --git a/weex_core/Source/core/network/android/default_request_handler.cc b/weex_core/Source/core/network/android/default_request_handler.cc
new file mode 100644
index 0000000..f44dc59
--- /dev/null
+++ b/weex_core/Source/core/network/android/default_request_handler.cc
@@ -0,0 +1,77 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#if OS_ANDROID
+
+#include "core/network/android/default_request_handler.h"
+#include "android/base/jni/android_jni.h"
+#include "android/base/string/scoped_jstring_utf8.h"
+#include "android/jniprebuild/jniheader/RequestHandler_jni.h"
+
+using namespace weex::core::network;
+
+static void InvokeOnSuccess(JNIEnv* env, jobject jcaller, jlong callback,
+                            jstring result) {
+  CallbackWrapper* callback_wrapper =
+      reinterpret_cast<CallbackWrapper*>(callback);
+  WeexCore::ScopedJStringUTF8 jni_result(env, result);
+  callback_wrapper->Invoke(jni_result.getChars() ? jni_result.getChars() : "");
+  delete callback_wrapper;
+}
+
+static void InvokeOnFailed(JNIEnv* env, jobject jcaller, jlong callback) {
+  CallbackWrapper* callback_wrapper =
+      reinterpret_cast<CallbackWrapper*>(callback);
+  delete callback_wrapper;
+}
+
+namespace weex {
+namespace core {
+namespace network {
+
+bool DefaultRequestHandler::RegisterJNIUtils(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+DefaultRequestHandler::DefaultRequestHandler() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Reset(env, Java_RequestHandler_create(env).Release());
+}
+
+DefaultRequestHandler::~DefaultRequestHandler() {}
+
+void DefaultRequestHandler::Send(const char* instance_id, const char* url,
+                                 Callback callback) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  if (!env) return;
+  CallbackWrapper* callback_wrapper = new CallbackWrapper(callback);
+  base::android::ScopedLocalJavaRef<jstring> jni_url(env,
+                                                     env->NewStringUTF(url));
+  base::android::ScopedLocalJavaRef<jstring> jni_id(
+      env, env->NewStringUTF(instance_id));
+  Java_RequestHandler_send(env, jni_object(), jni_id.Get(), jni_url.Get(),
+                           reinterpret_cast<jlong>(callback_wrapper));
+}
+
+RequestHandler* RequestHandler::CreateDefaultHandler() {
+  return new DefaultRequestHandler();
+}
+}  // namespace network
+}  // namespace core
+}  // namespace weex
+#endif
\ No newline at end of file
diff --git a/weex_core/Source/core/data_render/string_table.h b/weex_core/Source/core/network/android/default_request_handler.h
similarity index 52%
copy from weex_core/Source/core/data_render/string_table.h
copy to weex_core/Source/core/network/android/default_request_handler.h
index 5d1dddd..cf1f556 100644
--- a/weex_core/Source/core/data_render/string_table.h
+++ b/weex_core/Source/core/network/android/default_request_handler.h
@@ -16,46 +16,41 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+#if OS_ANDROID
 
-#ifndef CORE_DATA_RENDER_STRING_TABLE_H
-#define CORE_DATA_RENDER_STRING_TABLE_H
+#ifndef CORE_NETWORK_DEFAULT_REQUEST_HANDLER_H
+#define CORE_NETWORK_DEFAULT_REQUEST_HANDLER_H
 
-#include <memory>
-#include <string>
-#include <map>
-#include <vector>
+#include <jni.h>
+#include "android/wrap/jni_object_wrap.h"
+#include "core/network/request_handler.h"
 
 namespace weex {
 namespace core {
-namespace data_render {
-class String {
- public:
-  explicit String(const char *str, std::size_t len);
-  explicit String(const std::string &str);
-  ~String();
-
-  char *c_str() { return str_.get(); }
+namespace network {
 
-  std::size_t length() { return length_; }
-
- private:
-  std::unique_ptr<char[]> str_;
-  size_t length_;
+class DefaultRequestHandler : public RequestHandler,
+                              public WeexCore::JNIObjectWrap {
+ public:
+  static bool RegisterJNIUtils(JNIEnv* env);
+  DefaultRequestHandler();
+  ~DefaultRequestHandler() override;
+  void Send(const char* instance_id, const char* url,
+            Callback callback) override;
 };
 
-class StringTable {
+class CallbackWrapper {
  public:
-  StringTable() : store_() {}
-  ~StringTable();
-
-  String *StringFromUTF8(const std::string &str);
-  inline const std::vector<std::pair<std::string, std::unique_ptr<String>>>& store() {return store_;}
+  CallbackWrapper(Callback callback) : callback_(callback) {}
+  ~CallbackWrapper() {}
+  void Invoke(const std::string& result) { callback_(result); }
 
  private:
-  std::vector<std::pair<std::string, std::unique_ptr<String>>> store_;
+  Callback callback_;
 };
-}  // namespace data_render
+
+}  // namespace network
 }  // namespace core
 }  // namespace weex
-
-#endif  // CORE_DATA_RENDER_STRING_TABLE_H
+#endif  // CORE_NETWORK_DEFAULT_REQUEST_HANDLER_H
+#endif
diff --git a/weex_core/Source/core/data_render/vnode/vnode_render_context.cc b/weex_core/Source/core/network/http_module.cc
similarity index 63%
copy from weex_core/Source/core/data_render/vnode/vnode_render_context.cc
copy to weex_core/Source/core/network/http_module.cc
index 3f6c6ed..200952f 100644
--- a/weex_core/Source/core/data_render/vnode/vnode_render_context.cc
+++ b/weex_core/Source/core/network/http_module.cc
@@ -16,19 +16,24 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-#include "core/data_render/vnode/vnode_render_context.h"
+#include "core/network/http_module.h"
+#include "core/network/request_handler.h"
 
 namespace weex {
 namespace core {
-namespace data_render {
+namespace network {
+
+HttpModule::HttpModule()
+    : request_handler_(RequestHandler::CreateDefaultHandler()) {}
 
-VNodeRenderContext::VNodeRenderContext()
-    : page_id_(), root_(nullptr), raw_json_(), script_() {}
+HttpModule::HttpModule(RequestHandler* request_handler)
+    : request_handler_(request_handler) {}
 
-VNodeRenderContext::~VNodeRenderContext() {}
+void HttpModule::Send(const char* instance_id, const char* url,
+                      Callback callback) {
+  request_handler_->Send(instance_id, url, callback);
+}
 
-void VNodeRenderContext::Reset() { root_ = nullptr; }
-}  // namespace data_render
+}  // namespace network
 }  // namespace core
-}  // namespace weex
\ No newline at end of file
+}  // namespace weex
diff --git a/weex_core/Source/core/data_render/vnode/vnode_render_context.cc b/weex_core/Source/core/network/http_module.h
similarity index 66%
copy from weex_core/Source/core/data_render/vnode/vnode_render_context.cc
copy to weex_core/Source/core/network/http_module.h
index 3f6c6ed..4c4b579 100644
--- a/weex_core/Source/core/data_render/vnode/vnode_render_context.cc
+++ b/weex_core/Source/core/network/http_module.h
@@ -17,18 +17,25 @@
  * under the License.
  */
 
-#include "core/data_render/vnode/vnode_render_context.h"
+#ifndef CORE_NETWORK_HTTP_MODULE_
+#define CORE_NETWORK_HTTP_MODULE_
+#include "core/network/request_handler.h"
 
 namespace weex {
 namespace core {
-namespace data_render {
+namespace network {
 
-VNodeRenderContext::VNodeRenderContext()
-    : page_id_(), root_(nullptr), raw_json_(), script_() {}
+class HttpModule {
+ public:
+  HttpModule();
+  HttpModule(RequestHandler* request_handler);
+  void Send(const char* instance_id, const char* url, Callback callback);
 
-VNodeRenderContext::~VNodeRenderContext() {}
+ private:
+  std::unique_ptr<RequestHandler> request_handler_;
+};
 
-void VNodeRenderContext::Reset() { root_ = nullptr; }
-}  // namespace data_render
+}  // namespace network
 }  // namespace core
-}  // namespace weex
\ No newline at end of file
+}  // namespace weex
+#endif  // CORE_NETWORK_HTTP_MODULE_
diff --git a/weex_core/Source/core/data_render/vnode/vnode_render_context.cc b/weex_core/Source/core/network/ios/default_request_handler.h
similarity index 64%
copy from weex_core/Source/core/data_render/vnode/vnode_render_context.cc
copy to weex_core/Source/core/network/ios/default_request_handler.h
index 3f6c6ed..2099d53 100644
--- a/weex_core/Source/core/data_render/vnode/vnode_render_context.cc
+++ b/weex_core/Source/core/network/ios/default_request_handler.h
@@ -17,18 +17,24 @@
  * under the License.
  */
 
-#include "core/data_render/vnode/vnode_render_context.h"
+#ifndef CORE_NETWORK_DEFAULT_REQUEST_HANDLER_H
+#define CORE_NETWORK_DEFAULT_REQUEST_HANDLER_H
+
+#include "core/network/request_handler.h"
 
 namespace weex {
 namespace core {
-namespace data_render {
-
-VNodeRenderContext::VNodeRenderContext()
-    : page_id_(), root_(nullptr), raw_json_(), script_() {}
+namespace network {
 
-VNodeRenderContext::~VNodeRenderContext() {}
+class DefaultRequestHandler : public RequestHandler {
+ public:
+  DefaultRequestHandler();
+  ~DefaultRequestHandler() override;
+  void Send(const char* instance_id, const char* url,
+            Callback callback) override;
+};
 
-void VNodeRenderContext::Reset() { root_ = nullptr; }
-}  // namespace data_render
+}  // namespace network
 }  // namespace core
-}  // namespace weex
\ No newline at end of file
+}  // namespace weex
+#endif  // CORE_NETWORK_DEFAULT_REQUEST_HANDLER_H
diff --git a/weex_core/Source/core/data_render/vnode/vnode_render_context.cc b/weex_core/Source/core/network/ios/default_request_handler.mm
similarity index 53%
copy from weex_core/Source/core/data_render/vnode/vnode_render_context.cc
copy to weex_core/Source/core/network/ios/default_request_handler.mm
index 3f6c6ed..11f12f2 100644
--- a/weex_core/Source/core/data_render/vnode/vnode_render_context.cc
+++ b/weex_core/Source/core/network/ios/default_request_handler.mm
@@ -16,19 +16,30 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-#include "core/data_render/vnode/vnode_render_context.h"
+#include "core/network/ios/default_request_handler.h"
+#import "WXConvertUtility.h"
+#import "WXSDKManager.h"
 
 namespace weex {
 namespace core {
-namespace data_render {
+namespace network {
+    DefaultRequestHandler::DefaultRequestHandler() {}
 
-VNodeRenderContext::VNodeRenderContext()
-    : page_id_(), root_(nullptr), raw_json_(), script_() {}
+    DefaultRequestHandler::~DefaultRequestHandler() {}
 
-VNodeRenderContext::~VNodeRenderContext() {}
+    void DefaultRequestHandler::Send(const char* instance_id, const char* url, Callback callback) {
+        NSURL* nsURL = [NSURL URLWithString:NSSTRING(url)];
+        [[WXSDKManager bridgeMgr] DownloadJS:nsURL completion:^(NSString *script) {
+            if (!script) {
+                return;
+            }
+            callback([script UTF8String]);
+        }];
+    }
 
-void VNodeRenderContext::Reset() { root_ = nullptr; }
-}  // namespace data_render
-}  // namespace core
-}  // namespace weex
\ No newline at end of file
+    RequestHandler* RequestHandler::CreateDefaultHandler() {
+        return new DefaultRequestHandler();
+    }
+}
+}
+}
diff --git a/weex_core/Source/core/data_render/vnode/vnode_render_context.cc b/weex_core/Source/core/network/request_handler.h
similarity index 62%
copy from weex_core/Source/core/data_render/vnode/vnode_render_context.cc
copy to weex_core/Source/core/network/request_handler.h
index 3f6c6ed..66a4a87 100644
--- a/weex_core/Source/core/data_render/vnode/vnode_render_context.cc
+++ b/weex_core/Source/core/network/request_handler.h
@@ -17,18 +17,26 @@
  * under the License.
  */
 
-#include "core/data_render/vnode/vnode_render_context.h"
+#ifndef CORE_NETWORK_REQUEST_HANDLER_H
+#define CORE_NETWORK_REQUEST_HANDLER_H
+#include <functional>
+#include <memory>
 
 namespace weex {
 namespace core {
-namespace data_render {
+namespace network {
+typedef std::function<void(const std::string&)> Callback;
 
-VNodeRenderContext::VNodeRenderContext()
-    : page_id_(), root_(nullptr), raw_json_(), script_() {}
+class RequestHandler {
+ public:
+  RequestHandler() {}
+  virtual ~RequestHandler() {}
+  virtual void Send(const char* instance_id, const char* url,
+                    Callback callback) = 0;
+  static RequestHandler* CreateDefaultHandler();
+};
 
-VNodeRenderContext::~VNodeRenderContext() {}
-
-void VNodeRenderContext::Reset() { root_ = nullptr; }
-}  // namespace data_render
+}  // namespace network
 }  // namespace core
-}  // namespace weex
\ No newline at end of file
+}  // namespace weex
+#endif  // CORE_NETWORK_REQUEST_HANDLER_H
diff --git a/weex_core/Source/include/WeexApiHeader.h b/weex_core/Source/include/WeexApiHeader.h
index 9470cf4..53b5ef6 100644
--- a/weex_core/Source/include/WeexApiHeader.h
+++ b/weex_core/Source/include/WeexApiHeader.h
@@ -153,6 +153,8 @@ typedef std::unique_ptr<WeexJSResult> (*FuncCallDispatchMessageSync)(
 
 typedef void
 (*FuncOnReceivedResult)(long callback_id, std::unique_ptr<WeexJSResult>& result);
+typedef void
+(*FuncUpdateComponentData)(const char* page_id, const char* cid, const char* json_data);
 
 
 typedef struct FunctionsExposedByCore {
@@ -182,6 +184,7 @@ typedef struct FunctionsExposedByCore {
     FuncCallDIspatchMessage funcCallDIspatchMessage;
     FuncCallDispatchMessageSync funcCallDispatchMessageSync;
     FuncOnReceivedResult  funcOnReceivedResult;
+    FuncUpdateComponentData funcUpdateComponentData;
 } FunctionsExposedByCore;
 
 typedef void (*FuncCallSetJSVersion)(const char* version);
diff --git a/weex_core/release.sh b/weex_core/release.sh
index af143d0..02a0196 100755
--- a/weex_core/release.sh
+++ b/weex_core/release.sh
@@ -1,6 +1,6 @@
 cd ../android
-rm -rf sdk/build/intermediates/bundles/release/jni/*
-./gradlew clean assemble
-cp sdk/build/intermediates/bundles/release/jni/armeabi/libweexcore.so sdk/libs/armeabi/libweexcore.so
-cp sdk/build/intermediates/bundles/release/jni/armeabi-v7a/libweexcore.so sdk/libs/armeabi-v7a/libweexcore.so
-cp sdk/build/intermediates/bundles/release/jni/x86/libweexcore.so sdk/libs/x86/libweexcore.so
+rm -rf sdk/build/intermediates/bundles/default/jni/*
+./gradlew clean assembleRelease
+cp sdk/build/intermediates/bundles/default/jni/armeabi/libweexcore.so sdk/libs/armeabi/libweexcore.so
+cp sdk/build/intermediates/bundles/default/jni/armeabi-v7a/libweexcore.so sdk/libs/armeabi-v7a/libweexcore.so
+cp sdk/build/intermediates/bundles/default/jni/x86/libweexcore.so sdk/libs/x86/libweexcore.so