1. 程式人生 > >Weex學習與實踐(三):iOS原理篇

Weex學習與實踐(三):iOS原理篇

本文主要介紹包括WeexSDK-iOS主要類介紹、Weex頁面iOS端渲染流程、JS呼叫iOS方法

主要類

WXSDKEngine

WXSDKEngine主要用於初始化WeexSDK的環境

一開始會載入配置檔案main.js並且註冊一些預設的元件、模組以及handler

+ (void)initSDKEnviroment:(NSString *)script
{
   
    [self _registerDefaultComponents];
    [self _registerDefaultModules];
    [self _registerDefaultHandlers];
    
    [[WXSDKManager bridgeMgr] executeJsFramework:script];
}

在executeJsFramework前,會設定後JSContext的一些回撥,例如

    _jsContext[@"callNative"] = callNativeBlock;

以方便JS呼叫native的方法。

executeJsFramework呼叫的是JSContext的evaluateScript方法,把main.js執行到jS的環境裡面,之後再通過JSValue呼叫invokeMethod方法,把前面所有的components,modules,handlers註冊進入JS環境

WXSDKInstance

一個WXSDKInstance就對應一個UIViewController,對應一個weex頁面。

主要用來渲染頁面,一般通過renderWithURL方法,然後能夠接收一些回撥和一些檢視相關的方法

onCreate //根檢視rootView建立的時候
renderFinish//檢視渲染完成
componentForRef //通過檢視索引拿到對應的元件檢視

WXBridgeManager

WXBridgeManager 是JS與iOS通過JSCore互動的類,相關的類還有WXBridgeContext、WXJSCoreBridge。

比如呼叫JS


- (void)executeJsMethod:(WXBridgeMethod *)method
{
    if (!method) return;
    
    __weak typeof(self) weakSelf = self;
    WXPerformBlockOnBridgeThread(^(){
        [weakSelf.bridgeCtx executeJsMethod:method];
    });
}

JS呼叫native的話需要通過WXJSCoreBridge的registerCallNative方法

WXComponent

元件基類,自己實現iOS端的元件需要繼承它。相關的還有負責元件初始化的工廠類WXComponentFactory,以及WXComponentManager

WXModuleProtocol

自定義module需要實現的協議

weex頁面iOS端渲染流程

首先在ViewController裡的render放初始化WXSDKInstance,因為render會支援實時重新整理,所以每次都需要先銷燬這個例項。

    [_instance destroyInstance];
    _instance = [[WXSDKInstance alloc] init];

然後WXSDKManager會儲存instanceId

        [WXSDKManager storeInstance:self forID:_instanceId];

然後會呼叫renderWithURL方法來載入script,在這裡會判斷是本地檔案還是需要從伺服器下載,

- (void)renderWithURL:(NSURL *)url options:(NSDictionary *)options data:(id)data{
	    if ([url isFileURL]) {
        //from local
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSString *path = [url path];
            NSData *scriptData = [[NSFileManager defaultManager] contentsAtPath:path];
            NSString *script = [[NSString alloc] initWithData:scriptData encoding:NSUTF8StringEncoding];
            [weakSelf renderView:script options:newOptions data:data];
        });
    }else{
    	//from server
    }
}

然後就會根據script檔案渲染檢視

[weakSelf renderView:script options:newOptions data:data];

在這個方法裡面首先會建立根檢視,當建立完成時WXSDKInstance會收到onCreate的回撥

    //TODO WXRootView
    WXPerformBlockOnMainThread(^{
        self.rootView = [[WXView alloc] initWithFrame:self.frame];
        if(self.onCreate) {
            self.onCreate(self.rootView);
        }
    });

之後再通過bridge呼叫JS方法來開始建立例項

    [self callJSMethod:@"createInstance" args:args];

然後這裡會判斷JSFramework也就是js有沒有載入完成,然後再通過WXJSBridge的JSContext來執行js方法,這裡呼叫的就是js的createInstance方法,args裡面主要就是instanceID,we檔案轉化的js檔案,和options。

- (void)callJSMethod:(NSString *)method args:(NSArray *)args
{
    [[_jsContext globalObject] invokeMethod:method withArguments:args];
}

最後js會呼叫JSContext的callCreateFinish回撥,最後呼叫WXSDKInstance的createFinish方法來結束頁面的渲染

JS呼叫iOS方法

首先要註冊一個元件

    [self registerModule:@"dom" withClass:NSClassFromString(@"WXDomModule")];

註冊module的時候 會通過下面方法

+ (void)registerModule:(NSString *)name withClass:(Class)clazz
{
    WXAssert(name && clazz, @"Fail to register the module, please check if the parameters are correct !");
    
    NSString *moduleName = [WXModuleFactory registerModule:name withClass:clazz];
    NSDictionary *dict = [WXModuleFactory moduleMethodMapsWithName:moduleName];
    
    [[WXSDKManager bridgeMgr] registerModules:dict];
}

把所有通過巨集註冊的方法傳送給js端

WX_EXPORT_METHOD(@selector(createBody:))

這會把方法暴露出來,並且方法名字是”wx_export_method_“加程式碼所在行號,wx_export_method_25

元件、模組 是給js端用的,而handler則是給objc自己用的,所以不用傳送訊息給js端

然後通過methodForSelector拿到WX_EXPORT_METHOD方法的返回值,並且儲存到methods中

- (void)registerModuleMethods {

            if ([currentClass respondsToSelector:selector]) {
                method = ((NSString* (*)(id, SEL))[currentClass methodForSelector:selector])(currentClass, selector);
            }
            [_methods setObject:method forKey:name];

}

然後拿到WXModuleConfig組成的_moduleMap之後再發送給JS端

    [[WXSDKManager bridgeMgr] registerModules:dict];

這裡就是前面提到的呼叫JSContext的invokeMethod把內容傳送到JS端

最後需要自己callNative的回撥,當JS呼叫時就會傳值到這裡

- (void)registerCallNative:(WXJSCallNative)callNative
{
    NSInteger (^callNativeBlock)(JSValue *, JSValue *, JSValue *) = ^(JSValue *instance, JSValue *tasks, JSValue *callback){
        NSString *instanceId = [instance toString];
        NSArray *tasksArray = [tasks toArray];
        NSString *callbackId = [callback toString];
        
        return callNative(instanceId, tasksArray, callbackId);
    };
    
    _jsContext[@"callNative"] = callNativeBlock;
}

tasks裡面包括方法的一些相關資訊,包括module(比如dom),method(比如updateFinish),args

weex-devtool-iOS 其實是 PonyDebugger的衍生品。