[iOS] support reactor protocol to render
diff --git a/WeexSDK.podspec b/WeexSDK.podspec
index 37fbc1b..8689ebb 100644
--- a/WeexSDK.podspec
+++ b/WeexSDK.podspec
@@ -107,7 +107,8 @@
                           'weex_core/Source/core/layout/flex_enum.h',
                           'weex_core/Source/core/layout/layout.h',
                           'weex_core/Source/core/layout/style.h',
-                          'weex_core/Source/core/bridge/eagle_bridge.h'
+                          'weex_core/Source/core/bridge/eagle_bridge.h',
+                          'weex_core/Source/core/render/page/reactor_page.h'
 
   s.module_map = 'WeexSDK.modulemap'
 
diff --git a/ios/sdk/WeexSDK.xcodeproj/project.pbxproj b/ios/sdk/WeexSDK.xcodeproj/project.pbxproj
index 470c4ad..d14d0a7 100644
--- a/ios/sdk/WeexSDK.xcodeproj/project.pbxproj
+++ b/ios/sdk/WeexSDK.xcodeproj/project.pbxproj
@@ -575,6 +575,14 @@
 		BD88C14C22F02128004467AA /* render_action_update_richtext_child_style.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BD88C14822F02128004467AA /* render_action_update_richtext_child_style.cpp */; };
 		BD9205FB223651D900EDF93D /* eagle_bridge.h in Headers */ = {isa = PBXBuildFile; fileRef = BD9205F9223651D800EDF93D /* eagle_bridge.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		BD9205FC223651D900EDF93D /* eagle_bridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BD9205FA223651D800EDF93D /* eagle_bridge.cpp */; };
+		BDB112982459D6C2008492F9 /* WXReactorProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = BDB112972459D6C2008492F9 /* WXReactorProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		BDB1129B2459D71E008492F9 /* reactor_page.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BDB112992459D71E008492F9 /* reactor_page.cpp */; };
+		BDB1129C2459D71E008492F9 /* reactor_page.h in Headers */ = {isa = PBXBuildFile; fileRef = BDB1129A2459D71E008492F9 /* reactor_page.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		BDB1129D2459D802008492F9 /* WXReactorProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = BDB112972459D6C2008492F9 /* WXReactorProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		BDB1129E2459D8D3008492F9 /* reactor_page.cpp in Headers */ = {isa = PBXBuildFile; fileRef = BDB112992459D71E008492F9 /* reactor_page.cpp */; };
+		BDB1129F2459D8FC008492F9 /* reactor_page.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BDB112992459D71E008492F9 /* reactor_page.cpp */; };
+		BDB112A02459D90F008492F9 /* reactor_page.h in Headers */ = {isa = PBXBuildFile; fileRef = BDB1129A2459D71E008492F9 /* reactor_page.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		BDBA319B248D0A5200C6EDD0 /* reactor_page.cpp in Headers */ = {isa = PBXBuildFile; fileRef = BDB112992459D71E008492F9 /* reactor_page.cpp */; };
 		BDEEADBA22F2902E0099F1D7 /* time_calculator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BDEEADB822F2902D0099F1D7 /* time_calculator.cpp */; };
 		BDEEADBB22F2902E0099F1D7 /* time_calculator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BDEEADB822F2902D0099F1D7 /* time_calculator.cpp */; };
 		BDEEADBC22F2902E0099F1D7 /* time_calculator.h in Headers */ = {isa = PBXBuildFile; fileRef = BDEEADB922F2902E0099F1D7 /* time_calculator.h */; };
@@ -1331,6 +1339,9 @@
 		BD88C14822F02128004467AA /* render_action_update_richtext_child_style.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = render_action_update_richtext_child_style.cpp; sourceTree = "<group>"; };
 		BD9205F9223651D800EDF93D /* eagle_bridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eagle_bridge.h; sourceTree = "<group>"; };
 		BD9205FA223651D800EDF93D /* eagle_bridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eagle_bridge.cpp; sourceTree = "<group>"; };
+		BDB112972459D6C2008492F9 /* WXReactorProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXReactorProtocol.h; sourceTree = "<group>"; };
+		BDB112992459D71E008492F9 /* reactor_page.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = reactor_page.cpp; sourceTree = "<group>"; };
+		BDB1129A2459D71E008492F9 /* reactor_page.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reactor_page.h; sourceTree = "<group>"; };
 		BDEEADB822F2902D0099F1D7 /* time_calculator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = time_calculator.cpp; sourceTree = "<group>"; };
 		BDEEADB922F2902E0099F1D7 /* time_calculator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = time_calculator.h; sourceTree = "<group>"; };
 		C401945D1E344E8300D19C31 /* WXFloatCompareTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXFloatCompareTests.m; sourceTree = "<group>"; };
@@ -1887,6 +1898,7 @@
 		77D1611C1C02DD3C0010B15B /* Protocol */ = {
 			isa = PBXGroup;
 			children = (
+				BDB112972459D6C2008492F9 /* WXReactorProtocol.h */,
 				D7D6B6E1238E1B1D00BE56DD /* WXDarkSchemeProtocol.h */,
 				33CE19122153444900CF9670 /* WXJSFrameworkLoadProtocol.h */,
 				17036A5220FDE7490029AE3D /* WXApmProtocol.h */,
@@ -2226,6 +2238,8 @@
 		B8D66B372125572F003960BD /* page */ = {
 			isa = PBXGroup;
 			children = (
+				BDB112992459D71E008492F9 /* reactor_page.cpp */,
+				BDB1129A2459D71E008492F9 /* reactor_page.h */,
 				77788B6E2229252C000D5102 /* render_page_base.cpp */,
 				77788B702229252C000D5102 /* render_page_base.h */,
 				77788B6F2229252C000D5102 /* render_page_custom.cpp */,
@@ -2448,6 +2462,8 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				BDB112982459D6C2008492F9 /* WXReactorProtocol.h in Headers */,
+				BDB1129C2459D71E008492F9 /* reactor_page.h in Headers */,
 				77E659F11C0C3612008B8775 /* WXModuleFactory.h in Headers */,
 				F75C591C2313C1FC002FFF94 /* WXStreamModule.h in Headers */,
 				986CEAA723B230C2004166E0 /* WXEaglePlugin.h in Headers */,
@@ -2461,7 +2477,6 @@
 				45E0B4C121CB7B82005D1B3B /* WXConvertUtility.h in Headers */,
 				BD88C13F22F02111004467AA /* render_action_remove_child_from_richtext.h in Headers */,
 				BD9205FB223651D900EDF93D /* eagle_bridge.h in Headers */,
-				BD9205F82236518700EDF93D /* WXDataRenderHandler.h in Headers */,
 				D7D6B6E2238E1B1D00BE56DD /* WXDarkSchemeProtocol.h in Headers */,
 				7715EB6221A69DD9001F1108 /* WXRichText.h in Headers */,
 				B8D66C1B21255730003960BD /* style.h in Headers */,
@@ -2523,6 +2538,7 @@
 				B8D66C6B21255730003960BD /* render_scroller.h in Headers */,
 				B8D66C6921255730003960BD /* render_mask.h in Headers */,
 				C4C30DE91E1B833D00786B6C /* WXComponent+PseudoClassManagement.h in Headers */,
+				BDB1129E2459D8D3008492F9 /* reactor_page.cpp in Headers */,
 				591DD3321D23AD5800BE8709 /* WXErrorView.h in Headers */,
 				B8D66C8D21255730003960BD /* render_creator.h in Headers */,
 				17C74F0B2072145100AB4CAB /* WXAnalyzerCenter+Transfer.h in Headers */,
@@ -2700,6 +2716,8 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				BDB1129D2459D802008492F9 /* WXReactorProtocol.h in Headers */,
+				BDB112A02459D90F008492F9 /* reactor_page.h in Headers */,
 				DCA4461D1EFA5AAA00D0CFA8 /* WXHandlerFactory.h in Headers */,
 				DCA446101EFA5A8500D0CFA8 /* WXBridgeMethod.h in Headers */,
 				DCA4461A1EFA5AA000D0CFA8 /* WXInvocationConfig.h in Headers */,
@@ -2769,6 +2787,7 @@
 				DCA4459F1EFA56EC00D0CFA8 /* WXURLRewriteProtocol.h in Headers */,
 				DCA445A21EFA570100D0CFA8 /* WXScrollerComponent.h in Headers */,
 				B8D66C7621255730003960BD /* render_object.h in Headers */,
+				BDBA319B248D0A5200C6EDD0 /* reactor_page.cpp in Headers */,
 				DCA445B71EFA579200D0CFA8 /* WXImgLoaderProtocol.h in Headers */,
 				1746EA7420E9D253007E55BD /* WXComponent_performance.h in Headers */,
 				B8D66CEB21255B2A003960BD /* WXWebSocketLoader.h in Headers */,
@@ -3208,6 +3227,7 @@
 				744D61111E49979000B624B3 /* WXFooterComponent.m in Sources */,
 				B8D66C0721255730003960BD /* core_environment.cpp in Sources */,
 				745B2D6F1E5A8E1E0092D38A /* WXRecyclerUpdateController.m in Sources */,
+				BDB1129B2459D71E008492F9 /* reactor_page.cpp in Sources */,
 				745B2D6B1E5A8E1E0092D38A /* WXRecyclerComponent.mm in Sources */,
 				B8D66C0D21255730003960BD /* core_side_in_platform.cpp in Sources */,
 				B8D66C5D21255730003960BD /* render_action_appendtree_createfinish.cpp in Sources */,
@@ -3387,6 +3407,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				D77286FF22C9B22C00E1DA7D /* eagle_bridge.cpp in Sources */,
+				BDB1129F2459D8FC008492F9 /* reactor_page.cpp in Sources */,
 				453F376F219A78D700A03F1D /* WXConvertUtility.mm in Sources */,
 				453F376E219A789A00A03F1D /* default_request_handler.mm in Sources */,
 				453F376A219A784F00A03F1D /* http_module.cc in Sources */,
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXCoreBridge.mm b/ios/sdk/WeexSDK/Sources/Bridge/WXCoreBridge.mm
index f232ada..07db550 100644
--- a/ios/sdk/WeexSDK/Sources/Bridge/WXCoreBridge.mm
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXCoreBridge.mm
@@ -1821,9 +1821,9 @@
     return nullptr;
 }
 
-+ (std::vector<std::pair<std::string, std::string>>*)_parseMapValuePairs:(NSDictionary *)data
++ (std::unique_ptr<std::vector<std::pair<std::string, std::string>>>)_parseMapValuePairs:(NSDictionary *)data
 {
-    std::vector<std::pair<std::string, std::string>>* result = new std::vector<std::pair<std::string, std::string>>();
+    __block std::unique_ptr<std::vector<std::pair<std::string, std::string>>> result = std::make_unique<std::vector<std::pair<std::string, std::string>>>();
     [data enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
         ConvertToCString(obj, ^(const char * value) {
             if (value != nullptr) {
@@ -1831,7 +1831,7 @@
             }
         });
     }];
-    return result;
+    return std::move(result);
 }
 
 + (void)callAddElement:(NSString*)pageId parentRef:(NSString*)parentRef data:(NSDictionary*)data index:(int)index
@@ -1877,13 +1877,13 @@
 + (void)callUpdateAttrs:(NSString*)pageId ref:(NSString*)ref data:(NSDictionary*)data
 {
     SetConvertCurrentPage(pageId);
-    WeexCore::RenderManager::GetInstance()->UpdateAttr([pageId UTF8String] ?: "", [ref UTF8String] ?: "", [self _parseMapValuePairs:data]);
+    WeexCore::RenderManager::GetInstance()->UpdateAttr([pageId UTF8String] ?: "", [ref UTF8String] ?: "", [self _parseMapValuePairs:data].get());
 }
 
 + (void)callUpdateStyle:(NSString*)pageId ref:(NSString*)ref data:(NSDictionary*)data
 {
     SetConvertCurrentPage(pageId);
-    WeexCore::RenderManager::GetInstance()->UpdateStyle([pageId UTF8String] ?: "", [ref UTF8String] ?: "", [self _parseMapValuePairs:data]);
+    WeexCore::RenderManager::GetInstance()->UpdateStyle([pageId UTF8String] ?: "", [ref UTF8String] ?: "", [self _parseMapValuePairs:data].get());
 }
 
 + (void)callAddEvent:(NSString*)pageId ref:(NSString*)ref event:(NSString*)event
diff --git a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXJSASTParser.mm b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXJSASTParser.mm
index 2d26ff0..c6a69ef 100644
--- a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXJSASTParser.mm
+++ b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXJSASTParser.mm
@@ -427,7 +427,7 @@
                             
                             // 3 digits are only allowed when string starts
                             // with 0, 1, 2, 3
-                            if (std::string(1, '0123').find(ch) != std::string::npos &&
+                            if (std::string("0123").find(ch) != std::string::npos &&
                                 _index < _length &&
                                 isOctalDigit(_source[_index])) {
                                 code = code * 8 + _source[_index++] - '0';
diff --git a/ios/sdk/WeexSDK/Sources/Events/WXComponent+Events.m b/ios/sdk/WeexSDK/Sources/Events/WXComponent+Events.m
index 6e7e6db..34f0c69 100644
--- a/ios/sdk/WeexSDK/Sources/Events/WXComponent+Events.m
+++ b/ios/sdk/WeexSDK/Sources/Events/WXComponent+Events.m
@@ -416,11 +416,14 @@
         return;
     }
     if (!CGRectEqualToRect(self.view.frame, CGRectZero)) {
+        CGPoint pageLocation = [recognizer locationInView:self.weexInstance.rootView];
         CGRect frame = [self.view.superview convertRect:self.view.frame toView:self.view.window];
         position[@"x"] = @(frame.origin.x/scaleFactor);
         position[@"y"] = @(frame.origin.y/scaleFactor);
         position[@"width"] = @(frame.size.width/scaleFactor);
         position[@"height"] = @(frame.size.height/scaleFactor);
+        position[@"pageX"] = @(pageLocation.x/scaleFactor);
+        position[@"pageY"] = @(pageLocation.y/scaleFactor);
     }
     [self fireEvent:@"click" params:@{@"position":position}];
 }
diff --git a/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.h b/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.h
index 5fc9c54..e5fefd3 100644
--- a/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.h
+++ b/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.h
@@ -252,6 +252,8 @@
 
 - (void)checkJSThread;
 
++ (NSThread *)jsThread;
+
 @end
 
 NS_ASSUME_NONNULL_END
diff --git a/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.m b/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.m
index c5106a2..5c1f455 100644
--- a/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.m
+++ b/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.m
@@ -39,6 +39,7 @@
 #import "WXExceptionUtils.h"
 #import "WXSDKEngine.h"
 #import "WXConfigCenterProtocol.h"
+#import "WXReactorProtocol.h"
 
 @interface WXBridgeManager ()
 
@@ -642,7 +643,16 @@
         WXLogError(@"Event type and component ref should not be nil");
         return;
     }
-    
+    if (instance.useReactor) {
+        id<WXReactorProtocol> reactorHandler = [WXHandlerFactory handlerForProtocol:NSProtocolFromString(@"WXReactorProtocol")];
+        if (reactorHandler) {
+            [reactorHandler fireEvent:instanceId ref:ref event:type args:params?:@{} domChanges:domChanges?:@{}];
+        } else {
+            WXLogError(@"There is no reactor handler");
+        }
+        return;
+    }
+
     NSArray *args = @[ref, type, params?:@{}, domChanges?:@{}];
     if (handlerArguments) {
         NSMutableArray *newArgs = [args mutableCopy];
@@ -706,7 +716,14 @@
             [instance.renderPlugin invokeCallBack:instanceId function:funcId args:strongArgs keepAlive:keepAlive];
         });
     }
-    else {
+    else if (instance.useReactor) {
+        id<WXReactorProtocol> reactorHandler = [WXHandlerFactory handlerForProtocol:NSProtocolFromString(@"WXReactorProtocol")];
+        if (reactorHandler) {
+            [reactorHandler invokeCallBack:instanceId function:funcId args:args];
+        } else {
+            WXLogError(@"There is no reactor handler");
+        }
+    } else {
         WXCallJSMethod *method = [[WXCallJSMethod alloc] initWithModuleName:@"jsBridge" methodName:@"callback" arguments:args instance:instance];
         [self callJsMethod:method];
     }
diff --git a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.h b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.h
index fec4ac6..484172b 100644
--- a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.h
+++ b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.h
@@ -121,6 +121,11 @@
 @property (nonatomic, strong) NSDictionary* containerInfo;
 
 /**
+* Params for Canal
+**/
+@property (nonatomic, strong) NSMutableDictionary* canalParams;
+
+/**
  * Whether this instance is rendered or not. Please MUST not render an instance twice even if you have called destroyInstance.
  **/
 @property (nonatomic, assign, readonly) BOOL isRendered;
@@ -388,6 +393,11 @@
 - (NSURL *)completeURL:(NSString *)url;
 
 /**
+* register jscontext for reactor
+*/
+- (void)registerReactorContext:(JSContext*)context;
+
+/**
  * jsbundle str ,may be nil (weak)
  */
 - (NSString* _Nullable) bundleTemplate;
diff --git a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m
index 4879a57..31a51c8 100644
--- a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m
+++ b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m
@@ -54,6 +54,7 @@
 #import "WXDarkSchemeProtocol.h"
 #import "WXDarkSchemeModule.h"
 #import <WeexSDK/WXEaglePluginManager.h>
+#import "WXReactorProtocol.h"
 
 #define WEEX_RENDER_TYPE_PLATFORM       @"platform"
 
@@ -164,6 +165,8 @@
         _apmInstance = [[WXApmForInstance alloc] init];
                 
         _useBackupJsThread = NO;
+        _useReactor = NO;
+        _canalParams = [NSMutableDictionary dictionary];
 
         [self addObservers];
     }
@@ -339,7 +342,7 @@
         return;
     }
     WXLogInfo(@"pageid: %@ renderWithURL: %@", _instanceId, url.absoluteString);
-    
+
     _renderPlugin = [WXEaglePluginManager renderWithURL:&url];
     if (!_renderPlugin) {
         _renderPlugin = [WXEaglePluginManager renderWithOption:options];
@@ -402,6 +405,21 @@
     }
 }
 
+- (void)registerReactorContext:(JSContext*)context {
+    if (!context) {
+        return;
+    }
+    [WXCoreBridge install];
+    [self.canalParams setObject:context forKey:@"mainJSContext"];
+
+    id<WXReactorProtocol> reactorHandler = [WXHandlerFactory handlerForProtocol:NSProtocolFromString(@"WXReactorProtocol")];
+    if (reactorHandler) {
+        [reactorHandler registerJSContext:self.instanceId];
+    } else {
+        WXLogError(@"There is no reactor handler");
+    }
+}
+
 - (NSString *) bundleTemplate
 {
     return self.mainBundleString;
@@ -597,7 +615,20 @@
         return;
     }
     
-    [[WXSDKManager bridgeMgr] createInstance:self.instanceId template:mainBundleString options:dictionary data:_jsData];
+    if ([dictionary[@"USE_REACTOR"] boolValue]) {
+        id<WXReactorProtocol> reactorHandler = [WXHandlerFactory handlerForProtocol:NSProtocolFromString(@"WXReactorProtocol")];
+        if (reactorHandler) {
+            _useReactor = YES;
+            if (![self.canalParams objectForKey:@"mainJSContext"]) {
+                [reactorHandler registerJSContext:self.instanceId];
+            }
+            [reactorHandler render:self.instanceId source:mainBundleString data:_jsData];
+        } else {
+            WXLogError(@"There is no reactor handler");
+        }
+    } else {
+        [[WXSDKManager bridgeMgr] createInstance:self.instanceId template:mainBundleString options:dictionary data:_jsData];
+    }
     
     WX_MONITOR_PERF_SET(WXPTBundleSize, [mainBundleString lengthOfBytesUsingEncoding:NSUTF8StringEncoding], self);
     
@@ -830,7 +861,15 @@
 
     [WXPrerenderManager removePrerenderTaskforUrl:[self.scriptURL absoluteString]];
     [WXPrerenderManager destroyTask:self.instanceId];
-    if (!self.renderPlugin) {
+
+    if (_useReactor) {
+        id<WXReactorProtocol> reactorHandler = [WXHandlerFactory handlerForProtocol:NSProtocolFromString(@"WXReactorProtocol")];
+        if (reactorHandler) {
+            [reactorHandler unregisterJSContext:self.instanceId];
+        } else {
+            WXLogError(@"There is no reactor handler");
+        }
+    } else if (!self.renderPlugin) {
         [[WXSDKManager bridgeMgr] destroyInstance:self.instanceId];
     }
     
diff --git a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance_private.h b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance_private.h
index 38e5bb2..6ea7e4d 100644
--- a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance_private.h
+++ b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance_private.h
@@ -36,6 +36,8 @@
 @property (nonatomic, strong) NSString *mainBundleString;
 @property (nonatomic, weak) id <WXEaglePlugin> renderPlugin;
 
+@property (nonatomic, assign) BOOL useReactor;
+
 // add monitor information
 @property (nonatomic, strong) NSString *callCreateInstanceContext;
 @property (nonatomic, strong) NSString *createInstanceContextResult;
diff --git a/ios/sdk/WeexSDK/Sources/Protocol/WXReactorProtocol.h b/ios/sdk/WeexSDK/Sources/Protocol/WXReactorProtocol.h
new file mode 100644
index 0000000..4ac03f6
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Protocol/WXReactorProtocol.h
@@ -0,0 +1,64 @@
+/*
+ * 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>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@class JSContext;
+
+@protocol WXReactorProtocol <NSObject>
+
+@required
+
+/**
+Weex should register a JSContext to reactor
+*/
+- (void)registerJSContext:(NSString *)instanceId;
+
+/**
+ Reactor execute js source
+*/
+- (void)render:(NSString *)instanceId source:(NSString*)source data:(NSDictionary* _Nullable)data;
+
+- (void)unregisterJSContext:(NSString *)instanceId;
+
+/**
+ When js call Weex NativeModule, invoke callback function
+ 
+ @param instanceId : weex instance id
+ @param callbackId : callback function id
+ @param args       : args
+*/
+- (void)invokeCallBack:(NSString *)instanceId function:(NSString *)callbackId args:(NSArray * _Nullable)args;
+
+/**
+Native event to js
+ 
+@param instanceId :   instance id
+@param ref        :   node reference
+@param event      :   event type
+@param args       :   parameters in event object
+@param domChanges :  dom value changes, used for two-way data binding
+*/
+- (void)fireEvent:(NSString *)instanceId ref:(NSString *)ref event:(NSString *)event args:(NSDictionary * _Nullable)args domChanges:(NSDictionary * _Nullable)domChanges;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/ios/sdk/WeexSDK/Sources/WeexSDK.h b/ios/sdk/WeexSDK/Sources/WeexSDK.h
index 331ac78..372078a 100644
--- a/ios/sdk/WeexSDK/Sources/WeexSDK.h
+++ b/ios/sdk/WeexSDK/Sources/WeexSDK.h
@@ -24,6 +24,7 @@
 FOUNDATION_EXPORT const unsigned char WeexSDKVersionString[];
 
 #import <WeexSDK/style.h>
+#import <WeexSDK/reactor_page.h>
 #import <WeexSDK/layout.h>
 #import <WeexSDK/flex_enum.h>
 #import <WeexSDK/eagle_bridge.h>
@@ -49,6 +50,7 @@
 #import <WeexSDK/WXResourceLoader.h>
 #import <WeexSDK/WXRefreshComponent.h>
 #import <WeexSDK/WXRecyclerComponent.h>
+#import <WeexSDK/WXReactorProtocol.h>
 #import <WeexSDK/WXPrerenderManager.h>
 #import <WeexSDK/WXPageEventNotifyEvent.h>
 #import <WeexSDK/WXNetworkProtocol.h>
diff --git a/weex_core/Source/core/render/page/reactor_page.cpp b/weex_core/Source/core/render/page/reactor_page.cpp
new file mode 100644
index 0000000..f151dae
--- /dev/null
+++ b/weex_core/Source/core/render/page/reactor_page.cpp
@@ -0,0 +1,127 @@
+/**
+ * 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/render/page/reactor_page.h"
+
+#include "core/render/manager/render_manager.h"
+#include "core/render/page/render_page.h"
+#include "core/render/node/factory/render_creator.h"
+#include "core/manager/weex_core_manager.h"
+
+namespace WeexCore {
+
+void PostTaskOnComponentThread(const std::function<void()>& callback) {
+#if OS_IOS
+     WeexCoreManager::Instance()->getPlatformBridge()->platform_side()->PostTaskOnComponentThread(callback);
+#else
+    callback();
+#endif
+}
+
+void ReactorPage::CreateBody(const std::string& ref,
+                             const std::string& type,
+                             const std::map<std::string, std::string>& styles,
+                             const std::map<std::string, std::string>& attrs,
+                             const std::vector<std::string>& events) {
+    RenderManager::GetInstance()->CreatePage(page_id_, [&] (RenderPage* page_instance) -> RenderObject* {
+#if OS_IOS
+        page_instance->set_before_layout_needed(false); // do not need before and after layout on ios platform
+        page_instance->set_after_layout_needed(false);
+        page_instance->set_platform_layout_needed(true);
+#endif
+        return CreateRenderObject(ref, type, 0, styles, attrs, events, page_instance->reserve_css_styles(), nullptr);
+    });
+    
+}
+
+void ReactorPage::AddElement(const std::string& ref,
+                             const std::string& type,
+                             const std::map<std::string, std::string>& styles,
+                             const std::map<std::string, std::string>& attrs,
+                             const std::vector<std::string>& events,
+                             const std::string parent_ref, int index) {
+    RenderManager::GetInstance()->AddRenderObject(page_id_, parent_ref, index, [&] (RenderPage* page_instance) -> RenderObject* {
+        return CreateRenderObject(ref, type, 0, styles, attrs, events, page_instance->reserve_css_styles(), nullptr);
+     });
+}
+
+void ReactorPage::UpdateStyles(const std::string& ref, std::vector<std::pair<std::string, std::string>> styles) {
+     WeexCore::RenderManager::GetInstance()->UpdateStyle(page_id_, ref, &styles);
+}
+
+void ReactorPage::UpdateAttrs(const std::string& ref, std::vector<std::pair<std::string, std::string>> attrs) {
+     WeexCore::RenderManager::GetInstance()->UpdateAttr(page_id_, ref, &attrs);
+}
+
+void ReactorPage::CreateFinish() {
+    WeexCore::WeexCoreManager::Instance()->script_bridge()->core_side()->CreateFinish(page_id_.c_str());
+}
+
+void ReactorPage::RemoveElement(const std::string& ref) {
+    WeexCore::WeexCoreManager::Instance()->script_bridge()->core_side()->RemoveElement(page_id_.c_str(), ref.c_str());
+}
+
+void ReactorPage::CallNativeModule(const std::string& module,
+                                   const std::string& method,
+                                   const std::string& arguments,
+                                   size_t arguments_length,
+                                   const std::string& options,
+                                   int options_length) {
+  std::unique_ptr<ValueWithType> ptr = WeexCoreManager::Instance()
+      ->getPlatformBridge()
+      ->platform_side()
+      ->CallNativeModule(page_id_.c_str(), module.c_str(), method.c_str(), arguments.c_str(), static_cast<int>(arguments_length), options.c_str(), options_length);
+}
+
+RenderObject* ReactorPage::CreateRenderObject(const std::string& ref,
+                                              const std::string& type,
+                                              unsigned index,
+                                              const std::map<std::string, std::string>& styles,
+                                              const std::map<std::string, std::string>& attrs,
+                                              const std::vector<std::string>& events,
+                                              bool reserve_styles,
+                                              WeexCore::RenderObject* parent) {
+    if (ref.empty() || type.empty()) {
+        return nullptr;
+    }
+
+    RenderObject* render_object = (RenderObject *)RenderCreator::GetInstance()->CreateRender(type, ref);
+    render_object->set_page_id(page_id_);
+    if (parent) {
+        parent->AddRenderObject(index, render_object);
+    }
+
+    //fill attributes, styles and events
+    for (const auto& attr : attrs) {
+        render_object->AddAttr(attr.first, attr.second);
+    }
+    for (const auto& style : styles) {
+        render_object->AddStyle(style.first, style.second, reserve_styles);
+    }
+    for (const auto& event : events) {
+        render_object->AddEvent(event);
+    }
+
+    render_object->ApplyDefaultStyle(reserve_styles);
+    render_object->ApplyDefaultAttr();
+    return render_object;
+}
+
+}  // namespace WeexCore
+
diff --git a/weex_core/Source/core/render/page/reactor_page.h b/weex_core/Source/core/render/page/reactor_page.h
new file mode 100644
index 0000000..577f7e0
--- /dev/null
+++ b/weex_core/Source/core/render/page/reactor_page.h
@@ -0,0 +1,79 @@
+/**
+ * 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.
+ */
+#ifndef CORE_RENDER_PAGE_REACTOR_PAGE_H_
+#define CORE_RENDER_PAGE_REACTOR_PAGE_H_
+
+#if defined __cplusplus
+
+#include <string>
+#include <map>
+#include <functional>
+
+namespace WeexCore {
+
+void PostTaskOnComponentThread(const std::function<void()>& callback);
+
+class RenderObject;
+
+class ReactorPage {
+public:
+    explicit ReactorPage(const std::string& page_id)
+    : page_id_(page_id) {}
+
+    void CreateBody(const std::string& ref,
+                    const std::string& type,
+                    const std::map<std::string, std::string>& styles,
+                    const std::map<std::string, std::string>& attrs,
+                    const std::vector<std::string>& events);
+
+    void AddElement(const std::string& ref,
+                    const std::string& type,
+                    const std::map<std::string, std::string>& styles,
+                    const std::map<std::string, std::string>& attrs,
+                    const std::vector<std::string>& events,
+                    const std::string parent_ref, int index=-1);
+
+    void UpdateStyles(const std::string& ref, std::vector<std::pair<std::string, std::string>> styles);
+
+    void UpdateAttrs(const std::string& ref, std::vector<std::pair<std::string, std::string>> attrs);
+
+    void RemoveElement(const std::string& ref);
+
+    void CreateFinish();
+
+    const std::string& page_id() const {return page_id_;}
+
+    void CallNativeModule(const std::string& module,
+                          const std::string& method,
+                          const std::string& arguments,
+                          size_t arguments_length,
+                          const std::string& options,
+                          int options_length);
+
+private:
+    RenderObject* CreateRenderObject(const std::string& ref, const std::string& type, unsigned index, const std::map<std::string, std::string>& styles, const std::map<std::string, std::string>& attrs, const std::vector<std::string>& events, bool reserve_styles, WeexCore::RenderObject* parent);
+
+    const std::string page_id_;
+};
+
+}  // namespace WeexCore
+
+#endif
+
+#endif  // CORE_RENDER_PAGE_REACTOR_PAGE_H_
diff --git a/weex_core/Source/core/render/page/render_page.cpp b/weex_core/Source/core/render/page/render_page.cpp
index 79a3644..cb29d5c 100755
--- a/weex_core/Source/core/render/page/render_page.cpp
+++ b/weex_core/Source/core/render/page/render_page.cpp
@@ -338,8 +338,6 @@
   if (src != nullptr) {
     src->clear();
     src->shrink_to_fit();
-    delete src;
-    src = nullptr;
   }
 
   if (style != nullptr) {
@@ -395,8 +393,6 @@
   if (attrs != nullptr) {
     attrs->clear();
     attrs->shrink_to_fit();
-    delete attrs;
-    attrs = nullptr;
   }
 
   return true;