WXSDKInstance -> WXBridgeManager->WXBridgeContext->WXJSCoreBridge
->JSContext WXSDKInstance -> WXComponentManager
WXBridgeManager : 对WXBridgeContext进一步封装,提供JS API调用,JS 事件发送,注册Native Call Handler,注册Native模块Handler、注册Native组件Handler、注册Native服务Handler等接口。提供Bridge独立线程,上述接口基本上都在该线程中执行。
WXComponentManager :管理着组件的布局,样式等
// WXComponentManager.mm
- (void)_layoutAndSyncUI
{
[self _layout];
if(_uiTaskQueue.count > 0){
[self _syncUITasks];
_noTaskTickCount = 0;
} else {
// suspend display link when there's no task for 1 second, in order to save CPU time.
_noTaskTickCount ++;
if (_noTaskTickCount > 60) {
[self _suspendDisplayLink];
}
}
}
- (void)_layout
{
BOOL needsLayout = NO;
needsLayout = [_rootComponent needsLayout];
if (!needsLayout) {
return;
}
#ifdef DEBUG
WXLogDebug(@"flexLayout -> action__ calculateLayout root");
#endif
std::pair<float, float> renderPageSize;
renderPageSize.first = self.weexInstance.frame.size.width;
renderPageSize.second = self.weexInstance.frame.size.height;
_rootFlexCSSNode->calculateLayout(renderPageSize);
NSMutableSet<WXComponent *> *dirtyComponents = [NSMutableSet set];
[_rootComponent _calculateFrameWithSuperAbsolutePosition:CGPointZero gatherDirtyComponents:dirtyComponents];
[self _calculateRootFrame];
for (WXComponent *dirtyComponent in dirtyComponents) {
[self _addUITask:^{
[dirtyComponent _layoutDidFinish];
}];
}
}
WXSDKInstance : 加载bundle文件,管理、渲染根视图。
WXSDKManager :管理WXSDKInstance多实例
//WXSDKInstance.m
- (void)_renderWithMainBundleString:(NSString *)mainBundleString
{
if (!self.instanceId) {
WXLogError(@"Fail to find instance!");
return;
}
self.performance.renderTimeOrigin = CACurrentMediaTime()*1000;
if (![WXUtility isBlankString:self.pageName]) {
WXLog(@"Start rendering page:%@", self.pageName);
} else {
WXLogWarning(@"WXSDKInstance's pageName should be specified.");
id<WXJSExceptionProtocol> jsExceptionHandler = [WXHandlerFactory handlerForProtocol:@protocol(WXJSExceptionProtocol)];
if ([jsExceptionHandler respondsToSelector:@selector(onRuntimeCheckException:)]) {
WXRuntimeCheckException * runtimeCheckException = [WXRuntimeCheckException new];
runtimeCheckException.exception = @"We highly recommend you to set pageName.\n Using WXSDKInstance * instance = [WXSDKInstance new]; instance.pageName = @\"your page name\" to fix it";
[jsExceptionHandler onRuntimeCheckException:runtimeCheckException];
}
}
if (!self.userInfo) {
self.userInfo = [NSMutableDictionary new];
}
if (!self.userInfo[@"jsMainBundleStringContentLength"]) {
self.userInfo[@"jsMainBundleStringContentLength"] = @([mainBundleString length]);
}
if (!self.userInfo[@"jsMainBundleStringContentLength"]) {
self.userInfo[@"jsMainBundleStringContentMd5"] = [WXUtility md5:mainBundleString];
}
id<WXPageEventNotifyEventProtocol> pageEvent = [WXSDKEngine handlerForProtocol:@protocol(WXPageEventNotifyEventProtocol)];
if ([pageEvent respondsToSelector:@selector(pageStart:)]) {
[pageEvent pageStart:self.instanceId];
}
WX_MONITOR_INSTANCE_PERF_START(WXPTFirstScreenRender, self);
WX_MONITOR_INSTANCE_PERF_START(WXPTAllRender, self);
NSMutableDictionary *dictionary = [_options mutableCopy];
if ([WXLog logLevel] >= WXLogLevelLog) {
dictionary[@"debug"] = @(YES);
}
if ([WXDebugTool getReplacedBundleJS]) {
mainBundleString = [WXDebugTool getReplacedBundleJS];
}
//TODO WXRootView
WXPerformBlockOnMainThread(^{
_rootView = [[WXRootView alloc] initWithFrame:self.frame];
_rootView.instance = self;
if(self.onCreate) {
self.onCreate(_rootView);
}
});
// ensure default modules/components/handlers are ready before create instance
[WXSDKEngine registerDefaults];
[[NSNotificationCenter defaultCenter] postNotificationName:WX_SDKINSTANCE_WILL_RENDER object:self];
_needDestroy = YES;
_mainBundleString = mainBundleString;
if ([self _handleConfigCenter]) {
NSError * error = [NSError errorWithDomain:WX_ERROR_DOMAIN code:9999 userInfo:nil];
if (self.onFailed) {
self.onFailed(error);
}
return;
}
_needDestroy = YES;
[WXTracingManager startTracingWithInstanceId:self.instanceId ref:nil className:nil name:WXTExecJS phase:WXTracingBegin functionName:@"renderWithMainBundleString" options:@{@"threadName":WXTMainThread}];
[[WXSDKManager bridgeMgr] createInstance:self.instanceId template:mainBundleString options:dictionary data:_jsData];
[WXTracingManager startTracingWithInstanceId:self.instanceId ref:nil className:nil name:WXTExecJS phase:WXTracingEnd functionName:@"renderWithMainBundleString" options:@{@"threadName":WXTMainThread}];
WX_MONITOR_PERF_SET(WXPTBundleSize, [mainBundleString lengthOfBytesUsingEncoding:NSUTF8StringEncoding], self);
}
//WXBridgeProtocol.h
@protocol WXBridgeProtocol <NSObject>
@property (nonatomic, readonly) JSValue* exception;
/**
* Executes the js framework code in javascript engine
* You can do some setup in this method
*/
- (void)executeJSFramework:(NSString *)frameworkScript;
/**
* Executes the js code in javascript engine
* You can do some setup in this method
*/
- (void)executeJavascript:(NSString *)script;
/**
* Executes global js method with specific arguments
*/
- (JSValue *)callJSMethod:(NSString *)method args:(NSArray*)args;
/**
* Register callback when call native tasks occur
*/
- (void)registerCallNative:(WXJSCallNative)callNative;
/**
* Reset js engine environment, called when any environment variable is changed.
*/
- (void)resetEnvironment;
// WXJSCoreBridge.m
- (void)executeJSFramework:(NSString *)frameworkScript
{
WXAssertParam(frameworkScript);
if (WX_SYS_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) {
NSString * fileName = @"native-bundle-main.js";
if ([WXSDKManager sharedInstance].multiContext) {
fileName = @"weex-main-jsfm.js";
}
[_jsContext evaluateScript:frameworkScript withSourceURL:[NSURL URLWithString:fileName]];
}else{
[_jsContext evaluateScript:frameworkScript];
}
}
- (JSValue *)callJSMethod:(NSString *)method args:(NSArray *)args
{
WXLogDebug(@"Calling JS... method:%@, args:%@", method, args);
return [[_jsContext globalObject] invokeMethod:method withArguments:args];
}
- (void)registerCallNative:(WXJSCallNative)callNative
{
JSValue* (^callNativeBlock)(JSValue *, JSValue *, JSValue *) = ^JSValue*(JSValue *instance, JSValue *tasks, JSValue *callback){
NSString *instanceId = [instance toString];
NSArray *tasksArray = [tasks toArray];
NSString *callbackId = [callback toString];
WXLogDebug(@"Calling native... instance:%@, tasks:%@, callback:%@", instanceId, tasksArray, callbackId);
return [JSValue valueWithInt32:(int32_t)callNative(instanceId, tasksArray, callbackId) inContext:[JSContext currentContext]];
};
_jsContext[@"callNative"] = callNativeBlock;
}