You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@weex.apache.org by ji...@apache.org on 2017/01/24 08:18:33 UTC

[18/50] [abbrv] incubator-weex git commit: + [ios] iOS init.

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.h b/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.h
new file mode 100644
index 0000000..1ad5fcf
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.h
@@ -0,0 +1,91 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import <Foundation/Foundation.h>
+
+@class WXBridgeMethod;
+
+@interface WXBridgeContext : NSObject
+
+/**
+ *  Create Instance Method
+ *  @param instance  :   instance id
+ *  @param template  :   template data
+ *  @param options   :   parameters
+ *  @param data      :   external data
+ **/
+- (void)createInstance:(NSString *)instance
+              template:(NSString *)temp
+               options:(NSDictionary *)options
+                  data:(id)data;
+
+/**
+ *  Destroy Instance Method
+ *  @param instance  :   instance id
+ **/
+- (void)destroyInstance:(NSString *)instance;
+
+/**
+ *  Refresh Instance Method
+ *  @param instance  :   instance id
+ *  @param data      :   external data
+ **/
+- (void)refreshInstance:(NSString *)instance
+                   data:(id)data;
+
+/**
+ *  Update Instacne State Method
+ *  @param instance  :   instance id
+ *  @param data      :   parameters
+ **/
+- (void)updateState:(NSString *)instance
+               data:(id)data;
+
+/**
+ *  Execute JSFramework Script
+ *  @param script    :   script code
+ **/
+- (void)executeJsFramework:(NSString *)script;
+
+/**
+ *  Execute JS Method
+ *  @param method    :   object of bridge method
+ **/
+- (void)executeJsMethod:(WXBridgeMethod *)method;
+
+/**
+ *  Register Modules Method
+ *  @param modules   :   module list
+ **/
+- (void)registerModules:(NSDictionary *)modules;
+
+/**
+ *  Register Components Method
+ *  @param components:   component list
+ **/
+- (void)registerComponents:(NSArray *)components;
+
+/**
+ *  Connect To WebSocket
+ *  @param url       :   url to connect
+ **/
+- (void)connectToWebSocket:(NSURL *)url;
+
+/**
+ *  Log To WebSocket
+ *  @param flag      :   the tag to indentify
+ *  @param message   :   message to output
+ **/
+- (void)logToWebSocket:(NSString *)flag message:(NSString *)message;
+
+/**
+ *  Reset Environment
+ **/
+- (void)resetEnvironment;
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m b/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
new file mode 100644
index 0000000..ced9330
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
@@ -0,0 +1,372 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXBridgeContext.h"
+#import "WXBridgeProtocol.h"
+#import "WXJSCoreBridge.h"
+#import "WXWebSocketBridge.h"
+#import "WXLog.h"
+#import "WXUtility.h"
+#import "WXBridgeMethod.h"
+#import "WXModuleFactory.h"
+#import "WXModuleProtocol.h"
+#import "WXUtility.h"
+#import "WXSDKError.h"
+#import "WXAssert.h"
+#import "WXSDKManager.h"
+
+@interface WXBridgeContext ()
+
+@property (nonatomic, strong) id<WXBridgeProtocol>  jsBridge;
+@property (nonatomic, strong) WXWebSocketBridge *socketBridge;
+@property (nonatomic, assign) BOOL  debugJS;
+//store the methods which will be executed from native to js
+@property (nonatomic, strong) NSMutableDictionary   *sendQueue;
+//the instance stack
+@property (nonatomic, strong) NSMutableArray    *insStack;
+//identify if the JSFramework has been loaded
+@property (nonatomic) BOOL frameworkLoadFinished;
+//store some methods temporarily before JSFramework is loaded
+@property (nonatomic, strong) NSMutableArray *methodQueue;
+
+@end
+
+@implementation WXBridgeContext
+
+- (instancetype) init
+{
+    self = [super init];
+    if (self) {
+        _methodQueue = [NSMutableArray new];
+        _frameworkLoadFinished = NO;
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jsError:) name:WX_JS_ERROR_NOTIFICATION_NAME object:nil];
+    }
+    return self;
+}
+
+- (void)dealloc
+{
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:WX_JS_ERROR_NOTIFICATION_NAME object:nil];
+}
+
+- (void)jsError:(NSNotification *)note
+{
+    NSString *errorMessage = @"";
+    if (note.userInfo) {
+        errorMessage = note.userInfo[@"message"];
+    }
+    
+    NSURL *url;
+    if (self.insStack.count > 0) {
+        WXSDKInstance *topInstance = [WXSDKManager instanceForID:[self.insStack firstObject]];
+        url = topInstance.scriptURL;
+    }
+    
+    [WXSDKError monitorAlarm:NO errorCode:WX_ERR_JS_EXECUTE errorMessage:errorMessage withURL:url];
+}
+
+- (id<WXBridgeProtocol>)jsBridge
+{
+    WXAssertBridgeThread();
+    
+    Class bridgeClass = _debugJS ? [WXWebSocketBridge class] : [WXJSCoreBridge class];
+    
+    if (_jsBridge && [_jsBridge isKindOfClass:bridgeClass]) {
+        return _jsBridge;
+    }
+    
+    if (_jsBridge) {
+        [_methodQueue removeAllObjects];
+        _frameworkLoadFinished = NO;
+    }
+    
+    _jsBridge = _debugJS ? self.socketBridge : [[WXJSCoreBridge alloc] init];
+     __weak typeof(self) weakSelf = self;
+    [_jsBridge registerCallNative:^(NSString *instance, NSArray *tasks, NSString *callback) {
+        [weakSelf invokeNative:instance tasks:tasks callback:callback];
+    }];
+    
+    return _jsBridge;
+}
+
+- (NSMutableArray *)insStack
+{
+    WXAssertBridgeThread();
+
+    if (_insStack) return _insStack;
+
+    _insStack = [NSMutableArray array];
+    
+    return _insStack;
+}
+
+- (NSMutableDictionary *)sendQueue
+{
+    WXAssertBridgeThread();
+    
+    if (_sendQueue) return _sendQueue;
+    
+    _sendQueue = [NSMutableDictionary dictionary];
+    
+    return _sendQueue;
+}
+
+#pragma mark JS Bridge Management
+
+- (void)invokeNative:(NSString *)instance tasks:(NSArray *)tasks callback:(NSString *)callback
+{
+    WXAssertBridgeThread();
+    
+    if (!instance || !tasks) {
+        [WXSDKError monitorAlarm:NO errorCode:WX_ERR_JSFUNC_PARAM msg:@"JS call Native params error !"];
+        return;
+    }
+    [WXSDKError monitorAlarm:YES errorCode:WX_ERR_JSFUNC_PARAM msg:@""];
+    
+    for (NSDictionary *task in tasks) {
+        WXBridgeMethod *method = [[WXBridgeMethod alloc] initWihData:task];
+        method.instance = instance;
+        [[WXSDKManager moduleMgr] dispatchMethod:method];
+    }
+    
+    NSMutableArray *sendQueue = [self.sendQueue valueForKey:instance];
+    if (!sendQueue) {
+        WXLogError(@"No send queue for instance:%@", instance);
+        return;
+    }
+    
+    if (callback && ![callback isEqualToString:@"-1"]) {
+        WXBridgeMethod *method = [self _methodWithCallback:callback];
+        method.instance = instance;
+        [sendQueue addObject:method];
+    }
+    
+    [self performSelector:@selector(_sendQueueLoop) withObject:nil];
+}
+
+- (void)createInstance:(NSString *)instance
+              template:(NSString *)temp
+               options:(NSDictionary *)options
+                  data:(id)data
+{
+    WXAssertBridgeThread();
+    WXAssertParam(instance);
+    
+    if (![self.insStack containsObject:instance]) {
+        if ([options[@"RENDER_IN_ORDER"] boolValue]) {
+            [self.insStack addObject:instance];
+        } else {
+            [self.insStack insertObject:instance atIndex:0];
+        }
+    }
+    
+    //create a sendQueue bind to the current instance
+    NSMutableArray *sendQueue = [NSMutableArray array];
+    [self.sendQueue setValue:sendQueue forKey:instance];
+    
+    NSArray *args = nil;
+    if (data){
+        args = @[instance, temp, options, data];
+    } else {
+        args = @[instance, temp, options];
+    }
+    
+    WXSDKInstance *sdkInstance = [WXSDKManager instanceForID:instance] ;
+    [WXBridgeContext _timeSince:^() {
+        [self callJSMethod:@"createInstance" args:args];
+        WXLogInfo(@"CreateInstance Finish...%f", -[sdkInstance.renderStartDate timeIntervalSinceNow]);
+    } endBlock:^(NSTimeInterval time) {
+        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+            sdkInstance.communicateTime = time;
+        });
+    }];
+}
+
+- (void)destroyInstance:(NSString *)instance
+{
+    WXAssertBridgeThread();
+    WXAssertParam(instance);
+    
+    //remove instance from stack
+    if([self.insStack containsObject:instance]){
+        [self.insStack removeObject:instance];
+    }
+
+    if(self.sendQueue[instance]){
+        [self.sendQueue removeObjectForKey:instance];
+    }
+    
+    [self callJSMethod:@"destroyInstance" args:@[instance]];
+}
+
+- (void)refreshInstance:(NSString *)instance
+                   data:(id)data
+{
+    WXAssertBridgeThread();
+    WXAssertParam(instance);
+    
+    [self callJSMethod:@"refreshInstance" args:@[instance, data]];
+}
+
+- (void)updateState:(NSString *)instance data:(id)data
+{
+    WXAssertBridgeThread();
+    WXAssertParam(instance);
+    
+    //[self.jsBridge callJSMethod:@"updateState" args:@[instance, data]];
+}
+
+- (void)executeJsFramework:(NSString *)script
+{
+    WXAssertBridgeThread();
+    WXAssertParam(script);
+    
+    __weak __typeof__(self) weakSelf = self;
+    [WXBridgeContext _timeSince:^() {
+        WXLogVerbose(@"JSFramework starts executing...");
+        [self.jsBridge executeJSFramework:script];
+        WXLogVerbose(@"JSFramework ends executing...");
+        if ([self.jsBridge exception]) {
+            [WXSDKError monitorAlarm:NO errorCode:WX_ERR_LOAD_JSLIB msg:@"JSFramework executes error !"];
+        }
+        else {
+            [WXSDKError monitorAlarm:YES errorCode:WX_ERR_LOAD_JSLIB msg:@""];
+            
+            //the JSFramework has been load successfully.
+            weakSelf.frameworkLoadFinished = YES;
+            
+            //execute methods which has been stored in methodQueue temporarily.
+            for (NSDictionary *method in _methodQueue) {
+                [self callJSMethod:method[@"method"] args:method[@"args"]];
+            }
+            [_methodQueue removeAllObjects];
+        }
+    } endBlock:^(NSTimeInterval time) {
+        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+            JSLibInitTime = time;
+        });
+    }];
+}
+
+- (void)executeJsMethod:(WXBridgeMethod *)method
+{
+    WXAssertBridgeThread();
+    
+    if (!method.instance) {
+        WXLogError(@"Instance doesn't exist!");
+        return;
+    }
+    
+    NSMutableArray *sendQueue = self.sendQueue[method.instance];
+    if (!sendQueue) {
+        WXLogInfo(@"No send queue for instance:%@, may it has been destroyed so method:%@ is ignored", method.instance, method.method);
+        return;
+    }
+    
+    [sendQueue addObject:method];
+    [self performSelector:@selector(_sendQueueLoop) withObject:nil];
+}
+
+- (void)registerModules:(NSDictionary *)modules
+{
+    WXAssertBridgeThread();
+    
+    if(!modules) return;
+    
+    [self callJSMethod:@"registerModules" args:@[modules]];
+}
+
+- (void)registerComponents:(NSArray *)components
+{
+    WXAssertBridgeThread();
+    
+    if(!components) return;
+    
+    [self callJSMethod:@"registerComponents" args:@[components]];
+}
+
+- (void)callJSMethod:(NSString *)method args:(NSArray *)args
+{
+    if (self.frameworkLoadFinished) {
+        [self.jsBridge callJSMethod:method args:args];
+    }
+    else {
+        [_methodQueue addObject:@{@"method":method, @"args":args}];
+    }
+}
+
+- (void)resetEnvironment
+{
+    [_jsBridge resetEnvironment];
+}
+
+#pragma mark JS Debug Management
+
+- (void)connectToWebSocket:(NSURL *)url
+{
+    _socketBridge = [[WXWebSocketBridge alloc] initWithURL:url];
+}
+
+- (void)logToWebSocket:(NSString *)flag message:(NSString *)message
+{
+    [_socketBridge callJSMethod:@"__logger" args:@[flag, message]];
+}
+
+#pragma mark Private Mehtods
+
+- (WXBridgeMethod *)_methodWithCallback:(NSString *)callback
+{
+    WXAssertBridgeThread();
+    
+    if (!callback) return nil;
+    
+    NSDictionary *method = @{@"module":@"jsBridge", @"method":@"callback", @"args":@[callback]};
+    
+    return [[WXBridgeMethod alloc] initWihData:method];
+}
+
+- (void)_sendQueueLoop
+{
+    WXAssertBridgeThread();
+    
+    BOOL hasTask = NO;
+    NSMutableArray *methods = [NSMutableArray array];
+    NSString *execIns = nil;
+    
+    for (NSString *instance in self.insStack) {
+        NSMutableArray *sendQueue = self.sendQueue[instance];
+        if(sendQueue.count > 0){
+            hasTask = YES;
+            for(WXBridgeMethod *method in sendQueue){
+                [methods addObject:[method dataDesc]];
+            }
+            [sendQueue removeAllObjects];
+            execIns = instance;
+            break;
+        }
+    }
+    
+    if ([methods count] > 0 && execIns) {
+        [self callJSMethod:@"callJS" args:@[execIns, methods]];
+    }
+    
+    if (hasTask) {
+        [self performSelector:@selector(_sendQueueLoop) withObject:nil];
+    }
+}
+
++ (void)_timeSince:(void(^)())startBlock endBlock:(void(^)(NSTimeInterval))endBlock
+{
+    NSDate *startDate = [NSDate new];
+    startBlock();
+    NSDate *endDate = [NSDate new];
+    NSTimeInterval time = [endDate timeIntervalSinceDate:startDate];
+    endBlock(time);
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.h b/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.h
new file mode 100644
index 0000000..b3c604c
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.h
@@ -0,0 +1,13 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXBridgeProtocol.h"
+
+@interface WXJSCoreBridge : NSObject <WXBridgeProtocol>
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.m b/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.m
new file mode 100644
index 0000000..0d9a73a
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXJSCoreBridge.m
@@ -0,0 +1,133 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXJSCoreBridge.h"
+#import "WXDefine.h"
+#import "WXAssert.h"
+#import "WXLog.h"
+#import "WXUtility.h"
+#import "WXSDKEngine.h"
+#import "WXSDKError.h"
+#import <sys/utsname.h>
+#import <JavaScriptCore/JavaScriptCore.h>
+
+@interface WXJSCoreBridge ()
+
+@property (nonatomic, strong)  JSContext *jsContext;
+
+@end
+
+@implementation WXJSCoreBridge
+
+- (instancetype)init
+{
+    self = [super init];
+    
+    if(self){
+        _jsContext = [[JSContext alloc] init];
+        
+        __weak typeof(self) weakSelf = self;
+        
+        NSDictionary *data = [WXUtility getEnvironment];
+        _jsContext[@"WXEnvironment"] = data;
+        
+        _jsContext[@"setTimeout"] = ^(JSValue* function, JSValue* timeout) {
+            [weakSelf performSelector: @selector(triggerTimeout:) withObject:^() {
+                [function callWithArguments:@[]];
+            } afterDelay:[timeout toDouble] / 1000];
+        };
+
+        _jsContext[@"nativeLog"] = ^() {
+            static NSDictionary *levelMap;
+            static dispatch_once_t onceToken;
+            dispatch_once(&onceToken, ^{
+                levelMap = @{
+                             @"__ERROR":@(WXLogFlagError),
+                             @"__WARN": @(WXLogFlagWarning),
+                             @"__INFO": @(WXLogFlagInfo),
+                             @"__DEBUG": @(WXLogFlagDebug),
+                             @"__VERBOSE": @(WXLogFlagVerbose)
+                             };
+            });
+            
+            NSMutableString *string = [NSMutableString string];
+            [string appendString:@"jsLog: "];
+            NSArray *args = [JSContext currentArguments];
+            
+            [args enumerateObjectsUsingBlock:^(JSValue *jsVal, NSUInteger idx, BOOL *stop) {
+                if (idx == args.count - 1) {
+                    NSNumber *flag = levelMap[[jsVal toString]];
+                    if (flag) {
+                        WX_LOG([flag unsignedIntegerValue], @"%@", string);
+                    } else {
+                        [string appendFormat:@"%@ ", jsVal];
+                        WXLogInfo(@"%@", string);
+                    }
+                }
+                [string appendFormat:@"%@ ", jsVal ];
+            }];
+        };
+        
+        _jsContext.exceptionHandler = ^(JSContext *context, JSValue *exception){
+            context.exception = exception;
+            NSString *message = [NSString stringWithFormat:@"[%@:%@:%@] %@\n%@", exception[@"sourceURL"], exception[@"line"], exception[@"column"], exception, [exception[@"stack"] toObject]];
+            
+            [[NSNotificationCenter defaultCenter] postNotificationName:WX_JS_ERROR_NOTIFICATION_NAME object:weakSelf userInfo:message ? @{@"message":message} : nil];
+        };
+    }
+    return self;
+}
+
+#pragma mark - WXBridgeProtocol
+
+- (void)executeJSFramework:(NSString *)frameworkScript
+{
+    WXAssertParam(frameworkScript);
+    
+    [_jsContext evaluateScript:frameworkScript];
+}
+
+- (void)callJSMethod:(NSString *)method args:(NSArray *)args
+{
+    WXLogVerbose(@"Calling JS... method:%@, args:%@", method, args);
+    
+    [[_jsContext globalObject] invokeMethod:method withArguments:args];
+}
+
+- (void)registerCallNative:(WXJSCallNative)callNative
+{
+    void (^callNativeBlock)(JSValue *, JSValue *, JSValue *) = ^(JSValue *instance, JSValue *tasks, JSValue *callback){
+        NSString *instanceId = [instance toString];
+        NSArray *tasksArray = [tasks toArray];
+        NSString *callbackId = [callback toString];
+        WXLogVerbose(@"Calling native... instance:%@, tasks:%@, callback:%@", instanceId, tasksArray, callbackId);
+        callNative(instanceId, tasksArray, callbackId);
+    };
+    
+    _jsContext[@"callNative"] = callNativeBlock;
+}
+
+- (JSValue*)exception
+{
+    return _jsContext.exception;
+}
+
+- (void)resetEnvironment
+{
+    NSDictionary *data = [WXUtility getEnvironment];
+    _jsContext[@"WXEnvironment"] = data;
+}
+
+#pragma mark - Private
+
+- (void)triggerTimeout:(void(^)())block
+{
+    block();
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Bridge/WXWebSocketBridge.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXWebSocketBridge.h b/ios/sdk/WeexSDK/Sources/Bridge/WXWebSocketBridge.h
new file mode 100644
index 0000000..116c3c4
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXWebSocketBridge.h
@@ -0,0 +1,15 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXBridgeProtocol.h"
+
+@interface WXWebSocketBridge : NSObject <WXBridgeProtocol>
+
+- (instancetype)initWithURL:(NSURL *) URL;
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Bridge/WXWebSocketBridge.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXWebSocketBridge.m b/ios/sdk/WeexSDK/Sources/Bridge/WXWebSocketBridge.m
new file mode 100644
index 0000000..2059909
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXWebSocketBridge.m
@@ -0,0 +1,203 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXWebSocketBridge.h"
+#import "SRWebSocket.h"
+#import "WXSDKManager.h"
+#import "WXUtility.h"
+#import "WXLog.h"
+
+/**
+ * call format:
+ * {
+ *   id:1234,
+ *   method:(__logger/__hotReload/__inspector/evalFramework...),
+ *   arguments:[arg1,arg2,..],
+ * }
+ *
+ * callback format:
+ * {
+ *   callbackID:1234,(same as call id)
+ *   result:{a:1,b:2}
+ * }
+ */
+@interface WXWebSocketBridge()<SRWebSocketDelegate>
+
+@end
+
+@implementation WXWebSocketBridge
+{
+    BOOL    _isConnect;
+    SRWebSocket *_webSocket;
+    NSMutableArray  *_msgAry;
+    WXJSCallNative  _nativeCallBlock;
+    NSThread    *_curThread;
+}
+
+- (void)dealloc
+{
+    _nativeCallBlock = nil;
+    [self _disconnect];
+}
+
+- (instancetype)initWithURL:(NSURL *) URL
+{
+    self = [super init];
+    
+    _isConnect = NO;
+    _curThread = [NSThread currentThread];
+
+    [self _connect:URL];
+    
+    return self;
+}
+
+- (void)_initEnvironment
+{
+    [self callJSMethod:@"setEnvironment" args:@[[WXUtility getEnvironment]]];
+}
+
+- (void)_disconnect
+{
+    _msgAry = nil;
+    _isConnect = NO;
+    _webSocket.delegate = nil;
+    [_webSocket close];
+    _webSocket = nil;
+}
+
+- (void)_connect:(NSURL *)URL
+{
+    _msgAry = nil;
+    _msgAry = [NSMutableArray array];
+    _webSocket.delegate = nil;
+    [_webSocket close];
+    
+    _webSocket = [[SRWebSocket alloc] initWithURLRequest:[NSURLRequest requestWithURL:URL]];
+    _webSocket.delegate = self;
+    
+    [_webSocket open];
+}
+
+-(void)_executionMsgAry
+{
+    if (!_isConnect) return;
+    
+    for (NSString *msg in _msgAry) {
+        [_webSocket send:msg];
+    }
+    [_msgAry removeAllObjects];
+}
+
+-(void)_evaluateNative:(NSString *)data
+{
+    NSDictionary *dict = [WXUtility objectFromJSON:data];
+    NSString *method = [dict objectForKey:@"method"];
+    NSArray *args = [dict objectForKey:@"arguments"];
+    
+    if ([method isEqualToString:@"callNative"]) {
+        // call native
+        NSString *instanceId = args[0];
+        NSArray *methods = args[1];
+        NSString *callbackId = args[2];
+        
+        // params parse
+        if(!methods || methods.count <= 0){
+            return;
+        }
+        //call native
+        WXLogVerbose(@"Calling native... instancdId:%@, methods:%@, callbackId:%@", instanceId, [WXUtility JSONString:methods], callbackId);
+        _nativeCallBlock(instanceId, methods, callbackId);
+    } else if ([method isEqualToString:@"setLogLevel"]) {
+        NSString *levelString = [args firstObject];
+        [WXLog setLogLevelString:levelString];
+    }
+}
+
+#pragma mark - WXBridgeProtocol
+
+- (void)executeJSFramework:(NSString *)frameworkScript
+{
+    [self callJSMethod:@"evalFramework" args:@[frameworkScript]];
+}
+
+- (void)callJSMethod:(NSString *)method args:(NSArray *)args
+{
+    if (![method isEqualToString:@"__logger"]) {
+        // prevent recursion
+        WXLogVerbose(@"Calling JS... method:%@, args:%@", method, [WXUtility JSONString:args]);
+    }
+    
+    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
+    [dict setObject:method forKey:@"method"];
+    [dict setObject:args forKey:@"arguments"];
+    
+    [_msgAry addObject:[WXUtility JSONString:dict]];
+    [self _executionMsgAry];
+}
+
+- (void)registerCallNative:(WXJSCallNative)callNative
+{
+    _nativeCallBlock = callNative;
+}
+
+- (JSValue*) exception
+{
+    return nil;
+}
+
+- (void)resetEnvironment
+{
+    [self _initEnvironment];
+}
+
+- (void)executeBridgeThead:(dispatch_block_t)block
+{
+    if([NSThread currentThread] == _curThread){
+        block();
+    } else {
+        [self performSelector:@selector(executeBridgeThead:)
+                     onThread:_curThread
+                   withObject:[block copy]
+                waitUntilDone:NO];
+    }
+}
+
+#pragma mark - SRWebSocketDelegate
+
+- (void)webSocketDidOpen:(SRWebSocket *)webSocket;
+{
+    WXLogWarning(@"Websocket Connected:%@", webSocket.url);
+    _isConnect = YES;
+    [self _initEnvironment];
+    __weak typeof(self) weakSelf = self;
+    [self executeBridgeThead:^() {
+        [weakSelf _executionMsgAry];
+    }];
+}
+
+- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error;
+{
+    WXLogError(@":( Websocket Failed With Error %@", error);
+}
+
+- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message;
+{
+    __weak typeof(self) weakSelf = self;
+    [self executeBridgeThead:^() {
+        [weakSelf _evaluateNative:message];
+    }];
+}
+
+- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean
+{
+    WXLogInfo(@"Websocket closed with code: %ld, reason:%@, wasClean: %d", (long)code, reason, wasClean);
+    _isConnect = NO;
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXAComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXAComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXAComponent.h
new file mode 100644
index 0000000..5ebf7a0
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXAComponent.h
@@ -0,0 +1,13 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXComponent.h"
+
+@interface WXAComponent : WXComponent <UIGestureRecognizerDelegate>
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXAComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXAComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXAComponent.m
new file mode 100644
index 0000000..c916b0d
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXAComponent.m
@@ -0,0 +1,75 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXAComponent.h"
+#import "WXNavigationProtocol.h"
+#import "WXHandlerFactory.h"
+#import "WXLog.h"
+#import "WXComponent+Events.h"
+
+@interface WXAComponent()
+
+@property (nonatomic, strong) UITapGestureRecognizer *tap;
+@property (nonatomic, strong) NSString *href;
+
+@end
+
+@implementation WXAComponent
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
+{
+    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
+    if (self) {
+        _tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(openURL)];
+        _tap.delegate = self;
+        if (attributes[@"href"]) {
+            _href = attributes[@"href"];
+        }
+    }
+    return self;
+}
+
+- (void)viewDidLoad
+{
+    [self.view addGestureRecognizer:_tap];
+}
+
+- (void)openURL
+{
+    if (_href && [_href length] > 0) {
+        id<WXNavigationProtocol> navigationHandler = [WXHandlerFactory handlerForProtocol:@protocol(WXNavigationProtocol)];
+        if ([navigationHandler respondsToSelector:@selector(pushViewControllerWithParam:
+                                                            completion:
+                                                            withContainer:)]) {
+            __weak typeof(self) weexSelf = self;
+            [navigationHandler pushViewControllerWithParam:@{@"url":_href} completion:^(NSString *code, NSDictionary *responseData) {
+                WXLogVerbose(@"Push success -> %@", weexSelf.href);
+            } withContainer:self.weexInstance.viewController];
+        } else {
+            WXLogError(@"Event handler of class %@ does not respond to pushViewControllerWithParam", NSStringFromClass([navigationHandler class]));
+        }
+    }
+}
+
+- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
+{
+    if (gestureRecognizer == _tap) return YES;
+    
+    if (otherGestureRecognizer == _tap) return YES;
+    
+    return [super gestureRecognizer:gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:otherGestureRecognizer];
+}
+
+- (void)updateAttributes:(NSDictionary *)attributes
+{
+    if (attributes[@""]) {
+        _href = attributes[@"href"];
+    }
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.h
new file mode 100644
index 0000000..d016117
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.h
@@ -0,0 +1,18 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXComponent.h"
+@class WXListComponent;
+
+@interface WXCellComponent : WXComponent
+
+@property (nonatomic, strong) NSIndexPath *indexPath;
+@property (nonatomic, strong) NSString *scope;
+@property (nonatomic, weak) WXListComponent *list;
+
+@end
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.m
new file mode 100644
index 0000000..02a7e84
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.m
@@ -0,0 +1,93 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXSDKInstance.h"
+#import "WXLog.h"
+#import "WXCellComponent.h"
+#import "WXListComponent.h"
+#import "WXComponent_internal.h"
+
+@implementation WXCellComponent
+{
+    NSIndexPath *_indexPathBeforeMove;
+}
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
+{
+    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
+    
+    if (self) {
+        _async = YES;
+        _lazyCreateView = YES;
+    }
+    
+    return self;
+}
+
+- (void)dealloc
+{
+    
+}
+
+- (void)layoutDidFinish
+{
+    [self.list cellDidLayout:self];
+}
+
+- (WXDisplayCompeletionBlock)displayCompeletionBlock
+{
+    return ^(CALayer *layer, BOOL finished) {
+        if ([super displayCompeletionBlock]) {
+            [super displayCompeletionBlock](layer, finished);
+            [self.list cellDidRendered:self];
+        }
+    };
+}
+
+- (void)_moveToSupercomponent:(WXComponent *)newSupercomponent atIndex:(NSUInteger)index
+{
+    _indexPathBeforeMove = self.indexPath;
+    [super _moveToSupercomponent:newSupercomponent atIndex:index];
+}
+
+- (void)moveToSuperview:(WXComponent *)newSupercomponent atIndex:(NSUInteger)index
+{
+    if (newSupercomponent == self.list) {
+        [self.list cell:self didMoveFromIndexPath:_indexPathBeforeMove toIndexPath:_indexPath];
+    } else {
+        [super moveToSuperview:newSupercomponent atIndex:index];
+    }
+}
+
+- (void)_removeFromSupercomponent
+{
+    [super _removeFromSupercomponent];
+    
+    [self.list cellWillRemove:self];
+}
+
+- (void)removeFromSuperview
+{
+    [self.list cellDidRemove:self];
+}
+
+- (void)_calculateFrameWithSuperAbsolutePosition:(CGPoint)superAbsolutePosition gatherDirtyComponents:(NSMutableSet<WXComponent *> *)dirtyComponents
+{
+    if (isUndefined(self.cssNode->style.dimensions[CSS_WIDTH]) && self.list) {
+        self.cssNode->style.dimensions[CSS_WIDTH] = self.list.scrollerCSSNode->style.dimensions[CSS_WIDTH];
+    }
+    
+    if ([self needsLayout]) {
+        layoutNode(self.cssNode, CSS_UNDEFINED, CSS_UNDEFINED, CSS_DIRECTION_INHERIT);
+//        print_css_node(self.cssNode, CSS_PRINT_LAYOUT | CSS_PRINT_STYLE | CSS_PRINT_CHILDREN);
+    }
+    
+    [super _calculateFrameWithSuperAbsolutePosition:superAbsolutePosition gatherDirtyComponents:dirtyComponents];
+}
+@end
+

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h b/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h
new file mode 100644
index 0000000..4d1ecdb
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h
@@ -0,0 +1,163 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXScrollerProtocol.h"
+#import "WXComponent.h"
+#import "WXConvert.h"
+@class WXTouchGestureRecognizer;
+@class WXThreadSafeCounter;
+
+
+/**
+ * The following variables and methods are used in Weex INTERNAL logic.
+ * @warning These variables and methods must never be called or overridden.
+ */
+@interface WXComponent ()
+{
+@package
+    NSString *_type;
+    /**
+     *  Layout
+     */
+    css_node_t *_cssNode;
+    BOOL _isLayoutDirty;
+    CGRect _calculatedFrame;
+    CGPoint _absolutePosition;
+    WXPositionType _positionType;
+    
+    /**
+     *  View
+     */
+    UIColor *_backgroundColor;
+    WXClipType _clipToBounds;
+    UIView *_view;
+    CGFloat _opacity;
+    WXVisibility  _visibility;
+    
+    /**
+     *  Events
+     */
+    BOOL _appearEvent;
+    BOOL _disappearEvent;
+    UITapGestureRecognizer *_tapGesture;
+    NSMutableArray *_swipeGestures;
+    UILongPressGestureRecognizer *_longPressGesture;
+    UIPanGestureRecognizer *_panGesture;
+    BOOL _listenPanStart;
+    BOOL _listenPanMove;
+    BOOL _listenPanEnd;
+    WXTouchGestureRecognizer* _touchGesture;
+    
+    /**
+     *  Display
+     */
+    CALayer *_layer;
+    BOOL _composite;
+    BOOL _compositingChild;
+    WXThreadSafeCounter *_displayCounter;
+    
+    UIColor *_borderTopColor;
+    UIColor *_borderRightColor;
+    UIColor *_borderLeftColor;
+    UIColor *_borderBottomColor;
+    
+    CGFloat _borderTopWidth;
+    CGFloat _borderRightWidth;
+    CGFloat _borderLeftWidth;
+    CGFloat _borderBottomWidth;
+    
+    CGFloat _borderTopLeftRadius;
+    CGFloat _borderTopRightRadius;
+    CGFloat _borderBottomLeftRadius;
+    CGFloat _borderBottomRightRadius;
+    
+    WXBorderStyle _borderTopStyle;
+    WXBorderStyle _borderRightStyle;
+    WXBorderStyle _borderBottomStyle;
+    WXBorderStyle _borderLeftStyle;
+    
+    
+    BOOL _isFixed;
+    BOOL _async;
+    BOOL _isNeedJoinLayoutSystem;
+    BOOL _lazyCreateView;
+    
+    NSString *_transform;
+    NSString *_transformOrigin;
+}
+
+///--------------------------------------
+/// @name Package Internal Methods
+///--------------------------------------
+
+- (void)_layoutDidFinish;
+- (void)_calculateFrameWithSuperAbsolutePosition:(CGPoint)superAbsolutePosition
+                           gatherDirtyComponents:(NSMutableSet<WXComponent *> *)dirtyComponents;
+
+
+- (void)_willDisplayLayer:(CALayer *)layer;
+
+- (void)_unloadView;
+
+- (id<WXScrollerProtocol>)ancestorScroller;
+
+- (void)_insertSubcomponent:(WXComponent *)subcomponent atIndex:(NSInteger)index;
+- (void)_removeFromSupercomponent;
+- (void)_moveToSupercomponent:(WXComponent *)newSupercomponent atIndex:(NSUInteger)index;
+
+- (void)_updateStylesOnComponentThread:(NSDictionary *)styles;
+- (void)_updateAttributesOnComponentThread:(NSDictionary *)attributes;
+- (void)_updateStylesOnMainThread:(NSDictionary *)styles;
+- (void)_updateAttributesOnMainThread:(NSDictionary *)attributes;
+
+- (void)_addEventOnComponentThread:(NSString *)eventName;
+- (void)_removeEventOnComponentThread:(NSString *)eventName;
+- (void)_addEventOnMainThread:(NSString *)eventName;
+- (void)_removeEventOnMainThread:(NSString *)eventName;
+
+///--------------------------------------
+/// @name Protected Methods
+///--------------------------------------
+
+- (BOOL)_needsDrawBorder;
+
+- (void)_drawBorderWithContext:(CGContextRef)context size:(CGSize)size;
+
+- (void)_calculatedFrameDidChange;
+
+- (NSUInteger)_childrenCountForLayout;
+
+- (void)_fillAbsolutePositions;
+
+///--------------------------------------
+/// @name Private Methods
+///--------------------------------------
+
+- (void)_initCSSNodeWithStyles:(NSDictionary *)styles;
+
+- (void)_updateCSSNodeStyles:(NSDictionary *)styles;
+
+- (void)_recomputeCSSNodeChildren;
+
+- (void)_recomputeBorderRadius;
+
+- (void)_handleBorders:(NSDictionary *)styles isUpdating:(BOOL)updating;
+
+- (void)_initViewPropertyWithStyles:(NSDictionary *)styles;
+
+- (void)_updateViewStyles:(NSDictionary *)styles;
+
+- (void)_initEvents:(NSArray *)events;
+
+- (void)_removeAllEvents;
+
+- (void)_setupNavBarWithStyles:(NSMutableDictionary *)styles attributes:(NSMutableDictionary *)attributes;
+
+- (void)_updateNavBarAttributes:(NSDictionary *)attributes;
+
+@end
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXDivComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXDivComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXDivComponent.h
new file mode 100644
index 0000000..677eae2
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXDivComponent.h
@@ -0,0 +1,13 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXComponent.h"
+
+@interface WXDivComponent : WXComponent
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXDivComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXDivComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXDivComponent.m
new file mode 100644
index 0000000..c07f1c4
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXDivComponent.m
@@ -0,0 +1,16 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXDivComponent.h"
+
+@interface WXDivComponent ()
+@end
+
+@implementation WXDivComponent
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXEmbedComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXEmbedComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXEmbedComponent.h
new file mode 100644
index 0000000..9e28ece
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXEmbedComponent.h
@@ -0,0 +1,15 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXComponent.h"
+
+@interface WXEmbedComponent : WXComponent
+
+- (void)refreshWeex;
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXEmbedComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXEmbedComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXEmbedComponent.m
new file mode 100644
index 0000000..5b70f03
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXEmbedComponent.m
@@ -0,0 +1,175 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXEmbedComponent.h"
+#import "WXComponent_internal.h"
+#import "WXSDKInstance_private.h"
+#import "WXComponent+Navigation.h"
+#import "WXSDKInstance.h"
+#import "WXConvert.h"
+
+@interface WXEmbedComponent ()
+
+@property (nonatomic, strong) WXSDKInstance *embedInstance;
+@property (nonatomic, strong) UIView *embedView;
+@property (nonatomic, assign) BOOL renderFinished;
+@property (nonatomic, assign) WXVisibility visible;
+@property (nonatomic, strong) NSURL *sourceURL;
+
+@end
+
+@implementation WXEmbedComponent
+
+#pragma mark Life Cycle
+
+- (void)dealloc
+{
+    if (self.weexInstance) {
+        [self.weexInstance removeObserver:self forKeyPath:@"state"];
+    }
+    
+    if (self.embedInstance) {
+        [self.embedInstance destroyInstance];
+    }
+}
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
+{
+    if (self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance]) {
+        _sourceURL = [NSURL URLWithString: attributes[@"src"]];
+        _visible =  [WXConvert WXVisibility:styles[@"visibility"]];
+        
+        [self.weexInstance addObserver:self forKeyPath:@"state" options:NSKeyValueObservingOptionNew context:nil];
+    }
+    
+    return self;
+}
+
+- (void)viewDidLoad {
+    
+    [super viewDidLoad];
+    
+    [self _layoutEmbedView];
+}
+
+- (void)updateStyles:(NSDictionary *)styles
+{
+    [super updateStyles:styles];
+    
+    if (styles[@"visibility"]) {
+        WXVisibility visible = [WXConvert WXVisibility:styles[@"visibility"]];
+        if (_visible != visible) {
+            _visible = visible;
+            [self _layoutEmbedView];
+        }
+    }
+}
+
+- (void)updateAttributes:(NSDictionary *)attributes
+{
+    [super updateAttributes:attributes];
+    
+    if (attributes[@"src"]) {
+        NSURL *sourceURL = [NSURL URLWithString:attributes[@"src"]];
+        if (!sourceURL|| ![[sourceURL absoluteString] isEqualToString:[_sourceURL absoluteString]]) {
+            _sourceURL = sourceURL;
+            [self _layoutEmbedView];
+        }
+    }
+}
+
+- (void)refreshWeex
+{
+    [self _renderWithURL:_sourceURL];
+}
+
+- (void)_layoutEmbedView
+{
+    if (_visible == WXVisibilityShow) {
+        if (!_renderFinished && !CGRectEqualToRect(CGRectZero, self.calculatedFrame)) {
+            [self _renderWithURL:_sourceURL];
+        }
+        [self _updateState:WeexInstanceAppear];
+    }
+    else {
+        [self _updateState:WeexInstanceDisappear];
+    }
+}
+
+- (void)_renderWithURL:(NSURL *)sourceURL
+{
+    if (!sourceURL || [[sourceURL absoluteString] length] == 0) {
+        return;
+    }
+    
+    [_embedInstance destroyInstance];
+    _embedInstance = [[WXSDKInstance alloc] init];
+    _embedInstance.parentInstance = self.weexInstance;
+    _embedInstance.parentNodeRef = self.ref;
+    _embedInstance.frame = CGRectMake(0.0f, 0.0f, self.view.frame.size.width, self.view.frame.size.height);
+    _embedInstance.pageName = [sourceURL absoluteString];
+    _embedInstance.pageObject = self.weexInstance.viewController;
+    _embedInstance.viewController = self.weexInstance.viewController;
+    
+    NSString *newURL = nil;
+    
+    if ([sourceURL.absoluteString rangeOfString:@"?"].location != NSNotFound) {
+        newURL = [NSString stringWithFormat:@"%@&random=%d", sourceURL.absoluteString, arc4random()];
+    }
+    else {
+        newURL = [NSString stringWithFormat:@"%@?random=%d", sourceURL.absoluteString, arc4random()];
+    }
+    
+    [_embedInstance renderWithURL:[NSURL URLWithString:newURL] options:@{@"bundleUrl":[sourceURL absoluteString]} data:nil];
+    
+    __weak typeof(self) weakSelf = self;
+    _embedInstance.onCreate = ^(UIView *view) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            [weakSelf.embedView removeFromSuperview];
+            weakSelf.embedView = view;
+            weakSelf.renderFinished = YES;
+            [weakSelf.view addSubview:weakSelf.embedView];
+        });
+    };
+}
+
+- (void)_updateState:(WXState)state
+{
+    if (!_embedInstance) {
+        return;
+    }
+    
+    _embedInstance.state = state;
+    
+    if (state == WeexInstanceAppear || state == WeexInstanceForeground )
+    {
+        [self setNavigationWithStyles:self.embedInstance.naviBarStyles];
+    }
+}
+
+-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
+{
+    if ([keyPath isEqualToString:@"state"]) {
+        WXState state = [change[@"new"] longValue];
+        if (_visible == WXVisibilityHidden) {  
+            switch (state) {
+                case WeexInstanceBackground:
+                    [self _updateState:WeexInstanceBackground];
+                    break;
+                default:
+                    [self _updateState:WeexInstanceDisappear];
+                    break;
+            }
+        }
+        else {
+            [self _updateState:state];
+        }
+    }
+}
+
+@end
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXImageComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXImageComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXImageComponent.h
new file mode 100644
index 0000000..749bd17
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXImageComponent.h
@@ -0,0 +1,13 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXComponent.h"
+
+@interface WXImageComponent : WXComponent
+
+@end
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXImageComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXImageComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXImageComponent.m
new file mode 100644
index 0000000..57b373b
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXImageComponent.m
@@ -0,0 +1,234 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXImageComponent.h"
+#import "WXHandlerFactory.h"
+#import "WXComponent_internal.h"
+#import "WXImgLoaderProtocol.h"
+#import "WXLayer.h"
+#import "WXType.h"
+#import "WXConvert.h"
+
+@interface WXImageView : UIImageView
+
+@end
+
+@implementation WXImageView
+
++ (Class)layerClass
+{
+    return [WXLayer class];
+}
+
+@end
+
+static dispatch_queue_t WXImageUpdateQueue;
+
+@interface WXImageComponent ()
+
+@property (nonatomic, strong) NSString *imageSrc;
+@property (nonatomic, assign) UIViewContentMode resizeMode;
+@property (nonatomic, assign) WXImageQuality imageQuality;
+@property (nonatomic, assign) WXImageSharp imageSharp;
+@property (nonatomic, strong) UIImage *image;
+@property (nonatomic, strong) id<WXImageOperationProtocol> imageOperation;
+
+@end
+
+@implementation WXImageComponent
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
+{
+    if (self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance]) {
+        _async = YES;
+        if (!WXImageUpdateQueue) {
+            WXImageUpdateQueue = dispatch_queue_create("com.taobao.weex.ImageUpdateQueue", DISPATCH_QUEUE_SERIAL);
+        }
+        
+        _imageSrc = [WXConvert NSString:attributes[@"src"]];
+        _resizeMode = [WXConvert UIViewContentMode:attributes[@"resize"]];
+        _imageQuality = [WXConvert WXImageQuality:styles[@"quality"]];
+        _imageSharp = [WXConvert WXImageSharp:styles[@"sharpen"]];
+    }
+    
+    return self;
+}
+
+- (UIView *)loadView
+{
+    return [[WXImageView alloc] init];
+}
+
+- (void)updateStyles:(NSDictionary *)styles
+{
+    if (styles[@"quality"]) {
+        _imageQuality = [WXConvert WXImageQuality:styles[@"quality"]];
+        [self updateImage];
+    }
+    
+    if (styles[@"sharpen"]) {
+        _imageSharp = [WXConvert WXImageSharp:styles[@"sharpen"]];
+        [self updateImage];
+    }
+}
+
+- (void)updateAttributes:(NSDictionary *)attributes
+{
+    if (attributes[@"src"]) {
+        _imageSrc = [WXConvert NSString:attributes[@"src"]];
+        [self updateImage];
+    }
+    
+    if (attributes[@"resize"]) {
+        _resizeMode = [WXConvert UIViewContentMode:attributes[@"resize"]];
+        self.view.contentMode = _resizeMode;
+    }
+}
+
+- (void)viewDidLoad
+{
+    UIImageView *imageView = (UIImageView *)self.view;
+    imageView.contentMode = _resizeMode;
+    imageView.userInteractionEnabled = YES;
+    imageView.clipsToBounds = YES;
+    imageView.exclusiveTouch = YES;
+    
+    if (_image) {
+        imageView.image = _image;
+        _image = nil;
+    } else {
+        [self updateImage];
+    }
+}
+
+- (WXDisplayBlock)displayBlock
+{
+    if ([self isViewLoaded]) {
+        // if has a image view, image is setted by image view, displayBlock is not needed
+        return nil;
+    }
+    
+    __weak typeof(self) weakSelf = self;
+    return ^UIImage *(CGRect bounds, BOOL(^isCancelled)(void)) {
+        if (isCancelled()) {
+            return nil;
+        }
+        
+        if (!weakSelf.image) {
+            [weakSelf updateImage];
+            return nil;
+        }
+        
+        if (isCancelled && isCancelled()) {
+            return nil;
+        }
+        
+        UIGraphicsBeginImageContextWithOptions(bounds.size, self.layer.opaque, 1.0);
+        
+        [weakSelf.image drawInRect:bounds];
+        
+        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
+        
+        UIGraphicsEndImageContext();
+        
+        return image;
+    };
+}
+
+- (void)viewWillUnload
+{
+    [super viewWillUnload];
+    [self cancelImage];
+    _image = nil;
+}
+
+- (void)setImageSrc:(NSString*)src
+{
+    if (![src isEqualToString:_imageSrc]) {
+        _imageSrc = src;
+        [self updateImage];
+    }
+}
+
+- (void)updateImage
+{
+    __weak typeof(self) weakSelf = self;
+    dispatch_async(WXImageUpdateQueue, ^{
+        [self cancelImage];
+        
+        if (CGRectEqualToRect(self.calculatedFrame, CGRectZero)) {
+            return;
+        }
+        
+        if (weakSelf.imageSrc) {
+            NSString *imageSrc = weakSelf.imageSrc;
+            NSDictionary *userInfo = @{@"imageQuality":@(weakSelf.imageQuality), @"imageSharp":@(weakSelf.imageSharp)};
+            WXLogVerbose(@"Updating image, component:%@, image source:%@, userInfo:%@", self.ref, imageSrc, userInfo);
+            weakSelf.imageOperation = [[weakSelf imageLoader] downloadImageWithURL:imageSrc imageFrame:weakSelf.calculatedFrame userInfo:userInfo completed:^(UIImage *image, NSError *error, BOOL finished) {
+                dispatch_async(dispatch_get_main_queue(), ^{
+                    __strong typeof(self) strongSelf = weakSelf;
+                    if (error) {
+                        WXLogError(@"Error downloading image:%@, detail:%@", imageSrc, [error localizedDescription]);
+                        if ([strongSelf isViewLoaded]) {
+                            ((UIImageView *)(strongSelf.view)).image = nil;
+                        }
+                        return ;
+                    }
+                    
+                    if (![imageSrc isEqualToString:strongSelf.imageSrc]) {
+                        return ;
+                    }
+                    if ([strongSelf isViewLoaded]) {
+                        ((UIImageView *)strongSelf.view).image = image;
+                    } else {
+                        //TODO: Need this?
+                        strongSelf.image = image;
+                        [strongSelf setNeedsDisplay];
+                    }
+                });
+            }];
+        } else {
+            dispatch_async(dispatch_get_main_queue(), ^{
+                self.layer.contents = nil;
+            });
+        }
+    });
+}
+
+- (void)cancelImage
+{
+    [_imageOperation cancel];
+    _imageOperation = nil;
+}
+
+- (id<WXImgLoaderProtocol>)imageLoader
+{
+    static id<WXImgLoaderProtocol> imageLoader;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        imageLoader = [WXHandlerFactory handlerForProtocol:@protocol(WXImgLoaderProtocol)];
+    });
+    return imageLoader;
+}
+
+- (BOOL)_needsDrawBorder
+{
+    return NO;
+}
+
+#ifdef UITEST
+- (NSString *)description
+{
+    NSString *superDescription = super.description;
+    NSRange semicolonRange = [superDescription rangeOfString:@";"];
+    NSString *replacement = [NSString stringWithFormat:@"; imageSrc: %@; imageQuality: %@; imageSharp: %@; ",_imageSrc,_imageQuality,_imageSharp];
+    return [superDescription stringByReplacingCharactersInRange:semicolonRange withString:replacement];
+}
+#endif
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXIndicatorComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXIndicatorComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXIndicatorComponent.h
new file mode 100644
index 0000000..faeae40
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXIndicatorComponent.h
@@ -0,0 +1,33 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXComponent.h"
+
+typedef enum
+{
+    WXPointIndicatorAlignCenter,    // point indicator align center
+    WXPointIndicatorAlignLeft,      // point indicator align left
+    WXPointIndicatorAlignRight,     // point indicator align right
+} WXPointIndicatorAlignStyle;
+
+@interface WXIndicatorView : UIView
+
+@property (nonatomic, assign)   NSInteger   pointCount;         // total count point of point indicator
+@property (nonatomic, assign)   NSInteger   currentPoint;       // current light index of point at point indicator
+@property (nonatomic, strong)   UIColor *pointColor;        // normal point color of point indicator
+@property (nonatomic, strong)   UIColor *lightColor;        // highlight point color of point indicator
+@property (nonatomic, assign)   WXPointIndicatorAlignStyle  alignStyle;    //align style of point indicator
+@property (nonatomic, assign)   CGFloat pointSize;          // point size of point indicator
+@property (nonatomic, assign)   CGFloat pointSpace;         // point space of point indicator
+
+@end
+
+
+@interface WXIndicatorComponent : WXComponent
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXIndicatorComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXIndicatorComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXIndicatorComponent.m
new file mode 100644
index 0000000..c903c2a
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXIndicatorComponent.m
@@ -0,0 +1,186 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXIndicatorComponent.h"
+#import "WXSliderComponent.h"
+#import "WXConvert.h"
+
+@implementation WXIndicatorView
+
+@synthesize pointCount = _pointCount;
+@synthesize currentPoint = _currentPoint;
+
+- (id)initWithFrame:(CGRect)frame
+{
+    self = [super initWithFrame:frame];
+    if (self) {
+        self.pointSpace = 5.0f;
+    }
+    return self;
+}
+
+- (void)setBackgroundColor:(UIColor *)backgroundColor
+{
+    [super setBackgroundColor:backgroundColor];
+}
+
+- (void)setPointCount:(NSInteger)pointCount
+{
+    _pointCount = pointCount;
+    [self setNeedsDisplay];
+}
+
+- (void)setCurrentPoint:(NSInteger)currentPoint
+{
+    if (currentPoint < _pointCount && currentPoint >= 0) {
+        _currentPoint = currentPoint;
+        [self setNeedsDisplay];
+    }
+}
+
+- (void)setPointSize:(CGFloat)pointSize
+{
+    _pointSize = pointSize;
+    [self setNeedsDisplay];
+}
+
+- (void)setPointSpace:(CGFloat)pointSpace
+{
+    _pointSpace = pointSpace;
+    [self setNeedsDisplay];
+}
+
+- (void)drawRect:(CGRect)rect
+{
+    if (self.alignStyle == WXPointIndicatorAlignCenter) {
+        CGFloat startX = 0.0f, centerX = self.frame.size.width / 2.0f;
+        if (self.pointCount % 2) {
+            startX = centerX - (self.pointSize + self.pointSpace) * (int)(self.pointCount / 2.0f) - self.pointSize / 2.0f;
+        } else {
+            startX = centerX - (self.pointSize + self.pointSpace) * (int)(self.pointCount / 2.0f) +  self.pointSpace / 2.0f;   
+        }
+        
+        CGContextRef context=UIGraphicsGetCurrentContext();
+        CGContextBeginPath(context);
+        
+        for (int i = 0; i < self.pointCount; i++) {
+            if (self.currentPoint == i) {
+                CGContextSetFillColorWithColor(context, self.lightColor.CGColor);
+                CGContextAddEllipseInRect(context, CGRectMake(startX, (self.frame.size.height - self.pointSize) / 2.0f, self.pointSize, self.pointSize));
+                CGContextFillPath(context);
+            } else {
+                CGContextSetFillColorWithColor(context, self.pointColor.CGColor);
+                CGContextAddEllipseInRect(context, CGRectMake(startX, (self.frame.size.height - self.pointSize) / 2.0f, self.pointSize, self.pointSize));
+                CGContextFillPath(context);
+            }
+            startX += self.pointSize + self.pointSpace;
+        }
+    } else if (self.alignStyle == WXPointIndicatorAlignRight) {
+        CGFloat startX = self.frame.size.width - self.pointSize * self.pointCount - self.pointSpace * (self.pointCount - 1) - 10;   //10 right margin
+        CGContextRef context=UIGraphicsGetCurrentContext();
+        CGContextBeginPath(context);
+        
+        for(int i = 0; i < self.pointCount; i++) {
+            if (self.currentPoint == i) {
+                CGContextSetFillColorWithColor(context, self.lightColor.CGColor);
+                CGContextAddEllipseInRect(context, CGRectMake(startX, (self.frame.size.height - self.pointSize) / 2.0f, self.pointSize, self.pointSize));
+                CGContextFillPath(context);
+            } else {
+                CGContextSetFillColorWithColor(context, self.pointColor.CGColor);
+                CGContextAddEllipseInRect(context, CGRectMake(startX, (self.frame.size.height - self.pointSize) / 2.0f, self.pointSize, self.pointSize));
+                CGContextFillPath(context);
+            }
+            startX += self.pointSize + self.pointSpace;
+        }
+    } else if (self.alignStyle == WXPointIndicatorAlignLeft) {
+        CGFloat startX = 10.0f;   //10 left margin
+        CGContextRef context=UIGraphicsGetCurrentContext();
+        CGContextBeginPath(context);
+        for(int i = 0; i < self.pointCount; i++) {
+            if (self.currentPoint == i) {
+                CGContextSetFillColorWithColor(context, self.lightColor.CGColor);
+                CGContextAddEllipseInRect(context, CGRectMake(startX, (self.frame.size.height - self.pointSize) / 2.0f, self.pointSize, self.pointSize));
+                CGContextFillPath(context);
+            } else {
+                CGContextSetFillColorWithColor(context, self.pointColor.CGColor);
+                CGContextAddEllipseInRect(context, CGRectMake(startX, (self.frame.size.height - self.pointSize) / 2.0f, self.pointSize, self.pointSize));
+                CGContextFillPath(context);
+            }
+            startX += self.pointSize + self.pointSpace;
+        }
+    }
+}
+
+@end
+
+@interface WXIndicatorComponent()
+
+@property (nonatomic, strong)   WXIndicatorView   *indicatorView;
+
+@property (nonatomic, strong)   UIColor   *itemColor;
+@property (nonatomic, strong)   UIColor   *itemSelectedColor;
+@property (nonatomic)   CGFloat   itemSize;
+
+@end
+
+@implementation WXIndicatorComponent
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
+{
+    if (self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance]) {
+        _itemColor = styles[@"itemColor"] ? [WXConvert UIColor:styles[@"itemColor"]]:[UIColor colorWithRed:0xff/255.0f green:0xff/255.0f blue:0xff/255.0f alpha:0.5f];
+        _itemSelectedColor = styles[@"itemSelectedColor"] ? [WXConvert UIColor:styles[@"itemSelectedColor"]]:[UIColor colorWithRed:0xff/255.0f green:0xd5/255.0f blue:0x45/255.0f alpha:1.0f];
+        _itemSize = styles[@"itemSize"] ? [WXConvert CGFloat:styles[@"itemSize"]]: 5.0f;
+    }
+    return self;
+}
+
+- (UIView *)loadView
+{
+    return [[WXIndicatorView alloc] init];
+}
+
+- (void)viewDidLoad
+{
+    [super viewDidLoad];
+    
+    _indicatorView = (WXIndicatorView *)self.view;
+    _indicatorView.alignStyle = WXPointIndicatorAlignCenter;
+    _indicatorView.userInteractionEnabled = NO;
+    _indicatorView.pointColor = _itemColor;
+    _indicatorView.lightColor = _itemSelectedColor;
+    _indicatorView.pointSize = _itemSize;
+    
+    WXComponent *parent = self.supercomponent;
+    if([parent isKindOfClass:[WXSliderComponent class]]) {
+        WXSliderComponent *parentSlider = (WXSliderComponent *)parent;
+        [parentSlider setIndicatorView:_indicatorView];
+    }
+    else {
+         NSAssert(NO, @"");
+    }
+}
+
+- (void)updateStyles:(NSDictionary *)styles
+{
+    if (styles[@"itemColor"]) {
+        _itemColor = [WXConvert UIColor:styles[@"itemColor"]];
+        [_indicatorView setPointColor:_itemColor];
+    }
+    else if (styles[@"itemSelectedColor"]) {
+        _itemSelectedColor = [WXConvert UIColor:styles[@"itemSelectedColor"]];
+        [_indicatorView setLightColor:_itemSelectedColor];
+    }
+    else if (styles[@"itemSize"]) {
+        _itemSize = [WXConvert WXPixelType:styles[@"itemSelectedColor"]];
+        [_indicatorView setPointSize:_itemSize];
+    }
+}
+
+@end
+

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXListComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXListComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXListComponent.h
new file mode 100644
index 0000000..2a62c0b
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXListComponent.h
@@ -0,0 +1,24 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXCellComponent.h"
+#import "WXScrollerComponent.h"
+
+@interface WXListComponent : WXScrollerComponent
+
+- (void)cellWillRemove:(WXCellComponent *)cell;
+
+- (void)cellDidRemove:(WXCellComponent *)cell;
+
+- (void)cellDidLayout:(WXCellComponent *)cell;
+
+- (void)cellDidRendered:(WXCellComponent *)cell;
+
+- (void)cell:(WXCellComponent *)cell didMoveFromIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath;
+
+@end
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXListComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXListComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXListComponent.m
new file mode 100644
index 0000000..f4fbfd9
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXListComponent.m
@@ -0,0 +1,296 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXListComponent.h"
+#import "WXComponent.h"
+#import "WXComponent_internal.h"
+#import "NSArray+Weex.h"
+#import "WXAssert.h"
+#import "WXUtility.h"
+#import "WXSDKInstance.h"
+
+@interface WXTableView : UITableView
+
+@end
+
+@implementation WXTableView
+
++ (BOOL) requiresConstraintBasedLayout
+{
+    return NO;
+}
+
+- (void)layoutSubviews
+{
+    [super layoutSubviews];
+    [self.wx_component layoutDidFinish];
+}
+
+@end
+
+@interface WXListComponent () <UITableViewDataSource, UITableViewDelegate>
+
+@end
+
+@implementation WXListComponent
+{
+    __weak UITableView * _tableView;
+    NSMutableArray *     _cellComponents;
+    NSMutableArray *     _completedCells;
+    NSUInteger           _previousLoadMoreRowNumber;
+}
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
+{
+    if (self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance]) {
+        
+        _cellComponents = [NSMutableArray wx_mutableArrayUsingWeakReferences];
+        _completedCells = [NSMutableArray wx_mutableArrayUsingWeakReferences];
+    }
+    
+    return self;
+}
+
+- (UIView *)loadView
+{
+    return [[WXTableView alloc] init];
+}
+
+- (void)viewDidLoad
+{
+    [super viewDidLoad];
+    
+    _tableView = (UITableView *)self.view;
+    _tableView.allowsSelection = NO;
+    _tableView.allowsMultipleSelection = NO;
+    _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
+    _tableView.delegate = self;
+    _tableView.dataSource = self;
+    _tableView.userInteractionEnabled = YES;
+}
+
+- (void)setContentSize:(CGSize)contentSize
+{
+    // Do Nothing
+}
+
+- (NSUInteger)childrenCountForScrollerLayout
+{
+    return [super childrenCountForScrollerLayout] - _cellComponents.count;
+}
+
+#pragma mark - Inheritance
+
+- (void)_insertSubcomponent:(WXComponent *)subcomponent atIndex:(NSInteger)index
+{
+    [super _insertSubcomponent:subcomponent atIndex:index];
+    
+    if ([subcomponent isKindOfClass:[WXCellComponent class]]) {
+        WXCellComponent *cellComponent = (WXCellComponent *)subcomponent;
+        cellComponent.list = self;
+        
+        NSInteger insertIndex = index;
+        for (int j = 0; j <= index && j < self.subcomponents.count; j++) {
+            WXComponent *child = self.subcomponents[j];
+            if (![child isKindOfClass:[WXCellComponent class]]) {
+                insertIndex--;
+            }
+        }
+        
+        cellComponent.indexPath = [NSIndexPath indexPathForRow:insertIndex inSection:0];
+        [_cellComponents insertObject:subcomponent atIndex:insertIndex];
+    }
+}
+
+
+- (void)insertSubview:(WXComponent *)subcomponent atIndex:(NSInteger)index
+{
+    //List View insert cell's view by - cellForRowAtIndexPath:, so here will not insert cell's view again
+    if (![subcomponent isKindOfClass:[WXCellComponent class]]) {
+        [super insertSubview:subcomponent atIndex:index];
+    }
+}
+
+- (void)cellWillRemove:(WXCellComponent *)cell
+{
+    WXAssertComponentThread();
+    
+    [_cellComponents removeObject:cell];
+}
+
+- (void)cellDidRemove:(WXCellComponent *)cell
+{
+    WXAssertMainThread();
+    
+    NSIndexPath *indexPath = cell.indexPath;
+    WXAssert(indexPath, @"Removing cell:%@ has not been inserted to cell list before", cell);
+    
+    [_completedCells removeObject:cell];
+    
+    [UIView performWithoutAnimation:^{
+        [_tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
+    }];
+}
+
+- (void)cellDidLayout:(WXCellComponent *)cell
+{
+    WXAssertMainThread();
+    
+    NSIndexPath *indexPath = cell.indexPath;
+    WXAssert(indexPath, @"Laid out cell:%@ has not been inserted to cell list before", cell);
+
+    if (indexPath.row == 0) {
+        cell.absolutePosition = CGPointZero;
+    } else {
+        WXCellComponent *previousCell = _cellComponents[indexPath.row - 1];
+        CGPoint previousCellPostion = previousCell.absolutePosition;
+        cell.absolutePosition = CGPointMake(previousCellPostion.x, previousCellPostion.y + previousCell.calculatedFrame.size.height);
+    }
+    
+    [cell _fillAbsolutePositions];
+    
+    if (![_completedCells containsObject:cell]) {
+        [_completedCells addObject:cell];
+        WXLogVerbose(@"Insert cell at row:%ld", (long)indexPath.row);
+        [UIView performWithoutAnimation:^{
+            [_tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
+        }];
+    } else {
+        WXLogVerbose(@"Reload cell at row:%ld", (long)indexPath.row);
+        [UIView performWithoutAnimation:^{
+            [_tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
+        }];
+    }
+}
+
+- (void)cellDidRendered:(WXCellComponent *)cell
+{
+    WXAssertMainThread();
+    
+    NSIndexPath *indexPath = cell.indexPath;
+    WXAssert(indexPath, @"Rendered cell:%@ has not been inserted to cell list before", cell);
+
+    CGRect cellRect = [_tableView rectForRowAtIndexPath:indexPath];
+    if (cellRect.origin.y + cellRect.size.height >= _tableView.frame.size.height) {
+        if (self.weexInstance.screenRenderTime == 0) {
+            self.weexInstance.screenRenderTime = [[NSDate new] timeIntervalSinceDate:self.weexInstance.renderStartDate];
+        }
+    }
+    
+    if (self.weexInstance.onRenderProgress) {
+        CGRect renderRect = CGRectMake(self.absolutePosition.x + cellRect.origin.x,
+                                       self.absolutePosition.y + cellRect.origin.y,
+                                       cellRect.size.width, cellRect.size.height);
+        
+        self.weexInstance.onRenderProgress(renderRect);
+    }
+
+}
+
+- (void)cell:(WXCellComponent *)cell didMoveFromIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
+{
+    WXAssert(fromIndexPath, @"Moved cell:%@ has not been inserted to cell list before", cell);
+    
+    [UIView performWithoutAnimation:^{
+        [_tableView moveRowAtIndexPath:fromIndexPath toIndexPath:toIndexPath];
+    }];
+}
+
+#pragma mark - TableView delegate
+
+- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
+{
+    
+}
+
+- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
+{
+    NSArray *visibleIndexPaths = [tableView indexPathsForVisibleRows];
+    if (![visibleIndexPaths containsObject:indexPath]) {
+        WXCellComponent *component = [_cellComponents wx_safeObjectAtIndex:indexPath.row];
+        dispatch_async(dispatch_get_main_queue(), ^{
+            [component _unloadView];
+        });
+    }
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
+{
+    WXCellComponent *cell = _cellComponents[indexPath.row];
+    return cell.calculatedFrame.size.height;
+}
+
+#pragma mark - TableView Data Source
+
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
+{
+    return 1;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
+{
+    return [_completedCells count];
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
+{
+    static NSString *reuseIdentifier = @"WXTableViewCell";
+    
+    WXCellComponent *cell = _cellComponents[indexPath.row];
+    if (cell.scope.length > 0) {
+        //        reuseIdentifier = cell.scope;
+    }
+    
+    UITableViewCell *cellView = [_tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
+    if (!cellView) {
+        cellView = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
+        cellView.backgroundColor = [UIColor clearColor];
+    } else {
+    }
+    
+    if (cell.view.superview == cellView.contentView) {
+        return cellView;
+    }
+    
+    for (UIView *view in cellView.contentView.subviews) {
+        [view removeFromSuperview];
+    }
+    
+    [cellView.contentView addSubview:cell.view];
+    
+    double time = -[self.weexInstance.renderStartDate timeIntervalSinceNow] * 1000;
+    WXLogInfo(@"View Create Finish...%ld, %f", (long)indexPath.row, time);
+
+    return cellView;
+}
+
+#pragma mark - Load More Event
+
+- (void)setLoadmoreretry:(NSUInteger)loadmoreretry
+{
+    if (loadmoreretry > self.loadmoreretry) {
+        _previousLoadMoreRowNumber = 0;
+    }
+    
+    [super setLoadmoreretry:loadmoreretry];
+}
+
+- (void)loadMore
+{
+    [super loadMore];
+    _previousLoadMoreRowNumber = [self tableView:_tableView numberOfRowsInSection:0];
+}
+
+- (BOOL)isNeedLoadMore
+{
+    BOOL superNeedLoadMore = [super isNeedLoadMore];
+    return superNeedLoadMore && _previousLoadMoreRowNumber != [self tableView:_tableView numberOfRowsInSection:0];
+}
+
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXLoadingComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXLoadingComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXLoadingComponent.h
new file mode 100644
index 0000000..6a78b04
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXLoadingComponent.h
@@ -0,0 +1,17 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXComponent.h"
+
+@interface WXLoadingComponent : WXComponent
+
+- (void)resizeFrame;
+- (void)loading;
+- (BOOL)displayState;
+
+@end
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXLoadingComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXLoadingComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXLoadingComponent.m
new file mode 100644
index 0000000..78006ef
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXLoadingComponent.m
@@ -0,0 +1,137 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXLoadingComponent.h"
+#import "WXScrollerComponent.h"
+#import "WXLoadingIndicator.h"
+#import "WXComponent_internal.h"
+#import "WXLog.h"
+
+@interface WXLoadingComponent()
+
+@property (nonatomic) BOOL initFinished;
+@property (nonatomic) BOOL loadingEvent;
+@property (nonatomic) BOOL displayState;
+
+@property (nonatomic, weak) WXLoadingIndicator *indicator;
+
+@end
+
+@implementation WXLoadingComponent
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
+{
+    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
+    if (self) {
+        if (attributes[@"display"]) {
+            if ([attributes[@"display"] isEqualToString:@"show"]) {
+                _displayState = YES;
+            } else if ([attributes[@"display"] isEqualToString:@"hide"]){
+                _displayState = NO;
+            } else {
+                WXLogError(@"");
+            }
+        }
+        self.cssNode->style.position_type = CSS_POSITION_ABSOLUTE;
+    }
+    return self;
+}
+
+- (void)viewWillUnload
+{
+    _displayState = NO;
+    _loadingEvent = NO;
+    _initFinished = NO;
+}
+
+-(void)updateAttributes:(NSDictionary *)attributes
+{
+    if (attributes[@"display"]) {
+        if ([attributes[@"display"] isEqualToString:@"show"]) {
+            _displayState = YES;
+            
+        } else if ([attributes[@"display"] isEqualToString:@"hide"]) {
+            _displayState = NO;
+        } else {
+            WXLogError(@"");
+        }
+        [self setDisplay];
+    }
+}
+
+- (void)viewDidLoad
+{
+    _initFinished = YES;
+}
+
+- (void)addEvent:(NSString *)eventName
+{
+    if ([eventName isEqualToString:@"loading"]) {
+        _loadingEvent = YES;
+    }
+}
+
+- (void)removeEvent:(NSString *)eventName
+{
+    if ([eventName isEqualToString:@"loading"]) {
+        _loadingEvent = NO;
+    }
+}
+
+- (void)loading
+{
+    if (!_loadingEvent)
+        return;
+    
+    [self fireEvent:@"loading" params:nil];
+}
+
+- (void)setDisplay
+{
+    id<WXScrollerProtocol> scrollerProtocol = self.ancestorScroller;
+    if (scrollerProtocol == nil || !_initFinished)
+        return;
+    
+    WXComponent *scroller = (WXComponent*)scrollerProtocol;
+    CGPoint contentOffset = [scrollerProtocol contentOffset];
+    if (_displayState) {
+        contentOffset.y = [scrollerProtocol contentSize].height - scroller.calculatedFrame.size.height + self.view.frame.size.height;
+        [scrollerProtocol setContentOffset:contentOffset animated:YES];
+        [_indicator start];
+    } else {
+        UIEdgeInsets insets = [scrollerProtocol contentInset];
+        insets.bottom = 0;
+        
+        [scrollerProtocol setContentInset:insets];
+        [_indicator stop];
+    }
+}
+
+- (void)_insertSubcomponent:(WXComponent *)subcomponent atIndex:(NSInteger)index
+{
+    if (subcomponent) {
+        [super _insertSubcomponent:subcomponent atIndex:index];
+        if ([subcomponent isKindOfClass:[WXLoadingIndicator class]]) {
+            _indicator = (WXLoadingIndicator*)subcomponent;
+        }
+    }
+}
+
+- (void)resizeFrame
+{
+    CGRect rect = self.view.frame;
+    
+    id<WXScrollerProtocol> scrollerProtocol = self.ancestorScroller;
+    if (scrollerProtocol) {
+        rect.origin.y = [scrollerProtocol contentSize].height;
+    }
+    
+    [self.view setFrame:rect];
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXLoadingIndicator.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXLoadingIndicator.h b/ios/sdk/WeexSDK/Sources/Component/WXLoadingIndicator.h
new file mode 100644
index 0000000..8cc9990
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXLoadingIndicator.h
@@ -0,0 +1,17 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXComponent.h"
+
+@interface WXLoadingIndicator : WXComponent
+
+- (void)start;
+- (void)stop;
+- (void)setFrame:(CGRect)frame;
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXLoadingIndicator.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXLoadingIndicator.m b/ios/sdk/WeexSDK/Sources/Component/WXLoadingIndicator.m
new file mode 100644
index 0000000..16af357
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXLoadingIndicator.m
@@ -0,0 +1,78 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXLoadingIndicator.h"
+#import "WXConvert.h"
+
+@interface WXLoadingIndicator()
+
+@property (nonatomic, strong) UIActivityIndicatorView* indicator;
+
+@end
+
+@implementation WXLoadingIndicator
+
+- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance {
+    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
+    if (self) {
+        _indicator = [[UIActivityIndicatorView alloc] init];
+        if (styles[@"color"]) {
+            [self setColor:[WXConvert UIColor:styles[@"color"]]];
+        }
+    }
+    
+    return self;
+}
+
+- (void)updateStyles:(NSDictionary *)styles
+{
+    if (styles[@"color"]) {
+        [self setColor:[WXConvert UIColor:styles[@"color"]]];
+    }
+}
+
+- (UIView *)loadView
+{
+    return _indicator;
+}
+
+#pragma mark - lifeCircle
+- (void)viewWillUnload
+{
+    [_indicator stopAnimating];
+    _indicator = nil;
+
+}
+
+- (void)viewDidLoad
+{
+    [self setFrame:self.calculatedFrame];
+}
+
+- (void)setColor:(UIColor *)color
+{
+    _indicator.color = color;
+}
+
+- (void)start
+{
+    [_indicator startAnimating];
+}
+
+- (void)stop
+{
+    [_indicator stopAnimating];
+}
+
+- (void)setFrame:(CGRect)frame
+{
+    [_indicator setFrame:frame];
+}
+
+@end
+

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/185fe55c/ios/sdk/WeexSDK/Sources/Component/WXRefreshComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXRefreshComponent.h b/ios/sdk/WeexSDK/Sources/Component/WXRefreshComponent.h
new file mode 100644
index 0000000..46275f5
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Component/WXRefreshComponent.h
@@ -0,0 +1,17 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXComponent.h"
+
+@interface WXRefreshComponent : WXComponent
+
+- (void)refresh;
+
+- (BOOL)displayState;
+
+@end