| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| #import "WXSDKEngine.h" |
| #import "WXDebugTool.h" |
| #import "WXModuleFactory.h" |
| #import "WXHandlerFactory.h" |
| #import "WXComponentFactory.h" |
| #import "WXBridgeManager.h" |
| |
| #import "WXAppConfiguration.h" |
| #import "WXResourceRequestHandlerDefaultImpl.h" |
| #import "WXNavigationDefaultImpl.h" |
| #import "WXURLRewriteDefaultImpl.h" |
| #import "WXJSFrameworkLoadDefaultImpl.h" |
| #import "WXDarkThemeDefaultImpl.h" |
| |
| #import "WXSDKManager.h" |
| #import "WXSDKError.h" |
| #import "WXMonitor.h" |
| #import "WXSimulatorShortcutManager.h" |
| #import "WXAssert.h" |
| #import "WXLog.h" |
| #import "WXUtility.h" |
| #import "WXExtendCallNativeManager.h" |
| #import "WXExceptionUtils.h" |
| #import "WXConfigCenterProtocol.h" |
| #import "WXComponent+Layout.h" |
| #import "WXCoreBridge.h" |
| |
| @implementation WXSDKEngine |
| |
| # pragma mark Module Register |
| |
| // register some default modules when the engine initializes. |
| + (void)_registerDefaultModules |
| { |
| [self registerModule:@"dom" withClass:NSClassFromString(@"WXDomModule")]; |
| [self registerModule:@"locale" withClass:NSClassFromString(@"WXLocaleModule")]; |
| [self registerModule:@"navigator" withClass:NSClassFromString(@"WXNavigatorModule")]; |
| [self registerModule:@"stream" withClass:NSClassFromString(@"WXStreamModule")]; |
| [self registerModule:@"animation" withClass:NSClassFromString(@"WXAnimationModule")]; |
| [self registerModule:@"modal" withClass:NSClassFromString(@"WXModalUIModule")]; |
| [self registerModule:@"webview" withClass:NSClassFromString(@"WXWebViewModule")]; |
| [self registerModule:@"instanceWrap" withClass:NSClassFromString(@"WXInstanceWrap")]; |
| [self registerModule:@"timer" withClass:NSClassFromString(@"WXTimerModule")]; |
| [self registerModule:@"storage" withClass:NSClassFromString(@"WXStorageModule")]; |
| [self registerModule:@"clipboard" withClass:NSClassFromString(@"WXClipboardModule")]; |
| [self registerModule:@"globalEvent" withClass:NSClassFromString(@"WXGlobalEventModule")]; |
| [self registerModule:@"canvas" withClass:NSClassFromString(@"WXCanvasModule")]; |
| [self registerModule:@"picker" withClass:NSClassFromString(@"WXPickerModule")]; |
| [self registerModule:@"meta" withClass:NSClassFromString(@"WXMetaModule")]; |
| [self registerModule:@"webSocket" withClass:NSClassFromString(@"WXWebSocketModule")]; |
| [self registerModule:@"voice-over" withClass:NSClassFromString(@"WXVoiceOverModule")]; |
| [self registerModule:@"sdk-console-log" withClass:NSClassFromString(@"WXConsoleLogModule")]; |
| } |
| |
| + (void)registerModule:(NSString *)name withClass:(Class)clazz |
| { |
| WXAssert(name && clazz, @"Fail to register the module, please check if the parameters are correct !"); |
| if (!clazz || !name) { |
| return; |
| } |
| NSString *moduleName = [WXModuleFactory registerModule:name withClass:clazz]; |
| NSDictionary *dict = [WXModuleFactory moduleMethodMapsWithName:moduleName]; |
| |
| [[WXSDKManager bridgeMgr] registerModules:dict]; |
| } |
| |
| # pragma mark Component Register |
| |
| + (void)_registerAffineTypes |
| { |
| /* register weex core types that should match RenderList or RenderScroller. |
| "list" and "waterfall" must be registered before "scroller" because "WXListComponent" and "WXRecyclerComponent" |
| are both subclasses of "WXScrollerComponent". |
| */ |
| [WXComponentFactory registerBaseType:@"list" withClass:NSClassFromString(@"WXListComponent")]; |
| [WXComponentFactory registerBaseType:@"waterfall" withClass:NSClassFromString(@"WXRecyclerComponent")]; |
| [WXComponentFactory registerBaseType:@"scroller" withClass:NSClassFromString(@"WXScrollerComponent")]; |
| } |
| |
| // register some default components when the engine initializes. |
| + (void)_registerDefaultComponents |
| { |
| [self registerComponent:@"container" withClass:NSClassFromString(@"WXDivComponent") withProperties:nil]; |
| [self registerComponent:@"div" withClass:NSClassFromString(@"WXComponent") withProperties:nil]; |
| [self registerComponent:@"text" withClass:NSClassFromString(@"WXTextComponent") withProperties:nil]; |
| [self registerComponent:@"image" withClass:NSClassFromString(@"WXImageComponent") withProperties:nil]; |
| [self registerComponent:@"richtext" withClass:NSClassFromString(@"WXRichText") withProperties:nil]; |
| |
| [self registerComponent:@"scroller" withClass:NSClassFromString(@"WXScrollerComponent") withProperties:nil]; |
| [self registerComponent:@"list" withClass:NSClassFromString(@"WXListComponent") withProperties:nil]; |
| [self registerComponent:@"recycler" withClass:NSClassFromString(@"WXRecyclerComponent") withProperties:nil]; |
| [self registerComponent:@"waterfall" withClass:NSClassFromString(@"WXRecyclerComponent") withProperties:nil]; |
| |
| [self registerComponent:@"header" withClass:NSClassFromString(@"WXHeaderComponent")]; |
| [self registerComponent:@"cell" withClass:NSClassFromString(@"WXCellComponent")]; |
| [self registerComponent:@"embed" withClass:NSClassFromString(@"WXEmbedComponent")]; |
| [self registerComponent:@"a" withClass:NSClassFromString(@"WXAComponent")]; |
| |
| [self registerComponent:@"select" withClass:NSClassFromString(@"WXSelectComponent")]; |
| [self registerComponent:@"switch" withClass:NSClassFromString(@"WXSwitchComponent")]; |
| [self registerComponent:@"input" withClass:NSClassFromString(@"WXTextInputComponent")]; |
| [self registerComponent:@"video" withClass:NSClassFromString(@"WXVideoComponent")]; |
| [self registerComponent:@"indicator" withClass:NSClassFromString(@"WXIndicatorComponent")]; |
| [self registerComponent:@"slider" withClass:NSClassFromString(@"WXCycleSliderComponent")]; |
| [self registerComponent:@"cycleslider" withClass:NSClassFromString(@"WXCycleSliderComponent")]; |
| [self registerComponent:@"web" withClass:NSClassFromString(@"WXWebComponent")]; |
| [self registerComponent:@"loading" withClass:NSClassFromString(@"WXLoadingComponent")]; |
| [self registerComponent:@"loading-indicator" withClass:NSClassFromString(@"WXLoadingIndicator")]; |
| [self registerComponent:@"refresh" withClass:NSClassFromString(@"WXRefreshComponent")]; |
| [self registerComponent:@"textarea" withClass:NSClassFromString(@"WXTextAreaComponent")]; |
| [self registerComponent:@"canvas" withClass:NSClassFromString(@"WXCanvasComponent")]; |
| [self registerComponent:@"slider-neighbor" withClass:NSClassFromString(@"WXSliderNeighborComponent")]; |
| |
| [self registerComponent:@"recycle-list" withClass:NSClassFromString(@"WXRecycleListComponent")]; |
| [self registerComponent:@"cell-slot" withClass:NSClassFromString(@"WXCellSlotComponent") withProperties: @{@"append":@"tree", @"isTemplate":@YES}]; |
| |
| // other non-default components should be checked with affine-base types. |
| [self _registerAffineTypes]; |
| } |
| |
| + (void)registerComponent:(NSString *)name withClass:(Class)clazz |
| { |
| [self registerComponent:name withClass:clazz withProperties: @{@"append":@"tree"}]; |
| } |
| |
| + (void)registerExtendCallNative:(NSString *)name withClass:(Class)clazz |
| { |
| [WXExtendCallNativeManager registerExtendCallNative:name withClass:clazz]; |
| } |
| |
| + (void)registerComponent:(NSString *)name withClass:(Class)clazz withProperties:(NSDictionary *)properties |
| { |
| if (!name || !clazz) { |
| return; |
| } |
| |
| WXAssert(name && clazz, @"Fail to register the component, please check if the parameters are correct !"); |
| |
| [WXComponentFactory registerComponent:name withClass:clazz withPros:properties]; |
| NSMutableDictionary *dict = [WXComponentFactory componentMethodMapsWithName:name]; |
| dict[@"type"] = name; |
| if (properties) { |
| NSMutableDictionary *props = [properties mutableCopy]; |
| if ([dict[@"methods"] count]) { |
| [props addEntriesFromDictionary:dict]; |
| } |
| [[WXSDKManager bridgeMgr] registerComponents:@[props]]; |
| } else { |
| [[WXSDKManager bridgeMgr] registerComponents:@[dict]]; |
| } |
| } |
| |
| |
| # pragma mark Service Register |
| |
| + (void)registerService:(NSString *)name withScript:(NSString *)serviceScript withOptions:(NSDictionary *)options |
| { |
| [[WXSDKManager bridgeMgr] registerService:name withService:serviceScript withOptions:options completion:nil]; |
| } |
| |
| + (void)registerService:(NSString *)name withScript:(NSString *)serviceScript withOptions:(NSDictionary *)options completion:(void(^)(BOOL result))completion |
| { |
| [[WXSDKManager bridgeMgr] registerService:name withService:serviceScript withOptions:options completion:completion]; |
| } |
| |
| + (void)registerService:(NSString *)name withScriptUrl:(NSURL *)serviceScriptUrl withOptions:(NSDictionary *)options |
| { |
| [[WXSDKManager bridgeMgr] registerService:name withServiceUrl:serviceScriptUrl withOptions:options completion:nil]; |
| } |
| |
| + (void)registerService:(NSString *)name withScriptUrl:(NSURL *)serviceScriptUrl withOptions:(NSDictionary *)options completion:(void(^)(BOOL result))completion |
| { |
| [[WXSDKManager bridgeMgr] registerService:name withServiceUrl:serviceScriptUrl withOptions:options completion:completion]; |
| } |
| |
| + (void)unregisterService:(NSString *)name |
| { |
| [[WXSDKManager bridgeMgr] unregisterService:name]; |
| } |
| |
| # pragma mark Handler Register |
| |
| // register some default handlers when the engine initializes. |
| + (void)_registerDefaultHandlers |
| { |
| [self registerHandler:[WXResourceRequestHandlerDefaultImpl new] withProtocol:@protocol(WXResourceRequestHandler)]; |
| [self registerHandler:[WXNavigationDefaultImpl new] withProtocol:@protocol(WXNavigationProtocol)]; |
| [self registerHandler:[WXURLRewriteDefaultImpl new] withProtocol:@protocol(WXURLRewriteProtocol)]; |
| [self registerHandler:[WXJSFrameworkLoadDefaultImpl new] withProtocol:@protocol(WXJSFrameworkLoadProtocol)]; |
| [self registerHandler:[WXDarkThemeDefaultImpl new] withProtocol:@protocol(WXDarkThemeProtocol)]; |
| } |
| |
| + (void)registerHandler:(id)handler withProtocol:(Protocol *)protocol |
| { |
| WXAssert(handler && protocol, @"Fail to register the handler, please check if the parameters are correct !"); |
| |
| [WXHandlerFactory registerHandler:handler withProtocol:protocol]; |
| } |
| |
| + (id)handlerForProtocol:(Protocol *)protocol |
| { |
| WXAssert(protocol, @"Fail to get the handler, please check if the parameters are correct !"); |
| |
| return [WXHandlerFactory handlerForProtocol:protocol]; |
| } |
| |
| # pragma mark SDK Initialize |
| |
| + (void)initSDKEnvironment |
| { |
| NSString *fileName = @"weex-main-jsfm"; |
| NSString *filePath = [[NSBundle bundleForClass:self] pathForResource:fileName ofType:@"js"]; |
| if (filePath == nil) { |
| filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:@"js"]; |
| } |
| NSString *script = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; |
| [WXSDKEngine initSDKEnvironment:script]; |
| |
| #if TARGET_OS_SIMULATOR |
| static dispatch_once_t onceToken; |
| dispatch_once(&onceToken, ^{ |
| [WXSimulatorShortcutManager registerSimulatorShortcutWithKey:@"i" modifierFlags:UIKeyModifierCommand | UIKeyModifierAlternate action:^{ |
| NSURL *URL = [NSURL URLWithString:@"http://localhost:8687/launchDebugger"]; |
| NSURLRequest *request = [NSURLRequest requestWithURL:URL]; |
| |
| NSURLSession *session = [NSURLSession sharedSession]; |
| NSURLSessionDataTask *task = [session dataTaskWithRequest:request |
| completionHandler: |
| ^(NSData *data, NSURLResponse *response, NSError *error) { |
| // ... |
| }]; |
| |
| [task resume]; |
| WXLogInfo(@"Launching browser..."); |
| |
| dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ |
| [self connectDebugServer:@"ws://localhost:8687/debugger/0/renderer"]; |
| }); |
| |
| }]; |
| }); |
| #endif |
| } |
| |
| + (void)initSDKEnvironment:(NSString *)script |
| { |
| WX_MONITOR_PERF_START(WXPTInitalize) |
| WX_MONITOR_PERF_START(WXPTInitalizeSync) |
| |
| if (!script || script.length <= 0) { |
| NSMutableString *errMsg = [NSMutableString stringWithFormat:@"[WX_KEY_EXCEPTION_SDK_INIT_JSFM_INIT_FAILED] script don't exist:%@",script]; |
| [WXExceptionUtils commitCriticalExceptionRT:@"WX_KEY_EXCEPTION_SDK_INIT" errCode:[NSString stringWithFormat:@"%d", WX_KEY_EXCEPTION_SDK_INIT] function:@"initSDKEnvironment" exception:errMsg extParams:nil]; |
| WX_MONITOR_FAIL(WXMTJSFramework, WX_ERR_JSFRAMEWORK_LOAD, errMsg); |
| return; |
| } |
| static dispatch_once_t onceToken; |
| dispatch_once(&onceToken, ^{ |
| [self registerDefaults]; |
| [[WXSDKManager bridgeMgr] executeJsFramework:script]; |
| }); |
| |
| WX_MONITOR_PERF_END(WXPTInitalizeSync) |
| |
| } |
| |
| + (void)registerDefaults |
| { |
| static dispatch_once_t onceToken; |
| dispatch_once(&onceToken, ^{ |
| [self _loadRenderPlugins]; |
| [self _registerDefaultComponents]; |
| [self _registerDefaultModules]; |
| [self _registerDefaultHandlers]; |
| }); |
| } |
| |
| + (void)_loadRenderPlugins |
| { |
| // Load agil render |
| Class agilRender = NSClassFromString(@"WXAgilRender"); |
| if (agilRender) { |
| [agilRender initialize]; |
| } |
| } |
| |
| + (NSString*)SDKEngineVersion |
| { |
| return WX_SDK_VERSION; |
| } |
| |
| + (WXSDKInstance *)topInstance |
| { |
| return [WXSDKManager bridgeMgr].topInstance; |
| } |
| |
| |
| static NSDictionary *_customEnvironment = nil; |
| + (void)setCustomEnvironment:(NSDictionary *)environment |
| { |
| @synchronized (self) { |
| _customEnvironment = [environment copy]; |
| } |
| } |
| |
| + (NSDictionary *)customEnvironment |
| { |
| NSDictionary* result = nil; |
| @synchronized (self) { |
| result = [_customEnvironment copy]; |
| } |
| return result; |
| } |
| |
| # pragma mark Debug |
| |
| + (void)unload |
| { |
| [WXSDKManager unload]; |
| [WXComponentFactory unregisterAllComponents]; |
| } |
| |
| + (void)restart |
| { |
| NSString *fileName = @"weex-main-jsfm"; |
| NSString *filePath = [[NSBundle bundleForClass:self] pathForResource:fileName ofType:@"js"]; |
| if (filePath == nil) { |
| filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:@"js"]; |
| } |
| NSString *script = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; |
| [self restartWithScript:script]; |
| } |
| |
| + (void)restartWithScript:(NSString*)script |
| { |
| NSDictionary *components = [WXComponentFactory componentConfigs]; |
| NSDictionary *modules = [WXModuleFactory moduleConfigs]; |
| NSDictionary *handlers = [WXHandlerFactory handlerConfigs]; |
| [WXSDKManager unload]; |
| [WXComponentFactory unregisterAllComponents]; |
| |
| [self _originalRegisterComponents:components]; |
| [self _originalRegisterModules:modules]; |
| [self _originalRegisterHandlers:handlers]; |
| |
| [[WXSDKManager bridgeMgr] executeJsFramework:script]; |
| |
| NSDictionary *jsSerices = [WXDebugTool jsServiceCache]; |
| for(NSString *serviceName in jsSerices) { |
| NSDictionary *service = [jsSerices objectForKey:serviceName]; |
| NSString *serviceName = [service objectForKey:@"name"]; |
| NSString *serviceScript = [service objectForKey:@"script"]; |
| NSDictionary *serviceOptions = [service objectForKey:@"options"]; |
| [WXSDKEngine registerService:serviceName withScript:serviceScript withOptions:serviceOptions]; |
| } |
| } |
| |
| + (void)connectDebugServer:(NSString*)URL |
| { |
| [[WXSDKManager bridgeMgr] connectToWebSocket:[NSURL URLWithString:URL]]; |
| } |
| |
| + (void)connectDevToolServer:(NSString *)URL |
| { |
| [[WXSDKManager bridgeMgr] connectToDevToolWithUrl:[NSURL URLWithString:URL]]; |
| } |
| |
| + (void)setGlobalDeviceSize:(CGSize)size |
| { |
| [WXCoreBridge setDeviceSize:size]; |
| } |
| |
| + (CGSize)getGlobalDeviceSize |
| { |
| return [WXCoreBridge getDeviceSize]; |
| } |
| |
| + (void)_originalRegisterComponents:(NSDictionary *)components { |
| NSMutableDictionary * mutableComponents = [components mutableCopy]; |
| void (^componentBlock)(id, id, BOOL *) = ^(id mKey, id mObj, BOOL * mStop) { |
| NSString *name = mObj[@"name"]; |
| NSString *componentClass = mObj[@"clazz"]; |
| NSDictionary *pros = nil; |
| if (mObj[@"pros"]) { |
| pros = mObj[@"pros"]; |
| } |
| [self registerComponent:name withClass:NSClassFromString(componentClass) withProperties:pros]; |
| }; |
| [mutableComponents enumerateKeysAndObjectsUsingBlock:componentBlock]; |
| } |
| |
| + (void)_originalRegisterModules:(NSDictionary *)modules { |
| NSMutableDictionary * mutableModules = [modules mutableCopy]; |
| void (^moduleBlock)(id, id, BOOL *) = ^(id mKey, id mObj, BOOL * mStop) { |
| |
| [self registerModule:mKey withClass:NSClassFromString(mObj)]; |
| }; |
| [mutableModules enumerateKeysAndObjectsUsingBlock:moduleBlock]; |
| } |
| |
| + (void)_originalRegisterHandlers:(NSDictionary *)handlers { |
| NSMutableDictionary * mutableHandlers = [handlers mutableCopy]; |
| void (^handlerBlock)(id, id, BOOL *) = ^(id mKey, id mObj, BOOL * mStop) { |
| [self registerHandler:mObj withProtocol:NSProtocolFromString(mKey)]; |
| }; |
| [mutableHandlers enumerateKeysAndObjectsUsingBlock:handlerBlock]; |
| } |
| |
| @end |
| |
| @implementation WXSDKEngine (Deprecated) |
| |
| + (void)initSDKEnviroment |
| { |
| [self initSDKEnvironment]; |
| } |
| |
| + (void)initSDKEnviroment:(NSString *)script |
| { |
| [self initSDKEnvironment:script]; |
| } |
| |
| @end |