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的衍生品。