blob: 8b7e3cf083dcc160472fd92ccac0ded20a798592 [file] [log] [blame]
/**
* 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 "WXDebugDomainController.h"
#import "WXDevToolType.h"
#import "WXDeviceInfo.h"
#import "WXDebuggerUtility.h"
#import "WXMonitorHandler.h"
#import <WeexSDK/WeexSDK.h>
#define SYNCRETURN @"WxDebug.syncReturn"
@implementation WXDebugDomainController {
NSThread *_bridgeThread;
WXJSCallNative _nativeCallBlock;
WXJSCallAddElement _callAddElementBlock;
WXJSCallCreateBody _callCreateBodyBlock;
WXJSCallRemoveElement _callRemoveElementBlock;
WXJSCallMoveElement _callMoveElementBlock;
WXJSCallUpdateAttrs _callUpdateAttrsBlock;
WXJSCallUpdateStyle _callUpdateStyleBlock;
WXJSCallAddEvent _callAddEventBlock;
WXJSCallRemoveEvent _callRemoveEventBlock;
WXJSCallCreateFinish _callCreateFinishBlock;
WXJSCallNativeModule _nativeModuleBlock;
WXJSCallNativeComponent _nativeComponentBlock;
}
@dynamic domain;
+ (WXDebugDomainController *)defaultInstance {
static WXDebugDomainController *defaultInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
defaultInstance = [[WXDebugDomainController alloc] init];
});
return defaultInstance;
}
- (id)init;
{
self = [super init];
if (!self) {
return nil;
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationIsDebug:) name:@"WXDevtoolDebug" object:nil];
return self;
}
+ (Class)domainClass {
return [WXDebugDomain class];
}
+ (NSDictionary *)getLogLevelMap {
NSDictionary *logLevelEnumToString =
@{
@"all":@(WXLogLevelDebug),
@"error":@(WXLogLevelError),
@"warn":@(WXLogLevelWarning),
@"info":@(WXLogLevelInfo),
@"log":@(WXLogLevelLog),
@"debug":@(WXLogLevelDebug),
@"off":@(WXLogLevelOff)
};
return logLevelEnumToString;
}
- (void)registerDevice {
NSString *deviceID = [WXDeviceInfo getDeviceID];
NSString *machine = [WXDeviceInfo deviceName] ? : @"";
NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"] ?: [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithObjectsAndKeys:
deviceID, @"deviceId",
@"iOS", @"platform",
machine, @"model",
[WXSDKEngine SDKEngineVersion],@"weexVersion",
[WXDevTool WXDevtoolVersion],@"devtoolVersion",
[WXDebugger isVDom] ? @"vdom" : @"native",@"elementMode",
appName, @"name",
[WXLog logLevelString] ?: @"error",@"logLevel",
[NSNumber numberWithBool:[WXDevToolType isDebug]],@"remoteDebug",
[WXDebugger isNetwork], @"network",
nil];
[self _registerDeviceWithParams:parameters];
}
- (void)debugDomainRegisterCallNative:(WXJSCallNative)callNativeBlock {
[self _initBridgeThread];
_nativeCallBlock = callNativeBlock;
}
- (void)debugDomainRegisterCallAddElement:(WXJSCallAddElement)callAddElement {
_callAddElementBlock = callAddElement;
}
- (void)debugDomainRegisterCallCreateBody:(WXJSCallCreateBody)callCreateBody {
_callCreateBodyBlock = callCreateBody;
}
- (void)debugDomainRegisterCallRemoveElement:(WXJSCallRemoveElement)callRemoveElement {
_callRemoveElementBlock = callRemoveElement;
}
- (void)debugDomainRegisterCallMoveElement:(WXJSCallMoveElement)callMoveElement {
_callMoveElementBlock = callMoveElement;
}
- (void)debugDomainRegisterCallUpdateAttrs:(WXJSCallUpdateAttrs)callUpdateAttrs {
_callUpdateAttrsBlock = callUpdateAttrs;
}
- (void)debugDomainRegisterCallUpdateStyle:(WXJSCallUpdateStyle)callUpdateStyle {
_callUpdateStyleBlock = callUpdateStyle;
}
- (void)debugDomainRegisterCallAddEvent:(WXJSCallAddEvent)callAddEvent {
_callAddEventBlock = callAddEvent;
}
- (void)debugDomainRegisterCallRemoveEvent:(WXJSCallRemoveEvent)callRemoveEvent {
_callRemoveEventBlock = callRemoveEvent;
}
- (void)debugDomainRegisterCallCreateFinish:(WXJSCallCreateFinish)callCreateFinish {
_callCreateFinishBlock = callCreateFinish;
}
- (void)debugDomainRegisterCallNativeModule:(WXJSCallNativeModule)callNativeModuleBlock {
_nativeModuleBlock = callNativeModuleBlock;
}
- (void)debugDomainRegisterCallNativeComponent:(WXJSCallNativeComponent)callNativeComponentBlock {
_nativeComponentBlock = callNativeComponentBlock;
}
- (void)clearGarbage {
_nativeCallBlock = nil;
_callAddElementBlock = nil;
_nativeModuleBlock = nil;
_nativeComponentBlock = nil;
}
#pragma mark - private methods
- (void)_initBridgeThread {
_bridgeThread = [NSThread currentThread];
}
- (void)_executeBridgeThead:(dispatch_block_t)block
{
if([NSThread currentThread] == _bridgeThread) {
block();
} else if (_bridgeThread){
[self performSelector:@selector(_executeBridgeThead:)
onThread:_bridgeThread
withObject:[block copy]
waitUntilDone:NO];
}
}
- (void)_registerDeviceWithParams:(id)params {
NSDictionary *obj = [[NSDictionary alloc] initWithObjectsAndKeys:
@"WxDebug.registerDevice", @"method",
[params WX_JSONObject], @"params",
[NSNumber numberWithInt:0],@"id",
nil];
NSData *data = [NSJSONSerialization dataWithJSONObject:obj options:0 error:nil];
NSString *encodedData = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
[[WXDebugger defaultInstance] sendDebugMessage:encodedData onBridgeThread:_bridgeThread ? YES : NO];
}
#pragma mark - notification
- (void)notificationIsDebug:(NSNotification *)notification {
if ([notification.object boolValue]) {
_bridgeThread = nil;
}
}
#pragma mark - WXCommandDelegate
- (void)domain:(WXDynamicDebuggerDomain *)domain enableWithCallback:(void (^)(id error))callback {
dispatch_async(dispatch_get_main_queue(), ^{
[WXDevToolType setDebug:YES];
[WXSDKEngine restart];
});
[self performSelector:@selector(enableWithCallback:) withObject:callback afterDelay:1];
}
-(void)enableWithCallback:(void (^)(id error))callback{
[[NSNotificationCenter defaultCenter] postNotificationName:@"RefreshInstance" object:nil];
callback(nil);
}
- (void)domain:(WXDynamicDebuggerDomain *)domain disableWithCallback:(void (^)(id error))callback {
dispatch_async(dispatch_get_main_queue(), ^{
[WXDevToolType setDebug:NO];
[WXSDKEngine restart];
[self clearGarbage];
});
[self performSelector:@selector(disableWithCallback:) withObject:callback afterDelay:1];
}
-(void)disableWithCallback:(void (^)(id error))callback{
[[NSNotificationCenter defaultCenter] postNotificationName:@"RefreshInstance" object:nil];
callback(nil);
}
- (void)domain:(WXDebugDomain *)domain sendLogLevel:(NSString *)level withCallback:(void (^)(id error))callback {
NSDictionary *logLevelMap = [WXDebugDomainController getLogLevelMap];
WXLogLevel wxLogLevel = [[logLevelMap objectForKey:level] integerValue];
[WXLog setLogLevel:wxLogLevel];
callback(nil);
}
- (void)domain:(WXDebugDomain *)domain setInspectorMode:(NSString *)mode withCallback:(void (^)(id error))callback {
if ([mode isEqualToString:@"native"]) {
[WXDebugger setVDom:NO];
} else if ([mode isEqualToString:@"vdom"]) {
[WXDebugger setVDom:YES];
}
}
- (void)domain:(WXDynamicDebuggerDomain *)domain refreshCallback:(void (^)(id error))callback {
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:@"RefreshInstance" object:nil];
});
callback(nil);
}
- (void)domain:(WXDynamicDebuggerDomain *)domain reloadCallback:(void (^)(id error))callback {
dispatch_async(dispatch_get_main_queue(), ^{
[WXSDKEngine restart];
[[NSNotificationCenter defaultCenter] postNotificationName:@"RefreshInstance" object:nil];
});
}
- (void)domain:(WXDynamicDebuggerDomain *)domain enableNetwork:(BOOL)enable networkCallback:(void (^)(id error))callback {
WXDebugger *debugger = [WXDebugger defaultInstance];
if (enable) {
[debugger enableNetworkTrafficDebugging];
[debugger forwardAllNetworkTraffic];
}
}
- (void)domain:(WXDynamicDebuggerDomain *)domain callNative:(NSDictionary *)jsModule callBack:(void (^)(id error))callback {
[self _executeBridgeThead:^{
NSString *instanceId = jsModule[@"instance"];
NSArray *methods = jsModule[@"tasks"];
NSString *callbackId = jsModule[@"callback"];
// params parse
if(!methods || methods.count <= 0){
return;
}
//call native
WXLogInfo(@"Calling native... instancdId:%@, methods:%@, callbackId:%@", instanceId, [WXUtility JSONString:methods], callbackId);
if(_nativeCallBlock){
_nativeCallBlock(instanceId, methods, callbackId);
}
callback(nil);
}];
}
- (void)domain:(WXDynamicDebuggerDomain *)domain callAddElement:(NSDictionary *)jsModule callBack:(void (^)(id error))callback {
[self _executeBridgeThead:^{
NSString *instanceId = jsModule[@"instance"] ? : @"";
NSDictionary *componentData = jsModule[@"dom"] ? : [NSDictionary dictionary];
NSString *parentRef = jsModule[@"ref"] ? : @"";
NSNumber *index = jsModule[@"index"] ? : [NSNumber numberWithInteger:0];
NSInteger insertIndex = index.integerValue;
WXLogDebug(@"callAddElement...%@, %@, %@, %ld", instanceId, parentRef, componentData, (long)insertIndex);
_callAddElementBlock(instanceId, parentRef, componentData, insertIndex);
callback(nil);
}];
}
- (void)domain:(WXDynamicDebuggerDomain *)domain callCreateBody:(NSDictionary *)jsModule callBack:(void (^)(id error))callback {
}
- (void)domain:(WXDynamicDebuggerDomain *)domain callRemoveElement:(NSDictionary *)jsModule callBack:(void (^)(id error))callback {
}
- (void)domain:(WXDynamicDebuggerDomain *)domain callMoveElement:(NSDictionary *)jsModule callBack:(void (^)(id error))callback {
}
- (void)domain:(WXDynamicDebuggerDomain *)domain callUpdateAttrs:(NSDictionary *)jsModule callBack:(void (^)(id error))callback {
}
- (void)domain:(WXDynamicDebuggerDomain *)domain callUpdateStyle:(NSDictionary *)jsModule callBack:(void (^)(id error))callback {
}
- (void)domain:(WXDynamicDebuggerDomain *)domain callAddEvent:(NSDictionary *)jsModule callBack:(void (^)(id error))callback {
}
- (void)domain:(WXDynamicDebuggerDomain *)domain callRemoveEvent:(NSDictionary *)jsModule callBack:(void (^)(id error))callback {
}
- (void)domain:(WXDynamicDebuggerDomain *)domain syncCall:(NSDictionary *)data callBack:(void (^)(NSDictionary *result, id error))callback; {
[self _executeBridgeThead:^{
NSArray *args = [data objectForKey:@"args"];
NSString *method = [data objectForKey:@"method"];
NSString *syncId = [data objectForKey:@"syncId"];
NSMutableDictionary *result = [[NSMutableDictionary alloc] init];
[result setObject:SYNCRETURN forKey:@"method"];
NSError *error = nil;
if ([method isEqualToString:@"callNativeModule"]) {
NSString *instanceIdString = args[0] ? : @"";
NSString *moduleNameString = args[1] ? : @"";
NSString *methodNameString = args[2] ? : @"";
NSArray *argsArray = args[3] ? : [NSArray array];
NSDictionary *optionsDic = [args[4] isKindOfClass:[NSDictionary class]]? args[4]: [NSDictionary dictionary];
WXLog(@"callNativeModule...%@,%@,%@,%@", instanceIdString, moduleNameString, methodNameString, argsArray);
if(_nativeModuleBlock){
NSInvocation *invocation = _nativeModuleBlock(instanceIdString, moduleNameString, methodNameString, argsArray, optionsDic);
id object = [WXDebuggerUtility switchInvocationReture:invocation];
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
[params setObject:syncId forKey:@"syncId"];
if (object) {
[params setObject:object forKey:@"ret"];
}else {
error = [[NSError alloc] init];
}
[result setObject:params forKey:@"params"];
}else{
error = [NSError errorWithDomain:(NSErrorDomain)@"callNativeModule error" code:500 userInfo:nil];
}
}else if ([method isEqualToString:@"callNativeComponent"]) {
NSString *instanceIdString = args[0] ? : @"";
NSString *componentNameString = args[1] ? : @"";
NSString *methodNameString = args[2] ? : @"";
NSArray *argsArray = args[3] ? : [NSArray array];
NSDictionary *optionsDic = args[4] ? : [NSDictionary dictionary];
WXLog(@"callNativeComponent...%@,%@,%@,%@", instanceIdString, componentNameString, methodNameString, argsArray);
_nativeComponentBlock(instanceIdString, componentNameString, methodNameString, argsArray, optionsDic);
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
[result setObject:params forKey:@"params"];
}else if([method isEqualToString:@"extendCallNative"]) {
id value = [NSDictionary new];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
Class propertyClass = NSClassFromString(@"WXExtendCallNativeManager");
SEL sel =NSSelectorFromString(@"sendExtendCallNativeEvent:");
if(propertyClass && [propertyClass respondsToSelector:sel]){
value = [propertyClass performSelector:sel withObject:data[@"value"]];
}
#pragma clang diagnostic pop
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
[params setObject:value forKey:@"ret"];
[result setObject:params forKey:@"params"];
} else if([method isEqualToString:@"btoa"]) {
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
NSData *nsdata = [data[@"value"]
dataUsingEncoding:NSUTF8StringEncoding];
NSString *base64Encoded = [nsdata base64EncodedStringWithOptions:0];
[params setObject:base64Encoded forKey:@"ret"];
[result setObject:params forKey:@"params"];
} else if([method isEqualToString:@"atob"]) {
NSData *nsdataFromBase64String = [[NSData alloc]
initWithBase64EncodedString:data[@"value"] options:0];
NSString *base64Decoded = [[NSString alloc]
initWithData:nsdataFromBase64String encoding:NSUTF8StringEncoding];
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
[params setObject:base64Decoded forKey:@"ret"];
[result setObject:params forKey:@"params"];
}
callback(result, error);
}];
}
- (void)domain:(WXDynamicDebuggerDomain *)domain enablePerformanceMonitor:(BOOL)enable monitorCallback:(void (^)(id error))callback {
[WXAnalyzerCenter setOpen: enable];
if (enable) {
[WXAnalyzerCenter addWxAnalyzer:[WXMonitorHandler sharedInstance]];
if ([WXDebugTool isDebug]) {
[WXDebugTool setDebug:false];
}
}else {
[WXAnalyzerCenter rmWxAnalyzer:[WXMonitorHandler sharedInstance]];
[WXMonitorHandler resetMonitorData];
}
}
- (void)domain:(WXDynamicDebuggerDomain *)domain sendPerformanceData:(BOOL)enable sendCallback:(void (^)(id error))callback {
NSMutableDictionary *params = nil;
NSError *error = nil;
if ([WXMonitorHandler sharedInstance]) {
params = [WXMonitorHandler sharedInstance].monitorDictionary;
}else {
error = [NSError errorWithDomain:(NSErrorDomain)@"sendPerformanceData error" code:500 userInfo:nil];
}
if ([WXDebugger defaultInstance].isConnected) {
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:@"WxDebug.sendPerformanceData" forKey:@"method"];
[dict setObject:params forKey:@"params"];
[[WXDebugger defaultInstance] sendDebugMessage:[WXUtility JSONString:dict] onBridgeThread:false];
}
callback(error);
}
@end