diff --git a/framework/ios/base/bridge/HippyBridge.h b/framework/ios/base/bridge/HippyBridge.h index 36402a6168b..836e51f9ca5 100644 --- a/framework/ios/base/bridge/HippyBridge.h +++ b/framework/ios/base/bridge/HippyBridge.h @@ -318,8 +318,11 @@ HIPPY_EXTERN NSString *HippyBridgeModuleNameForClass(Class bridgeModuleClass); /// All registered bridge module classes. @property (nonatomic, copy, readonly) NSArray *moduleClasses; -- (NSString *)moduleConfig; +/// Get all native module info. +- (NSDictionary *)nativeModuleConfig; +/// Get config info for given module name +/// - Parameter moduleName: name of module - (NSArray *)configForModuleName:(NSString *)moduleName; - (BOOL)moduleSetupComplete; @@ -350,9 +353,8 @@ HIPPY_EXTERN NSString *HippyBridgeModuleNameForClass(Class bridgeModuleClass); */ - (BOOL)moduleIsInitialized:(Class)moduleClass; -/** - * Get the turbo module for a given name. - */ +/// Get turbo module by name. +/// - Parameter name: name of turbo module - (id)turboModuleWithName:(NSString *)name; diff --git a/framework/ios/base/bridge/HippyBridge.mm b/framework/ios/base/bridge/HippyBridge.mm index 26e02abe01f..e5517b92c36 100644 --- a/framework/ios/base/bridge/HippyBridge.mm +++ b/framework/ios/base/bridge/HippyBridge.mm @@ -25,7 +25,6 @@ #import "HippyBundleLoadOperation.h" #import "HippyBundleExecutionOperation.h" #import "HippyBundleOperationQueue.h" -#import "HippyContextWrapper.h" #import "HippyDeviceBaseInfo.h" #import "HippyDisplayLink.h" #import "HippyEventDispatcher.h" @@ -103,6 +102,10 @@ static NSString *const HippyNativeGlobalKeyLocalization = @"Localization"; static NSString *const HippyNativeGlobalKeyNightMode = @"NightMode"; +// key of module config info for js side +static NSString *const kHippyRemoteModuleConfigKey = @"remoteModuleConfig"; +static NSString *const kHippyBatchedBridgeConfigKey = @"__hpBatchedBridgeConfig"; + typedef NS_ENUM(NSUInteger, HippyBridgeFields) { HippyBridgeFieldRequestModuleIDs = 0, @@ -309,6 +312,9 @@ - (void)setUpNativeRenderManager { return _uriLoader; } + +#pragma mark - Module Management + - (NSArray *)moduleClasses { return _moduleSetup.moduleClasses; } @@ -345,6 +351,35 @@ - (BOOL)moduleIsInitialized:(Class)moduleClass { return [_moduleSetup isModuleInitialized:moduleClass]; } +- (BOOL)moduleSetupComplete { + return _moduleSetup.isModuleSetupComplete; +} + +- (NSDictionary *)nativeModuleConfig { + NSMutableArray *config = [NSMutableArray new]; + for (HippyModuleData *moduleData in [_moduleSetup moduleDataByID]) { + NSArray *moduleDataConfig = [moduleData config]; + [config addObject:HippyNullIfNil(moduleDataConfig)]; + } + return @{ kHippyRemoteModuleConfigKey : config }; +} + +- (NSArray *)configForModuleName:(NSString *)moduleName { + HippyModuleData *moduleData = [_moduleSetup moduleDataByName][moduleName]; + return moduleData.config; +} + +- (HippyOCTurboModule *)turboModuleWithName:(NSString *)name { + if (!self.enableTurbo || name.length <= 0) { + return nil; + } + + if (!self.turboModuleManager) { + self.turboModuleManager = [[HippyTurboModuleManager alloc] initWithBridge:self]; + } + return [self.turboModuleManager turboModuleWithName:name]; +} + #pragma mark - Image Config Related @@ -412,12 +447,14 @@ - (void)setUp { __weak HippyBridge *weakSelf = self; _moduleSetup = [[HippyModulesSetup alloc] initWithBridge:self extraProviderModulesBlock:_moduleProvider]; _javaScriptExecutor = [[HippyJSExecutor alloc] initWithEngineKey:self.engineKey bridge:self]; - _javaScriptExecutor.contextCreatedBlock = ^(id ctxWrapper){ - HippyBridge *strongSelf = weakSelf; + + _javaScriptExecutor.contextCreatedBlock = ^(){ + __strong __typeof(weakSelf)strongSelf = weakSelf; if (strongSelf) { dispatch_semaphore_wait(strongSelf.moduleSemaphore, DISPATCH_TIME_FOREVER); - NSString *moduleConfig = [strongSelf moduleConfig]; - [ctxWrapper createGlobalObject:@"__hpBatchedBridgeConfig" withJsonValue:moduleConfig]; + NSDictionary *nativeModuleConfig = [strongSelf nativeModuleConfig]; + [strongSelf.javaScriptExecutor injectObjectSync:nativeModuleConfig + asGlobalObjectNamed:kHippyBatchedBridgeConfigKey callback:nil]; #if HIPPY_DEV //default is yes when debug mode [strongSelf setInspectable:YES]; @@ -1016,10 +1053,6 @@ - (BOOL)isLoading { return 0 == count; } -- (BOOL)moduleSetupComplete { - return _moduleSetup.isModuleSetupComplete; -} - - (void)invalidate { HippyLogInfo(@"[Hippy_OC_Log][Life_Circle],%@ invalide %p", NSStringFromClass([self class]), self); if (![self isValid]) { @@ -1163,18 +1196,6 @@ - (void)setOSNightMode:(BOOL)isOSNightMode withRootViewTag:(nonnull NSNumber *)r #pragma mark - -- (NSString *)moduleConfig { - NSMutableArray *config = [NSMutableArray new]; - for (HippyModuleData *moduleData in [_moduleSetup moduleDataByID]) { - NSArray *moduleDataConfig = [moduleData config]; - [config addObject:HippyNullIfNil(moduleDataConfig)]; - } - id jsonArray = @{ - @"remoteModuleConfig": config, - }; - return HippyJSONStringify(jsonArray, NULL); -} - - (void)setRedBoxShowEnabled:(BOOL)enabled { #if HIPPY_DEBUG HippyRedBox *redBox = [self redBox]; @@ -1182,33 +1203,10 @@ - (void)setRedBoxShowEnabled:(BOOL)enabled { #endif // HIPPY_DEBUG } -- (HippyOCTurboModule *)turboModuleWithName:(NSString *)name { - if (!self.enableTurbo) { - return nil; - } - - if (name.length <= 0) { - return nil; - } - - if(!self.turboModuleManager) { - self.turboModuleManager = [[HippyTurboModuleManager alloc] initWithBridge:self]; - } - - // getTurboModule - HippyOCTurboModule *turboModule = [self.turboModuleManager turboModuleWithName:name]; - return turboModule; -} - - (void)registerModuleForFrameUpdates:(id)module withModuleData:(HippyModuleData *)moduleData { [_displayLink registerModuleForFrameUpdates:module withModuleData:moduleData]; } -- (NSArray *)configForModuleName:(NSString *)moduleName { - HippyModuleData *moduleData = [_moduleSetup moduleDataByName][moduleName]; - return moduleData.config; -} - - (void)setSandboxDirectory:(NSURL *)sandboxDirectory { if (![_sandboxDirectory isEqual:sandboxDirectory]) { _sandboxDirectory = sandboxDirectory; diff --git a/framework/ios/base/enginewrapper/HippyContextWrapper.h b/framework/ios/base/enginewrapper/HippyContextWrapper.h deleted file mode 100644 index 261a5bb0108..00000000000 --- a/framework/ios/base/enginewrapper/HippyContextWrapper.h +++ /dev/null @@ -1,92 +0,0 @@ -/*! - * iOS SDK - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * Licensed 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 - -#include - -#include "driver/napi/js_ctx.h" -#include "driver/napi/js_ctx_value.h" - -NS_ASSUME_NONNULL_BEGIN - -namespace hippy { -inline namespace driver { -inline namespace napi { -class Ctx; -class CtxValue; -} -} -} - -@class HippyJSStackFrame; - -typedef id __nullable (^FunctionImplementationBlock)(NSArray *arguments); - -@protocol HippyContextWrapper - -typedef void (^ExceptionHandler)(idwrapper, NSString *message, NSArray *stackFrames); - -@required - -@property(nonatomic, readonly)std::weak_ptr underlyingContext; -@property(nonatomic, copy)ExceptionHandler excpetionHandler; - -@property(nonatomic, readonly)NSString *exception; - -- (instancetype)initWithContext:(std::weak_ptr)context; - -- (BOOL)createGlobalObject:(NSString *)name withValue:(NSString *)value; -- (BOOL)createGlobalObject:(NSString *)name withJsonValue:(NSString *)value; -- (BOOL)createGlobalObject:(NSString *)name withDictionary:(NSDictionary *)value; - -- (id)globalObjectForName:(NSString *)name; -- (std::shared_ptr)globalJSValueForName:(NSString *)name; -- (BOOL)setProperties:(NSDictionary *)properties toGlobalObject:(NSString *)objectName; -- (BOOL)setProperty:(NSString *)propertyName - forJSValue:(std::shared_ptr)value - toJSObject:(std::shared_ptr)object; -- (std::shared_ptr)property:(NSString *)propertyName - forJSObject:(std::shared_ptr)object; - -- (void)registerFunction:(NSString *)funcName implementation:(FunctionImplementationBlock)implementation; -- (id)callFunction:(NSString *)funcName arguments:(NSArray *)arguments; - -- (id)runScript:(NSString *)script sourceURL:(NSURL *)sourceURL useCachedCode:(BOOL)useCachedCode cachedCodeData:(inout NSData *_Nullable *_Nullable)data; - -- (std::shared_ptr)createNumber:(NSNumber *)number; -- (std::shared_ptr)createBool:(NSNumber *)number; -- (std::shared_ptr)createString:(NSString *)string; -- (std::shared_ptr)createUndefined; -- (std::shared_ptr)createNull; -- (std::shared_ptr)createObject:(NSDictionary *)dictionary; -- (std::shared_ptr)createObjectFromJsonString:(NSString *)JsonString; -- (std::shared_ptr)createArray:(NSArray *)array; -- (std::shared_ptr)createException:(NSString *)description; - -- (void)setContextName:(NSString *)name; - -@end - -id CreateContextWrapper(std::shared_ptr); - -NS_ASSUME_NONNULL_END diff --git a/framework/ios/base/enginewrapper/jsc/HippyJSCContextWrapper.h b/framework/ios/base/enginewrapper/jsc/HippyJSCContextWrapper.h deleted file mode 100644 index c636c848ffa..00000000000 --- a/framework/ios/base/enginewrapper/jsc/HippyJSCContextWrapper.h +++ /dev/null @@ -1,36 +0,0 @@ -/*! - * iOS SDK - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * Licensed 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 -#import "HippyContextWrapper.h" - -NS_ASSUME_NONNULL_BEGIN - -@class JSContext; - -@interface HippyJSCContextWrapper : NSObject - -@property(nonatomic, readonly)JSContext *context; - -@end - -NS_ASSUME_NONNULL_END diff --git a/framework/ios/base/enginewrapper/jsc/HippyJSCContextWrapper.mm b/framework/ios/base/enginewrapper/jsc/HippyJSCContextWrapper.mm deleted file mode 100644 index d11a66c6ce5..00000000000 --- a/framework/ios/base/enginewrapper/jsc/HippyJSCContextWrapper.mm +++ /dev/null @@ -1,448 +0,0 @@ -/*! - * iOS SDK - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * Licensed 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 - -#import "NSObject+JSValue.h" -#import "HippyAssert.h" -#import "HippyJSCContextWrapper.h" -#import "HippyJSStackFrame.h" - -#include -#include "driver/napi/jsc/jsc_ctx.h" -#include "driver/napi/jsc/jsc_ctx_value.h" - -static id StringJSONToObject(NSString *string) { - @autoreleasepool { - NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding]; - id obj = [NSJSONSerialization JSONObjectWithData:data options:(0) error:nil]; - return obj; - } -} - -static BOOL IsJSValueFunction(JSValue *value) { - if (!value) { - return NO; - } - JSGlobalContextRef contextRef = value.context.JSGlobalContextRef; - JSValueRef valueRef = value.JSValueRef; - if (!JSValueIsObject(contextRef, valueRef)) { - return NO; - } - JSObjectRef objRef = JSValueToObject(contextRef, valueRef, nil); - if (!objRef) { - return NO; - } - return JSObjectIsFunction(contextRef, objRef); -} - -@interface HippyJSCContextWrapper () { - std::weak_ptr _napiContext; - JSContext *_context; - NSMutableDictionary *_callbackDic; -} - -@end - -@implementation HippyJSCContextWrapper - -@synthesize excpetionHandler = _excpetionHandler; - -- (instancetype)initWithContext:(std::weak_ptr)context { - self = [super init]; - if (self) { - auto strongContext = context.lock(); - HippyAssert(strongContext, @"context must be available"); - if (strongContext) { - auto jscontext = std::static_pointer_cast(strongContext); - _napiContext = jscontext; - _context = [JSContext contextWithJSGlobalContextRef:jscontext->GetCtxRef()]; - __weak HippyJSCContextWrapper *weakSelf = self; - _context.exceptionHandler = ^(JSContext *context, JSValue *exception) { - @autoreleasepool { - HippyJSCContextWrapper *strongSelf = weakSelf; - if (!strongSelf) { - return; - } - ExceptionHandler exceptionHandler = strongSelf.excpetionHandler; - if (!exceptionHandler) { - return; - } - JSGlobalContextRef contextRef = strongSelf->_context.JSGlobalContextRef; - NSString *stacksString = [[exception objectForKeyedSubscript:@"stack"] toString]; - NSString *message = [[exception objectForKeyedSubscript:@"message"] toString]; - double lineNumber = JSValueToNumber(contextRef, [exception objectForKeyedSubscript:@"line"].JSValueRef, NULL); - double column = JSValueToNumber(contextRef, [exception objectForKeyedSubscript:@"column"].JSValueRef, NULL); - NSArray *stacksArray = [stacksString componentsSeparatedByString:@"\n"]; - NSMutableArray *stackFrames = [NSMutableArray arrayWithCapacity:[stacksArray count]]; - for (NSString *line in stacksArray) { - HippyJSStackFrame *stackFrame = [[HippyJSStackFrame alloc] initWithMethodName:line file:@"" lineNumber:lineNumber column:column]; - [stackFrames addObject:stackFrame]; - } - exceptionHandler(strongSelf, message, [stackFrames copy]); - } - }; - _callbackDic = [NSMutableDictionary dictionaryWithCapacity:8]; - } - } - return self; -} - -- (std::weak_ptr)underlyingContext { - return _napiContext; -} - -- (JSContext *)context { - return _context; -} - -- (NSString *)exception { - return [[_context exception] toString]; -} - -- (BOOL)createGlobalObject:(NSString *)name withValue:(NSString *)value { - @autoreleasepool { - if (!name || !value) { - return NO; - } - [_context setObject:name forKeyedSubscript:value]; - return YES; - } -} - -- (BOOL)createGlobalObject:(NSString *)name withJsonValue:(NSString *)value { - @autoreleasepool { - if (!name || !value) { - return NO; - } - id obj = StringJSONToObject(value); - if (!obj) { - return NO; - } - JSValue *objValue = [obj toJSValueInContext:_context]; - if (!objValue) { - return NO; - } - [_context setObject:objValue forKeyedSubscript:name]; - return YES; - } -} - -- (BOOL)createGlobalObject:(NSString *)name withDictionary:(NSDictionary *)value { - @autoreleasepool { - if (!name || !value) { - return NO; - } - JSValue *mapValue = [value toJSValueInContext:_context]; - if (!mapValue) { - return NO; - } - [_context setObject:mapValue forKeyedSubscript:name]; - return YES; - } -} - -- (id)globalObjectForName:(NSString *)name { - @autoreleasepool { - JSValue *value = [_context objectForKeyedSubscript:name]; - JSValueRef exception = NULL; - id object = ObjectFromJSValueRef(_context.JSGlobalContextRef, value.JSValueRef, &exception); - if (exception) { - _context.exception = [JSValue valueWithJSValueRef:exception inContext:_context]; - return nil; - } - return object; - } -} - -- (std::shared_ptr)globalJSValueForName:(NSString *)name { - @autoreleasepool { - JSValue *value = [_context objectForKeyedSubscript:name]; - return std::make_shared(_context.JSGlobalContextRef, value.JSValueRef); - } -} - -- (std::shared_ptr)property:(NSString *)propertyName - forJSObject:(std::shared_ptr)object { - @autoreleasepool { - auto jscValue = std::static_pointer_cast(object); - JSValue *ocValue = [JSValue valueWithJSValueRef:jscValue->value_ inContext:_context]; - JSValue *obj = [ocValue objectForKeyedSubscript:propertyName]; - return std::make_shared(_context.JSGlobalContextRef, obj.JSValueRef); - } -} - -- (BOOL)setProperties:(NSDictionary *)properties toGlobalObject:(NSString *)objectName { - @autoreleasepool { - if (!properties || !objectName) { - return NO; - } - JSValue *globalObject = _context[objectName]; - if ([globalObject isNull] || [globalObject isUndefined]) { - return NO; - } - for (NSString *key in properties) { - if (![key isKindOfClass:[NSString class]]) { - continue; - } - id value = properties[key]; - JSValue *obj = [value toJSValueInContext:_context]; - globalObject[key] = obj; - } - return YES; - } -} - -- (BOOL)setProperty:(NSString *)propertyName - forJSValue:(std::shared_ptr)value - toJSObject:(std::shared_ptr)object { - @autoreleasepool { - if (!propertyName || !value || !object) { - return NO; - } - auto objRef = std::static_pointer_cast(object); - auto valueRef = std::static_pointer_cast(value); - JSValue *objc = [JSValue valueWithJSValueRef:objRef->value_ inContext:_context]; - JSValueRef exception = NULL; - JSValue *valueObject = [JSValue valueWithJSValueRef:valueRef->value_ inContext:_context]; - if (exception) { - _context.exception = [JSValue valueWithJSValueRef:exception inContext:_context]; - return NO; - } - objc[propertyName] = valueObject; - return YES; - } -} - -- (void)registerFunction:(NSString *)funcName implementation:(FunctionImplementationBlock)implementation { - @autoreleasepool { - if (!funcName || !implementation) { - return; - } - FunctionImplementationBlock callback = [implementation copy]; - JSContext *context = _context; - JSGlobalContextRef contextRef = [context JSGlobalContextRef]; - auto native_func_callback = [](JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t cnt, const JSValueRef arguments[], JSValueRef* exception) -> JSValueRef { - @autoreleasepool { - JSContext *context = [JSContext contextWithJSGlobalContextRef:(JSGlobalContextRef)ctx]; - void *privateData = JSObjectGetPrivate(function); - if (!privateData) { - *exception = [JSValue valueWithNewErrorFromMessage:@"Get private data from function failed" inContext:context].JSValueRef; - return JSValueMakeUndefined(ctx); - } - FunctionImplementationBlock block = (__bridge FunctionImplementationBlock)privateData; - NSMutableArray *argAry = [NSMutableArray arrayWithCapacity:cnt]; - for (size_t index = 0; index < cnt; index++) { - JSValueRef valueRef = arguments[index]; - id obj = ObjectFromJSValueRef((JSGlobalContextRef)ctx, valueRef, exception); - if (*exception) { - return JSValueMakeUndefined(ctx); - } - [argAry addObject:obj]; - } - id ret = block([argAry copy]); - if (ret) { - JSValue *retValue = [ret toJSValueInContext:context]; - return retValue.JSValueRef; - } - return JSValueMakeUndefined(ctx); - } - }; - [_callbackDic setObject:callback forKey:funcName]; - JSClassDefinition cls_def = kJSClassDefinitionEmpty; - cls_def.callAsFunction = native_func_callback; - JSClassRef cls_ref = JSClassCreate(&cls_def); - JSObjectRef func_object = JSObjectMake(contextRef, cls_ref, (__bridge void *)callback); - JSClassRelease(cls_ref); - JSStringRef JSFunctionName = JSStringCreateWithCFString((__bridge CFStringRef)funcName); - if (!JSFunctionName) { - return; - } - JSValueRef exception = NULL; - JSObjectSetProperty(contextRef, JSContextGetGlobalObject(contextRef), JSFunctionName, func_object, kJSPropertyAttributeNone, &exception); - if (exception) { - _context.exception = [JSValue valueWithJSValueRef:exception inContext:_context]; - } - JSStringRelease(JSFunctionName); - } -} - -- (id)callFunction:(NSString *)funcName arguments:(NSArray *)arguments { - @autoreleasepool { - if (!funcName) { - return nil; - } - JSContext *context = _context; - JSValue *batchedbridgeValue = context[@"__hpBatchedBridge"]; - HippyAssert(batchedbridgeValue && ![batchedbridgeValue isUndefined] && ![batchedbridgeValue isNull], @"__hpBatchedBridge must not be null or undefined"); - if (!batchedbridgeValue || [batchedbridgeValue isUndefined]) { - _context.exception = [JSValue valueWithNewErrorFromMessage:@"cannot find __hpBatchedBridge" inContext:context]; - return nil; - } - JSValue *methodValue = batchedbridgeValue[funcName]; - if (!IsJSValueFunction(methodValue)) { - return nil; - } - JSValueRef arrayValues[[arguments count]]; - for (size_t i = 0; i < [arguments count]; i++) { - arrayValues[i] = [arguments[i] toJSValueInContext:context].JSValueRef; - } - JSValueRef exception = NULL; - JSObjectRef functionObject = JSValueToObject(context.JSGlobalContextRef, methodValue.JSValueRef, &exception); - if (exception) { - _context.exception = [JSValue valueWithJSValueRef:exception inContext:_context]; - return nil; - } - JSValueRef ret = JSObjectCallAsFunction(context.JSGlobalContextRef, functionObject, NULL, [arguments count], arrayValues, &exception); - if (exception) { - _context.exception = [JSValue valueWithJSValueRef:exception inContext:_context]; - return nil; - } - id obj = ObjectFromJSValueRef(context.JSGlobalContextRef, ret, &exception); - if (exception) { - _context.exception = [JSValue valueWithJSValueRef:exception inContext:_context]; - return nil; - } - return obj; - } -} - -- (id)runScript:(NSString *)script - sourceURL:(NSURL *)sourceURL - useCachedCode:(BOOL)useCachedCode - cachedCodeData:(inout NSData *_Nullable *_Nullable)data { - @autoreleasepool { - JSContext *context = _context; - JSValue *result = [context evaluateScript:script withSourceURL:sourceURL?:[NSURL URLWithString:@""]]; - JSValueRef exception = NULL; - id object = ObjectFromJSValueRef(context.JSGlobalContextRef, result.JSValueRef, &exception); - if (exception) { - _context.exception = [JSValue valueWithJSValueRef:exception inContext:_context]; - } - return object; - } -} - -- (std::shared_ptr)createNumber:(NSNumber *)number { - @autoreleasepool { - HippyAssert(number, @"number must not be null"); - if (number) { - JSValueRef valueRef = [number toJSValueInContext:_context].JSValueRef; - return std::make_shared(_context.JSGlobalContextRef, valueRef); - } - return [self createUndefined]; - } -} - -- (std::shared_ptr)createBool:(NSNumber *)number { - @autoreleasepool { - HippyAssert(number, @"number must not be null"); - if (number) { - JSValueRef valueRef = [number toJSValueInContext:_context].JSValueRef; - return std::make_shared(_context.JSGlobalContextRef, valueRef); - } - return [self createUndefined]; - } -} - -- (std::shared_ptr)createString:(NSString *)string { - @autoreleasepool { - HippyAssert(string, @"string must not be null"); - if (string) { - JSValueRef valueRef = [string toJSValueInContext:_context].JSValueRef; - return std::make_shared(_context.JSGlobalContextRef, valueRef); - } - return [self createUndefined]; - } -} - -- (std::shared_ptr)createUndefined { - return std::make_shared(_context.JSGlobalContextRef, JSValueMakeUndefined(_context.JSGlobalContextRef)); -} - -- (std::shared_ptr)createNull { - return std::make_shared(_context.JSGlobalContextRef, JSValueMakeNull(_context.JSGlobalContextRef)); -} - -- (std::shared_ptr)createObject:(NSDictionary *)dictionary { - @autoreleasepool { - HippyAssert(dictionary, @"dictionary must not be null"); - if (dictionary) { - JSValueRef valueRef = [dictionary toJSValueInContext:_context].JSValueRef; - return std::make_shared(_context.JSGlobalContextRef, valueRef); - } - return [self createUndefined]; - } -} - -- (std::shared_ptr)createObjectFromJsonString:(NSString *)JsonString { - @autoreleasepool { - HippyAssert(JsonString, @"JsonString must not be null"); - id obj = StringJSONToObject(JsonString); - if (obj) { - JSValueRef valueRef = [obj toJSValueInContext:_context].JSValueRef; - return std::make_shared(_context.JSGlobalContextRef, valueRef); - } - return [self createUndefined]; - } -} - -- (std::shared_ptr)createArray:(NSArray *)array { - @autoreleasepool { - HippyAssert(array, @"array must not be null"); - if (array) { - JSValueRef valueRef = [array toJSValueInContext:_context].JSValueRef; - return std::make_shared(_context.JSGlobalContextRef, valueRef); - } - return [self createUndefined]; - } -} - -- (std::shared_ptr)createException:(NSString *)description { - @autoreleasepool { - HippyAssert(description, @"description must not be null"); - description = description?:@""; - JSValueRef arguments[1]; - arguments[0] = [description toJSValueInContext:_context].JSValueRef; - JSValueRef exception = NULL; - JSValueRef errorObj = JSObjectMakeError(_context.JSGlobalContextRef, 1, arguments, &exception); - if (exception) { - _context.exception = [JSValue valueWithJSValueRef:exception inContext:_context]; - return std::make_shared(_context.JSGlobalContextRef, errorObj); - } - return [self createUndefined]; - } -} - -- (void)setContextName:(NSString *)name { - [_context setName:name]; -} - -- (void)dealloc { - -} - -@end - -id CreateContextWrapper(std::shared_ptr context) { - return [[HippyJSCContextWrapper alloc] initWithContext:context]; -} diff --git a/framework/ios/base/enginewrapper/v8/HippyV8ContextWrapper.h b/framework/ios/base/enginewrapper/v8/HippyV8ContextWrapper.h deleted file mode 100644 index 3cf1203be54..00000000000 --- a/framework/ios/base/enginewrapper/v8/HippyV8ContextWrapper.h +++ /dev/null @@ -1,32 +0,0 @@ -/*! - * iOS SDK - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * Licensed 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 -#import "HippyContextWrapper.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface HippyV8ContextWrapper : NSObject - -@end - -NS_ASSUME_NONNULL_END diff --git a/framework/ios/base/enginewrapper/v8/HippyV8ContextWrapper.mm b/framework/ios/base/enginewrapper/v8/HippyV8ContextWrapper.mm deleted file mode 100644 index 0fb3414f3b3..00000000000 --- a/framework/ios/base/enginewrapper/v8/HippyV8ContextWrapper.mm +++ /dev/null @@ -1,701 +0,0 @@ -/*! - * iOS SDK - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * Licensed 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 "HippyAsserts.h" -#import "HippyLog.h" -#import "HPDriverStackFrame.h" -#import "HippyV8ContextWrapper.h" -#import "NSObject+CtxValue.h" -#import "NSObject+V8Value.h" - -#include - -#include "driver/napi/v8/v8_ctx_value.h" -#include "driver/napi/v8/v8_ctx.h" - -static id StringJSONToObject(NSString *string) { - @autoreleasepool { - NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding]; - id obj = [NSJSONSerialization JSONObjectWithData:data options:(0) error:nil]; - return obj; - } -} - -static v8::Local V8ValueFromCtxValue(const std::shared_ptr &value, v8::Local context) { - auto ctxValue = std::static_pointer_cast(value); - v8::Local v8Value = ctxValue->global_value_.Get(context->GetIsolate()); - return v8Value; -} - -static v8::Local V8ObjectFromCtxValue(const std::shared_ptr &value, - v8::Local context) { - auto ctxValue = std::static_pointer_cast(value); - v8::Local v8Value = ctxValue->global_value_.Get(context->GetIsolate()); - HippyAssert(v8Value->IsObject(), @"value is not a object"); - v8::MaybeLocal maybeObject = v8Value->ToObject(context); - HippyAssert(!maybeObject.IsEmpty(), @"maybe object is not a object"); - return maybeObject.ToLocalChecked(); -} - -static NSString *v8StringToNSString(v8::Isolate *isolate, v8::Local v8String) { - @autoreleasepool { - if (v8String.IsEmpty() || !isolate) { - return nil; - } - int len = v8String->Length(); - if (v8String->IsOneByte()) { - void *buffer = malloc(len); - v8String->WriteOneByte(isolate, reinterpret_cast(buffer)); - NSString *result = [[NSString alloc] initWithBytesNoCopy:buffer length:len encoding:NSUTF8StringEncoding freeWhenDone:YES]; - return result; - } - else { - void *buffer = malloc(len * 2); - v8String->Write(isolate, reinterpret_cast(buffer)); - NSString *result = [[NSString alloc] initWithBytesNoCopy:buffer length:len * 2 encoding:NSUTF16LittleEndianStringEncoding freeWhenDone:YES]; - return result; - } - } -} - -@interface HippyV8ContextWrapper () { - std::weak_ptr _v8Context; - v8::Isolate *_ioslate; - NSMutableDictionary *_blockDic; - NSString *_exception; - NSData *_cachedCodeData; -} - -@end - -@implementation HippyV8ContextWrapper - -@synthesize excpetionHandler = _excpetionHandler; - -static void HandleUncaughtJsError(v8::Local message, v8::Local data) { - @autoreleasepool { - if (!data->IsExternal() || data->IsNullOrUndefined()) { - return; - } - v8::Local external = data.As(); - HippyV8ContextWrapper *wrapper = (__bridge HippyV8ContextWrapper *)external->Value(); - ExceptionHandler excpetionHandler = wrapper.excpetionHandler; - if (!excpetionHandler) { - return; - } - v8::Local stack = message->GetStackTrace(); - v8::Isolate *isolate = message->GetIsolate(); - NSString *errorMessage = v8StringToNSString(isolate, message->Get()); - int frameCount = stack->GetFrameCount(); - NSMutableArray *stacks = [NSMutableArray arrayWithCapacity:frameCount]; - for (int i = 0; i < frameCount; i++) { - v8::Local frame = stack->GetFrame(isolate, i); - v8::Local functionName = frame->GetFunctionName(); - NSString *funcName = v8StringToNSString(isolate, functionName); - if (!funcName) { - funcName = @"unknown function name"; - } - v8::Local scrName = frame->GetScriptNameOrSourceURL(); - NSString *scriptName = v8StringToNSString(isolate, scrName); - HPDriverStackFrame *stackFrame = [[HPDriverStackFrame alloc] initWithMethodName:funcName - file:scriptName - lineNumber:frame->GetLineNumber() - column:frame->GetColumn()]; - [stacks addObject:stackFrame]; - } - excpetionHandler(wrapper, errorMessage, [stacks copy]); - } -} - -- (instancetype)initWithContext:(std::weak_ptr)context { - self = [super init]; - if (self) { - @autoreleasepool { - _v8Context = std::static_pointer_cast(context.lock()); - _blockDic = [NSMutableDictionary dictionaryWithCapacity:8]; - auto ctx = _v8Context.lock(); - if (ctx) { - v8::Isolate *isolate = ctx->isolate_; - v8::HandleScope handleScope(isolate); - v8::Local localContext = ctx->context_persistent_.Get(isolate); - v8::Context::Scope contextScope(localContext); - - void *data = (__bridge void *)self; - v8::Local external = v8::External::New(isolate, data); - isolate->AddMessageListener(HandleUncaughtJsError, external); - isolate->SetCaptureStackTraceForUncaughtExceptions(YES); - } - } - } - return self; -} - -- (std::weak_ptr)underlyingContext { - return _v8Context; -} - -- (NSString *)exception { - return _exception; -} - -- (BOOL)createGlobalObject:(NSString *)name withValue:(NSString *)value { - if (!name || !value) { - _exception = @"name or value nil for createGlobalObject:withvalue:"; - return NO; - } - auto context = _v8Context.lock(); - if (!context) { - _exception = @"context null for createGlobalObject:withvalue:"; - return NO; - } - v8::HandleScope handleScope(context->isolate_); - v8::Local localContext = context->context_persistent_.Get(context->isolate_); - v8::Context::Scope contextScope(localContext); - v8::Local globalObject = localContext->Global(); - v8::TryCatch tryCache(context->isolate_); - v8::Local v8Name = [name toV8StringInIsolate:context->isolate_]; - v8::Local v8Value = [value toV8StringInIsolate:context->isolate_]; - BOOL result = globalObject->Set(localContext, v8Name, v8Value).FromMaybe(false); - if (tryCache.HasCaught()) { - _exception = TryToFetchStringFromV8Value(tryCache.Exception(), context->isolate_); - } - return result; -} - -- (BOOL)createGlobalObject:(NSString *)name withJsonValue:(NSString *)value { - if (!name || !value) { - _exception = @"name or value nil for createGlobalObject:withJsonValue:"; - return NO; - } - auto context = _v8Context.lock(); - if (!context) { - _exception = @"context null for createGlobalObject:withJsonValue:"; - return NO; - } - v8::HandleScope handleScope(context->isolate_); - v8::Local localContext = context->context_persistent_.Get(context->isolate_); - v8::Context::Scope contextScope(localContext); - v8::Local globalObject = localContext->Global(); - v8::TryCatch tryCache(context->isolate_); - v8::Local v8Name = [name toV8StringInIsolate:context->isolate_]; - v8::MaybeLocal jsonValue = v8::JSON::Parse(localContext, [value toV8StringInIsolate:context->isolate_]); - if (jsonValue.IsEmpty()) { - if (tryCache.HasCaught()) { - _exception = TryToFetchStringFromV8Value(tryCache.Exception(), context->isolate_); - } - return NO; - } - BOOL ret = globalObject->Set(localContext, v8Name, jsonValue.ToLocalChecked()).FromMaybe(false); - return ret; -} - -- (BOOL)createGlobalObject:(NSString *)name withDictionary:(NSDictionary *)value { - if (!name || !value) { - _exception = @"name or value nil for createGlobalObject:withDictionary:"; - return NO; - } - auto context = _v8Context.lock(); - if (!context) { - _exception = @"context null for createGlobalObject:withDictionary:"; - return NO; - } - v8::Isolate *isolate = context->isolate_; - v8::HandleScope handleScope(isolate); - v8::Local localContext = context->context_persistent_.Get(isolate); - v8::Context::Scope contextScope(localContext); - v8::Local globalObject = localContext->Global(); - v8::TryCatch tryCache(isolate); - v8::Local v8Name = [name toV8StringInIsolate:context->isolate_]; - v8::Local map = [value toV8ValueInIsolate:isolate context:localContext]; - BOOL result = globalObject->Set(localContext, v8Name, map).FromMaybe(false); - if (tryCache.HasCaught()) { - _exception = TryToFetchStringFromV8Value(tryCache.Exception(), context->isolate_); - } - return result; -} - -- (id)globalObjectForName:(NSString *)name { - if (!name) { - _exception = @"name nil for globalObjectForName:"; - return nullptr; - } - auto context = _v8Context.lock(); - if (!context) { - _exception = @"context null for globalObjectForName:"; - return nullptr; - } - v8::Isolate *isolate = context->isolate_; - v8::HandleScope handleScope(isolate); - v8::Local localContext = context->context_persistent_.Get(isolate); - v8::Context::Scope contextScope(localContext); - v8::Local globalObject = localContext->Global(); - v8::TryCatch tryCache(isolate); - v8::Local v8Name = [name toV8StringInIsolate:context->isolate_]; - v8::MaybeLocal mayBeValue = globalObject->Get(localContext, v8Name); - if (mayBeValue.IsEmpty()) { - if (tryCache.HasCaught()) { - _exception = TryToFetchStringFromV8Value(tryCache.Exception(), isolate); - } - return nil; - } - v8::Local value = mayBeValue.ToLocalChecked(); - return ObjectFromV8Value(value, isolate, localContext); -} - -- (std::shared_ptr)globalJSValueForName:(NSString *)name { - if (!name) { - _exception = @"name nil for globalJSValueForName:"; - return nullptr; - } - auto context = _v8Context.lock(); - if (!context) { - _exception = @"context null for globalJSValueForName:"; - return nullptr; - } - v8::Isolate *isolate = context->isolate_; - v8::HandleScope handleScope(isolate); - v8::Local localContext = context->context_persistent_.Get(isolate); - v8::Context::Scope contextScope(localContext); - v8::Local globalObject = localContext->Global(); - v8::TryCatch tryCache(isolate); - v8::Local v8Name = [name toV8StringInIsolate:context->isolate_]; - v8::MaybeLocal mayBeValue = globalObject->Get(localContext, v8Name); - if (mayBeValue.IsEmpty()) { - if (tryCache.HasCaught()) { - _exception = TryToFetchStringFromV8Value(tryCache.Exception(), isolate); - } - return nil; - } - v8::Local value = mayBeValue.ToLocalChecked(); - auto ctxValue = std::make_shared(isolate, value); - return ctxValue; -} - -- (BOOL)setProperties:(NSDictionary *)properties toGlobalObject:(NSString *)objectName { - if (!objectName) { - _exception = @"properties or objectName nil for setProperties:toGlobalObject:"; - return NO; - } - auto context = _v8Context.lock(); - if (!context) { - _exception = @"context null for setProperties:toGlobalObject:"; - return NO; - } - v8::Isolate *isolate = context->isolate_; - v8::HandleScope handleScope(isolate); - v8::Local localContext = context->context_persistent_.Get(isolate); - v8::Context::Scope contextScope(localContext); - v8::TryCatch tryCache(isolate); - v8::Local v8Name = [objectName toV8StringInIsolate:isolate]; - v8::MaybeLocal maybeTagetValue = localContext->Global()->Get(localContext, v8Name); - if (maybeTagetValue.IsEmpty()) { - if (tryCache.HasCaught()) { - _exception = TryToFetchStringFromV8Value(tryCache.Exception(), isolate); - } - return NO; - } - v8::Local value = maybeTagetValue.ToLocalChecked(); - if (!value->IsObject()) { - _exception = @"value is not object"; - return NO; - } - v8::MaybeLocal maybeObject = value->ToObject(localContext); - if (maybeObject.IsEmpty()) { - _exception = @"maybeObject is empty"; - return NO; - } - v8::Local targetObject = maybeObject.ToLocalChecked(); - for (NSString *key in properties) { - id object = [properties objectForKey:key]; - v8::TryCatch tryCache(isolate); - v8::Local keyString = [key toV8StringInIsolate:isolate]; - v8::Local localValue = [object toV8ValueInIsolate:isolate context:localContext]; - if (!targetObject->Set(localContext, keyString, localValue).FromMaybe(false)) { -// NativeRenderLogWarn(@"createGlobalObject withDictionary failed, key:%@, value:%@", key, object); - - } - if (tryCache.HasCaught()) { - _exception = TryToFetchStringFromV8Value(tryCache.Exception(), isolate); - } - } - return YES; -} - -- (BOOL)setProperty:(NSString *)propertyName - forJSValue:(std::shared_ptr)value - toJSObject:(std::shared_ptr)object { - if (!propertyName || !value || !object) { - _exception = @"propertyName or value or object nil for setProperty:forJSValue::toJSObject"; - return NO; - } - auto context = _v8Context.lock(); - if (!context) { - _exception = @"propertyName or value or object nil for setProperty:forJSValue::toJSObject"; - return NO; - } - v8::Isolate *isolate = context->isolate_; - v8::HandleScope handleScope(isolate); - v8::Local localContext = context->context_persistent_.Get(isolate); - v8::Context::Scope contextScope(localContext); - v8::Local v8Name = [propertyName toV8StringInIsolate:isolate]; - v8::Local targetObject = V8ObjectFromCtxValue(object, localContext); - v8::Local targetValue = V8ValueFromCtxValue(value, localContext); - v8::TryCatch tryCache(isolate); - BOOL ret = targetObject->Set(localContext, v8Name, targetValue).FromMaybe(false); - if (tryCache.HasCaught()) { - _exception = TryToFetchStringFromV8Value(tryCache.Exception(), isolate); - } - return ret; -} - -- (std::shared_ptr)property:(NSString *)propertyName - forJSObject:(std::shared_ptr)object { - if (!propertyName || !object) { - _exception = @"property or object nil for property:forJSObject:"; - return nullptr; - } - auto context = _v8Context.lock(); - if (!context) { - return nullptr; - } - v8::Isolate *isolate = context->isolate_; - v8::HandleScope handleScope(isolate); - v8::Local localContext = context->context_persistent_.Get(isolate); - v8::Context::Scope contextScope(localContext); - v8::Local targetObject = V8ObjectFromCtxValue(object, localContext); - v8::Local v8Name = [propertyName toV8StringInIsolate:isolate]; - v8::MaybeLocal maybeValue = targetObject->Get(localContext, v8Name); - if (maybeValue.IsEmpty()) { - HippyLog(@"get property %@ for object failed", propertyName); - return nullptr; - } - v8::Local value = maybeValue.ToLocalChecked(); - return std::make_shared(isolate, value); -} - -static void NativeCallbackFuncWithValue(const v8::FunctionCallbackInfo& info) { - v8::Local data = info.Data().As(); - if (data.IsEmpty()) { - info.GetReturnValue().SetUndefined(); - return; - } - FunctionImplementationBlock block = (__bridge FunctionImplementationBlock)data->Value(); - if (!block) { - info.GetReturnValue().SetUndefined(); - return; - } - NSMutableArray *argumentsArray = [NSMutableArray arrayWithCapacity:info.Length()]; - v8::Isolate *isolate = info.GetIsolate(); - v8::Local context = isolate->GetCurrentContext(); - for (int index = 0; index < info.Length(); index++) { - v8::Local infoArgu = info[index]; - id object = ObjectFromV8Value(infoArgu, info.GetIsolate(), info.GetIsolate()->GetCurrentContext()); - [argumentsArray addObject:object]; - } - id result = block([argumentsArray copy]); - if (!result) { - info.GetReturnValue().SetUndefined(); - return; - } - v8::HandleScope handleScope(isolate); - v8::Context::Scope contextScope(context); - v8::Local resultValue = [result toV8ValueInIsolate:isolate context:context]; - info.GetReturnValue().Set(resultValue); -} - -- (void)registerFunction:(NSString *)funcName implementation:(FunctionImplementationBlock)implementation { - if (!funcName || !implementation) { - _exception = @"funcName or implementation nil for registerFunction:implementation:"; - return; - } - auto context = _v8Context.lock(); - if (!context) { - _exception = @"context null for funcName:implementation:"; - return; - } - v8::Isolate *isolate = context->isolate_; - v8::HandleScope handleScope(isolate); - v8::Local localContext = context->context_persistent_.Get(isolate); - v8::Context::Scope contextScope(localContext); - - id blockCallback = [implementation copy]; - [_blockDic setObject:blockCallback forKey:funcName]; - void *callbackData = (__bridge void *)blockCallback; - v8::Local external = v8::External::New(isolate, callbackData); - v8::Local funcTemplate = v8::FunctionTemplate::New(isolate, NativeCallbackFuncWithValue, external); - funcTemplate->RemovePrototype(); - v8::Local v8funcName = [funcName toV8StringInIsolate:isolate]; - v8::TryCatch tryCache(isolate); - localContext->Global()->Set(localContext, v8funcName, funcTemplate->GetFunction(localContext).ToLocalChecked()).Check(); - if (tryCache.HasCaught()) { - _exception = TryToFetchStringFromV8Value(tryCache.Exception(), isolate); - } -} - -- (id)callFunction:(NSString *)funcName arguments:(NSArray *)arguments { - if (!funcName) { - _exception = @"funcName null for callFunction:arguments:"; - return nil; - } - auto context = _v8Context.lock(); - if (!context) { - _exception = [NSString stringWithFormat:@"context null for function %@ invoke", funcName]; - return nil; - } - v8::Isolate *isolate = context->isolate_; - v8::HandleScope handleScope(isolate); - v8::Local localContext = context->context_persistent_.Get(isolate); - v8::Context::Scope contextScope(localContext); - v8::TryCatch tryCache(isolate); - v8::MaybeLocal maybeBatchedBridgeObject = - localContext->Global()->Get(localContext, [@"__hpBatchedBridge" toV8StringInIsolate:isolate]); - if (maybeBatchedBridgeObject.IsEmpty()) { - _exception = @"cannot find __hpBatchedBridge"; - return nil; - } - v8::Local batchedBridgeObject = maybeBatchedBridgeObject.ToLocalChecked().As(); - if (batchedBridgeObject->IsNullOrUndefined()) { - _exception = @"cannot find __hpBatchedBridge"; - return nil; - } - v8::Local v8Name = [funcName toV8StringInIsolate:isolate]; - v8::MaybeLocal maybeFuncValue = batchedBridgeObject->Get(localContext, v8Name); - if (maybeFuncValue.IsEmpty()) { - if (tryCache.HasCaught()) { - _exception = TryToFetchStringFromV8Value(tryCache.Exception(), isolate); - } - return nil; - } - v8::Local funcValue = maybeFuncValue.ToLocalChecked(); - if (!funcValue->IsFunction()) { - if (tryCache.HasCaught()) { - _exception = TryToFetchStringFromV8Value(tryCache.Exception(), isolate); - } - return nil; - } - v8::Local function = funcValue.As(); - int count = (int)[arguments count]; - v8::Local args[count]; - for (size_t i = 0; i < count; i++) { - id obj = arguments[i]; - args[i] = [obj toV8ValueInIsolate:isolate context:localContext]; - } - v8::MaybeLocal maybeResult = function->Call(localContext, localContext->Global(), count, args); - if (maybeResult.IsEmpty()) { - if (tryCache.HasCaught()) { - _exception = TryToFetchStringFromV8Value(tryCache.Exception(), isolate); - } - return nil; - } - v8::Local result = maybeResult.ToLocalChecked(); - return ObjectFromV8Value(result, isolate, localContext); -} - -- (id)runScript:(NSString *)script - sourceURL:(NSURL *)sourceURL - useCachedCode:(BOOL)useCachedCode - cachedCodeData:(inout NSData *_Nullable *_Nullable)data { - if (!script) { - _exception = @"script must not be null for runScript:sourceURL:"; - return nil; - } - auto context = _v8Context.lock(); - if (!context) { - _exception = @"context null for runScript:sourceURL:"; - return nil; - } - v8::Isolate *isolate = context->isolate_; - v8::HandleScope handleScope(isolate); - v8::Local localContext = context->context_persistent_.Get(isolate); - v8::Context::Scope contextScope(localContext); - NSString *source = sourceURL?[sourceURL absoluteString]:@""; - v8::TryCatch scriptCatch(isolate); - v8::Local scriptString = [script toV8StringInIsolate:isolate]; -#if (V8_MAJOR_VERSION == 8 && V8_MINOR_VERSION == 9 && \ - V8_BUILD_NUMBER >= 45) || \ - (V8_MAJOR_VERSION == 8 && V8_MINOR_VERSION > 9) || (V8_MAJOR_VERSION > 8) - v8::ScriptOrigin origin(isolate, [source toV8StringInIsolate:isolate]); -#else - v8::ScriptOrigin origin([source toV8StringInIsolate:isolate]); -#endif - v8::ScriptCompiler::CachedData *v8CachedDataStruct = nullptr; - v8::ScriptCompiler::CompileOptions options = v8::ScriptCompiler::kNoCompileOptions; - if (useCachedCode && data) { - NSData *cachedData = *data; - if (cachedData) { - const uint8_t *underlying = reinterpret_cast([cachedData bytes]); - int length = static_cast([cachedData length]); - v8CachedDataStruct = new v8::ScriptCompiler::CachedData(underlying, length); - options = v8::ScriptCompiler::kConsumeCodeCache; - } - } - v8::ScriptCompiler::Source script_source(scriptString, origin, v8CachedDataStruct); - v8::MaybeLocal maybeScriptResult = v8::ScriptCompiler::Compile(localContext, &script_source, options); - if (maybeScriptResult.IsEmpty()) { - if (scriptCatch.HasCaught()) { - _exception = TryToFetchStringFromV8Value(scriptCatch.Exception(), isolate); - } - return nil; - } - if (useCachedCode && data) { - const v8::ScriptCompiler::CachedData* cached_data = - v8::ScriptCompiler::CreateCodeCache(maybeScriptResult.ToLocalChecked()->GetUnboundScript()); - const void *underlying = reinterpret_cast(cached_data->data); - NSData *outData = [NSData dataWithBytes:underlying length:cached_data->length]; - *data = outData; - } - v8::TryCatch runCatch(isolate); - v8::MaybeLocal maybeRunResult = maybeScriptResult.ToLocalChecked()->Run(localContext); - if (maybeScriptResult.IsEmpty()) { - if (runCatch.HasCaught()) { - _exception = TryToFetchStringFromV8Value(runCatch.Exception(), isolate); - } - return nil; - } - v8::Local runResult = maybeRunResult.ToLocalChecked(); - id objResult = ObjectFromV8Value(runResult, isolate, localContext); - return objResult; -} - -- (std::shared_ptr)createNumber:(NSNumber *)number { - auto context = _v8Context.lock(); - if (!context) { - return nullptr; - } - return context->CreateNumber([number doubleValue]); -} - -- (std::shared_ptr)createBool:(NSNumber *)number { - auto context = _v8Context.lock(); - if (!context) { - return nullptr; - } - return context->CreateNumber([number boolValue]); -} - -- (std::shared_ptr)createString:(NSString *)string { - if (!string) { - return nullptr; - } - auto context = _v8Context.lock(); - if (!context) { - return nullptr; - } - v8::Isolate *isolate = context->isolate_; - v8::HandleScope handleScope(isolate); - v8::Local localContext = context->context_persistent_.Get(isolate); - v8::Context::Scope contextScope(localContext); - v8::Handle v8String = [string toV8ValueInIsolate:context->isolate_ context:localContext].As(); - return std::make_shared(isolate, v8String); -} - -- (std::shared_ptr)createUndefined { - auto context = _v8Context.lock(); - if (!context) { - return nullptr; - } - return context->CreateUndefined(); -} - -- (std::shared_ptr)createNull { - auto context = _v8Context.lock(); - if (!context) { - return nullptr; - } - return context->CreateNull(); -} - -- (std::shared_ptr)createObject:(NSDictionary *)dictionary { - if (!dictionary) { - return nullptr; - } - auto context = _v8Context.lock(); - if (!context) { - return nullptr; - } - v8::Isolate *isolate = context->isolate_; - v8::HandleScope handleScope(isolate); - v8::Local localContext = context->context_persistent_.Get(isolate); - v8::Context::Scope contextScope(localContext); - v8::Handle dic = [dictionary toV8ValueInIsolate:context->isolate_ context:localContext]; - return std::make_shared(isolate, dic); -} - -- (std::shared_ptr)createObjectFromJsonString:(NSString *)JsonString { - if (!JsonString) { - return nullptr; - } - auto context = _v8Context.lock(); - if (!context) { - return nullptr; - } - id objFromJson = StringJSONToObject(JsonString); - if (!objFromJson) { - return nullptr; - } - v8::Isolate *isolate = context->isolate_; - v8::HandleScope handleScope(isolate); - v8::Local localContext = context->context_persistent_.Get(isolate); - v8::Context::Scope contextScope(localContext); - v8::Handle value = [objFromJson toV8ValueInIsolate:context->isolate_ context:localContext]; - return std::make_shared(isolate, value); -} - -- (std::shared_ptr)createArray:(NSArray *)array { - if (!array) { - return nullptr; - } - auto context = _v8Context.lock(); - if (!context) { - return nullptr; - } - v8::Isolate *isolate = context->isolate_; - v8::HandleScope handleScope(isolate); - v8::Local localContext = context->context_persistent_.Get(isolate); - v8::Context::Scope contextScope(localContext); - v8::Handle value = [array toV8ValueInIsolate:context->isolate_ context:localContext]; - return std::make_shared(isolate, value); -} -- (std::shared_ptr)createError:(NSString *)description { - if (!description) { - return nullptr; - } - auto context = _v8Context.lock(); - if (!context) { - return nullptr; - } - v8::Isolate *isolate = context->isolate_; - v8::HandleScope handleScope(isolate); - v8::Local localContext = context->context_persistent_.Get(isolate); - v8::Context::Scope contextScope(localContext); - v8::Local message = [description toV8ValueInIsolate:isolate context:localContext].As(); - v8::Local error = v8::Exception::Error(message); - return std::make_shared(isolate, error); -} - -- (void)setContextName:(NSString *)name {} - -@end - -id CreateContextWrapper(std::shared_ptr context) { - return [[HippyV8ContextWrapper alloc] initWithContext:context]; -} diff --git a/framework/ios/base/executors/HippyJSExecutor.h b/framework/ios/base/executors/HippyJSExecutor.h index 9f049f907a0..69d7ae174ae 100644 --- a/framework/ios/base/executors/HippyJSExecutor.h +++ b/framework/ios/base/executors/HippyJSExecutor.h @@ -51,9 +51,7 @@ class UriLoader; } @class HippyBridge; -@protocol HippyContextWrapper; - -typedef void (^HippyContextCreatedBlock)(id); +typedef void (^HippyContextCreatedBlock)(void); /** @@ -64,9 +62,7 @@ typedef void (^HippyContextCreatedBlock)(id); /// HippyBridge instance @property (nonatomic, weak) HippyBridge *bridge; -/** - * Whether the executor has been invalidated - */ +/// Whether the executor has been invalidated @property (nonatomic, readonly, getter=isValid) BOOL valid; /// EngineKey @@ -76,7 +72,7 @@ typedef void (^HippyContextCreatedBlock)(id); @property (atomic, assign) std::shared_ptr pScope; /// context created block -@property(nonatomic, copy) HippyContextCreatedBlock contextCreatedBlock; +@property (nonatomic, copy) HippyContextCreatedBlock contextCreatedBlock; /// Init method /// - Parameters: @@ -136,8 +132,6 @@ typedef void (^HippyContextCreatedBlock)(id); */ - (void)executeApplicationScript:(NSData *)script sourceURL:(NSURL *)sourceURL onComplete:(HippyJavaScriptCallback)onComplete; -- (void)injectJSONText:(NSString *)script asGlobalObjectNamed:(NSString *)objectName callback:(HippyJavaScriptCallback)onComplete; - /** * Enqueue a block to run in the executors JS thread. Fallback to `dispatch_async` * on the main queue if the executor doesn't own a thread. @@ -155,4 +149,11 @@ typedef void (^HippyContextCreatedBlock)(id); /// - Parameter dict: updated info - (void)updateNativeInfoToHippyGlobalObject:(NSDictionary *)dict; +/// Inject object to JS global using `objectName` as key sync. +/// Must be called in the JS thread. +- (void)injectObjectSync:(NSObject *)value asGlobalObjectNamed:(NSString *)objectName callback:(HippyJavaScriptCallback)onComplete; + +/// Inject object to JS global using `objectName` as key async. +- (void)injectObjectAsync:(NSString *)value asGlobalObjectNamed:(NSString *)objectName callback:(HippyJavaScriptCallback)onComplete; + @end diff --git a/framework/ios/base/executors/HippyJSExecutor.mm b/framework/ios/base/executors/HippyJSExecutor.mm index c6aed485dca..b905c7b87a0 100644 --- a/framework/ios/base/executors/HippyJSExecutor.mm +++ b/framework/ios/base/executors/HippyJSExecutor.mm @@ -24,7 +24,6 @@ #import "VFSUriHandler.h" #import "HippyAssert.h" #import "HippyBundleURLProvider.h" -#import "HippyContextWrapper.h" #import "HippyDefines.h" #import "HippyDevInfo.h" #import "HippyDevMenu.h" @@ -74,14 +73,14 @@ constexpr char kGlobalKey[] = "global"; constexpr char kHippyKey[] = "Hippy"; -static NSString * const kHippyNativeGlobalKey = @"__HIPPYNATIVEGLOBAL__"; -static const char * kHippyExceptionEventName = "uncaughtException"; +constexpr char kHippyNativeGlobalKey[] = "__HIPPYNATIVEGLOBAL__"; +constexpr char kHippyExceptionEventName[] = "uncaughtException"; +constexpr char kHippyRequireModuleConfigFuncKey[] = "nativeRequireModuleConfig"; +constexpr char kHippyFlushQueueImmediateFuncKey[] = "nativeFlushQueueImmediate"; +constexpr char kHippyGetTurboModule[] = "getTurboModule"; @interface HippyJSExecutor () { - // Set at setUp time: - id _contextWrapper; - #ifdef JS_JSC BOOL _isInspectable; #endif //JS_JSC @@ -139,102 +138,22 @@ - (void)setup { // add `Hippy` property to global object auto hippy_key = context->CreateString(kHippyKey); context->SetProperty(global_object, hippy_key, context->CreateObject()); + + // inject device info to `__HIPPYNATIVEGLOBAL__` + [strongSelf injectDeviceInfoAsHippyNativeGlobal:bridge context:context globalObject:global_object]; - // Context Wrapper - id contextWrapper = CreateContextWrapper(context); - contextWrapper.excpetionHandler = ^(id _Nonnull wrapper, - NSString * _Nonnull message, - NSArray * _Nonnull stackFrames) { - HippyJSExecutor *strongSelf = weakSelf; - if (!strongSelf) { - return; - } - HippyBridge *bridge = strongSelf.bridge; - if (!bridge) { - return; - } - NSDictionary *userInfo = @{ - HippyFatalModuleName: bridge.moduleName?:@"unknown", - NSLocalizedDescriptionKey:message?:@"unknown", - HippyJSStackTraceKey:stackFrames - }; - NSError *error = [NSError errorWithDomain:HippyErrorDomain code:2 userInfo:userInfo]; - HippyBridgeFatal(error, bridge); - }; - strongSelf->_contextWrapper = contextWrapper; - - // inject device info information - NSMutableDictionary *deviceInfo = [NSMutableDictionary dictionaryWithDictionary:[bridge deviceInfo]]; - NSString *deviceName = [[UIDevice currentDevice] name]; - NSString *clientId = HippyMD5Hash([NSString stringWithFormat:@"%@%p", deviceName, strongSelf]); - NSDictionary *debugInfo = @{@"Debug" : @{@"debugClientId" : clientId}}; - [deviceInfo addEntriesFromDictionary:debugInfo]; - - NSError *serializationError; - NSString *deviceInfoStr = HippyJSONStringify(deviceInfo, &serializationError); - if (serializationError) { - NSString *errorString = [NSString stringWithFormat:@"device parse error:%@, deviceInfo:%@", - [serializationError localizedFailureReason], deviceInfo]; - NSError *error = HippyErrorWithMessageAndModuleName(errorString, bridge.moduleName); - HippyBridgeFatal(error, bridge); - } - [contextWrapper createGlobalObject:kHippyNativeGlobalKey withJsonValue:deviceInfoStr]; + // register `nativeRequireModuleConfig` function + [strongSelf registerRequiredModuleConfigFuncToJS:context globalObject:global_object scope:scope]; - // regist `nativeRequireModuleConfig` function - [contextWrapper registerFunction:@"nativeRequireModuleConfig" implementation:^id _Nullable(NSArray * _Nonnull arguments) { - NSString *moduleName = [arguments firstObject]; - if (moduleName) { - HippyJSExecutor *strongSelf = weakSelf; - if (!strongSelf.valid) { - return nil; - } - HippyBridge *bridge = strongSelf.bridge; - if (!bridge) { - return nil; - } - NSArray *result = [bridge configForModuleName:moduleName]; - return HippyNullIfNil(result); - } - return nil; - }]; - - // regist `nativeFlushQueueImmediate` function - [contextWrapper registerFunction:@"nativeFlushQueueImmediate" implementation:^id _Nullable(NSArray * _Nonnull arguments) { - NSArray *calls = [arguments firstObject]; - HippyJSExecutor *strongSelf = weakSelf; - if (!strongSelf.valid || !calls) { - return nil; - } - HippyBridge *bridge = strongSelf.bridge; - if (!bridge) { - return nil; - } - [bridge handleBuffer:calls batchEnded:NO]; - return nil; - }]; + // register `nativeFlushQueueImmediate` function + [strongSelf registerFlushQueueImmediateFuncToJS:context globalObject:global_object scope:scope]; - auto turbo_wrapper = std::make_unique([](hippy::CallbackInfo& info, void* data) { - @autoreleasepool { - //todo - HippyJSExecutor *strongSelf = (__bridge HippyJSExecutor*)data; - if (!strongSelf) { - return; - } - const auto &context = strongSelf.pScope->GetContext(); - if (context->IsString(info[0])) { - NSString *name = ObjectFromCtxValue(context, info[0]); - auto value = [strongSelf JSTurboObjectWithName:name]; - info.GetReturnValue()->Set(value); - } - } - }, (__bridge void*)weakSelf); - auto turbo_function = context->CreateFunction(turbo_wrapper); - scope->SaveFunctionWrapper(std::move(turbo_wrapper)); - context->SetProperty(global_object, context->CreateString("getTurboModule"), turbo_function); + // register `getTurboModule` function + [strongSelf registerGetTurboModuleFuncToJS:context globalObject:global_object scope:scope]; // call finish block if (strongSelf.contextCreatedBlock) { - strongSelf.contextCreatedBlock(strongSelf->_contextWrapper); + strongSelf.contextCreatedBlock(); } scope->SyncInitialize(); @@ -329,6 +248,99 @@ - (void)invalidate { } +#pragma mark - Subprocedures of Setup + +- (void)injectDeviceInfoAsHippyNativeGlobal:(HippyBridge *)bridge + context:(const std::shared_ptr &)context + globalObject:(const std::shared_ptr &)globalObject { + NSMutableDictionary *deviceInfo = [NSMutableDictionary dictionaryWithDictionary:[bridge deviceInfo]]; + NSString *deviceName = [[UIDevice currentDevice] name]; + NSString *clientId = HippyMD5Hash([NSString stringWithFormat:@"%@%p", deviceName, self]); + NSDictionary *debugInfo = @{@"Debug" : @{@"debugClientId" : clientId}}; + [deviceInfo addEntriesFromDictionary:debugInfo]; + + auto key = context->CreateString(kHippyNativeGlobalKey); + auto value = [deviceInfo convertToCtxValue:context]; + if (key && value) { + context->SetProperty(globalObject, key, value); + } +} + +- (void)registerRequiredModuleConfigFuncToJS:(const std::shared_ptr &)context + globalObject:(const std::shared_ptr &)globalObject + scope:(const std::shared_ptr &)scope { + __weak __typeof(self)weakSelf = self; + auto requireModuleConfigFunWrapper = std::make_unique([](hippy::CallbackInfo& info, void* data) { + @autoreleasepool { + HippyJSExecutor *strongSelf = (__bridge HippyJSExecutor*)data; + HippyBridge *bridge = strongSelf.bridge; + if (!strongSelf.valid || !bridge || !strongSelf.pScope) { + return; + } + + const auto &context = strongSelf.pScope->GetContext(); + if (context->IsString(info[0])) { + NSString *moduleName = ObjectFromCtxValue(context, info[0]); + if (moduleName) { + NSArray *result = [bridge configForModuleName:moduleName]; + info.GetReturnValue()->Set([HippyNullIfNil(result) convertToCtxValue:context]); + } + } + } + }, (__bridge void*)weakSelf); + auto requireModuleConfigFunction = context->CreateFunction(requireModuleConfigFunWrapper); + scope->SaveFunctionWrapper(std::move(requireModuleConfigFunWrapper)); + context->SetProperty(globalObject, context->CreateString(kHippyRequireModuleConfigFuncKey), requireModuleConfigFunction); +} + +- (void)registerFlushQueueImmediateFuncToJS:(const std::shared_ptr &)context + globalObject:(const std::shared_ptr &)globalObject + scope:(const std::shared_ptr &)scope { + __weak __typeof(self)weakSelf = self; + auto nativeFlushQueueFunWrapper = std::make_unique([](hippy::CallbackInfo& info, void* data) { + @autoreleasepool { + HippyJSExecutor *strongSelf = (__bridge HippyJSExecutor*)data; + HippyBridge *bridge = strongSelf.bridge; + if (!strongSelf.valid || !bridge || !strongSelf.pScope) { + return; + } + + const auto &context = strongSelf.pScope->GetContext(); + if (context->IsArray(info[0])) { + NSArray *calls = ObjectFromCtxValue(context, info[0]); + [bridge handleBuffer:calls batchEnded:NO]; + } + } + }, (__bridge void*)weakSelf); + auto nativeFlushQueueFunction = context->CreateFunction(nativeFlushQueueFunWrapper); + scope->SaveFunctionWrapper(std::move(nativeFlushQueueFunWrapper)); + context->SetProperty(globalObject, context->CreateString(kHippyFlushQueueImmediateFuncKey), nativeFlushQueueFunction); +} + +- (void)registerGetTurboModuleFuncToJS:(const std::shared_ptr &)context + globalObject:(const std::shared_ptr &)globalObject + scope:(const std::shared_ptr &)scope { + __weak __typeof(self)weakSelf = self; + auto turbo_wrapper = std::make_unique([](hippy::CallbackInfo& info, void* data) { + @autoreleasepool { + HippyJSExecutor *strongSelf = (__bridge HippyJSExecutor*)data; + if (!strongSelf || !strongSelf.pScope) { + return; + } + const auto &context = strongSelf.pScope->GetContext(); + if (context->IsString(info[0])) { + NSString *name = ObjectFromCtxValue(context, info[0]); + auto value = [strongSelf JSTurboObjectWithName:name]; + info.GetReturnValue()->Set(value); + } + } + }, (__bridge void*)weakSelf); + auto turbo_function = context->CreateFunction(turbo_wrapper); + scope->SaveFunctionWrapper(std::move(turbo_wrapper)); + context->SetProperty(globalObject, context->CreateString(kHippyGetTurboModule), turbo_function); +} + + #pragma mark - - (void)setUriLoader:(std::weak_ptr)uriLoader { @@ -477,7 +489,7 @@ - (void)updateNativeInfoToHippyGlobalObject:(NSDictionary *)updatedInfoDict { } - (void)addInfoToGlobalObject:(NSDictionary*)addInfoDict{ - string_view str(kHippyNativeGlobalKey.UTF8String); + string_view str(kHippyNativeGlobalKey); auto context = self.pScope->GetContext(); auto global_object = context->GetGlobalObject(); auto hippy_native_object_key = context->CreateString(str); @@ -667,45 +679,49 @@ - (void)executeAsyncBlockOnJavaScriptQueue:(dispatch_block_t)block { } } -- (void)injectJSONText:(NSString *)script asGlobalObjectNamed:(NSString *)objectName callback:(HippyJavaScriptCallback)onComplete { - HippyAssert(nil != script, @"param 'script' can't be nil"); - if (nil == script) { +- (void)injectObjectSync:(NSObject *)value asGlobalObjectNamed:(NSString *)objectName callback:(HippyJavaScriptCallback)onComplete { + if (!objectName || !value) { if (onComplete) { - NSString *errorMessage = [NSString stringWithFormat:@"param 'script' is nil"]; - NSError *error = [NSError errorWithDomain:HippyErrorDomain code:2 userInfo:@{ NSLocalizedDescriptionKey: errorMessage }]; + NSError *error = HippyErrorWithMessage(@"Inject param invalid"); onComplete(@(NO), error); } return; } - if (HIPPY_DEBUG) { - HippyAssert(HippyJSONParse(script, NULL) != nil, @"%@ wasn't valid JSON!", script); + if (!self.isValid || !self.pScope) { + return; + } + auto context = self.pScope->GetContext(); + auto tryCatch = hippy::napi::CreateTryCatchScope(true, context); + auto globalObject = context->GetGlobalObject(); + auto nameKey = context->CreateString(objectName.UTF8String); + auto ctxValue = [value convertToCtxValue:context]; + if (nameKey && ctxValue) { + context->SetProperty(globalObject, nameKey, [value convertToCtxValue:context]); + } else { + HippyLogError(@"Convert Error while inject:%@ for:%@", value, objectName); + } + if (tryCatch->HasCaught()) { + NSString *errorMsg = StringViewToNSString(tryCatch->GetExceptionMessage()); + NSError *error = HippyErrorWithMessage(errorMsg); + if (onComplete) { + onComplete(@(NO), error); + } else { + HippyLogError(@"Error(%@) while inject:%@ for:%@", errorMsg, value, objectName); + } + } else if (onComplete) { + onComplete(@(YES), nil); } +} - __weak HippyJSExecutor *weakSelf = self; +- (void)injectObjectAsync:(NSObject *)value asGlobalObjectNamed:(NSString *)objectName callback:(HippyJavaScriptCallback)onComplete { + __weak __typeof(self)weakSelf = self; [self executeBlockOnJavaScriptQueue:^{ @autoreleasepool { - HippyJSExecutor *strongSelf = weakSelf; + __strong __typeof(weakSelf)strongSelf = weakSelf; if (!strongSelf || !strongSelf.isValid) { return; } - string_view json_view = NSStringToU8StringView(script); - string_view name_view = NSStringToU8StringView(objectName); - auto context = strongSelf.pScope->GetContext(); - auto tryCatch = hippy::napi::CreateTryCatchScope(true, context); - auto global_object = context->GetGlobalObject(); - auto name_key = context->CreateString(name_view); - auto engine = [[HippyJSEnginesMapper defaultInstance] JSEngineResourceForKey:strongSelf.enginekey]; - auto json_value = engine->GetEngine()->GetVM()->ParseJson(context, json_view); - context->SetProperty(global_object, name_key, json_value); - if (tryCatch->HasCaught()) { - string_view errorMsg = tryCatch->GetExceptionMessage(); - NSError *error = [NSError errorWithDomain:HippyErrorDomain code:2 userInfo:@{ - NSLocalizedDescriptionKey: StringViewToNSString(errorMsg)}]; - onComplete(@(NO), error); - } - else { - onComplete(@(YES), nil); - } + [strongSelf injectObjectSync:value asGlobalObjectNamed:objectName callback:onComplete]; } }]; } diff --git a/framework/ios/base/modules/HippyModuleData.mm b/framework/ios/base/modules/HippyModuleData.mm index 7c1a3974e3d..71fd86bf74c 100644 --- a/framework/ios/base/modules/HippyModuleData.mm +++ b/framework/ios/base/modules/HippyModuleData.mm @@ -312,7 +312,13 @@ - (NSArray *)config { [methods addObject:method.JSMethodName]; } - NSArray *config = @[self.name, HippyNullIfNil(constants), HippyNullIfNil(methods), HippyNullIfNil(promiseMethods), HippyNullIfNil(syncMethods)]; + NSArray *config = @[ + self.name, + HippyNullIfNil(constants), + HippyNullIfNil(methods), + HippyNullIfNil(promiseMethods), + HippyNullIfNil(syncMethods) + ]; return config; } diff --git a/framework/ios/utils/jsc/NSObject+JSValue.h b/framework/ios/utils/jsc/NSObject+JSValue.h deleted file mode 100644 index 0ae0fa74ed0..00000000000 --- a/framework/ios/utils/jsc/NSObject+JSValue.h +++ /dev/null @@ -1,55 +0,0 @@ -/*! - * iOS SDK - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * Licensed 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 -#import -#import "HippyDefines.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface NSObject (JSValue) - -- (JSValue *)toJSValueInContext:(JSContext *)context; - -@end - -@interface NSArray (JSValue) - -- (JSValue *)toJSValueInContext:(JSContext *)context; - -@end - -@interface NSDictionary (JSValue) - -- (JSValue *)toJSValueInContext:(JSContext *)context; - -@end - -@interface NSData (JSValue) - -- (JSValue *)toJSValueInContext:(JSContext *)context; - -@end - -HIPPY_EXTERN id ObjectFromJSValueRef(JSGlobalContextRef const context, JSValueRef const value, JSValueRef _Nonnull * _Nonnull exception); - -NS_ASSUME_NONNULL_END diff --git a/framework/ios/utils/jsc/NSObject+JSValue.m b/framework/ios/utils/jsc/NSObject+JSValue.m deleted file mode 100644 index 3181893264f..00000000000 --- a/framework/ios/utils/jsc/NSObject+JSValue.m +++ /dev/null @@ -1,253 +0,0 @@ -/*! - * iOS SDK - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * Licensed 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 "NSObject+JSValue.h" -#import "HippyLog.h" - -@implementation NSObject (JSValue) - -- (JSValue *)toJSValueInContext:(JSContext *)context { - @autoreleasepool { -#ifdef DEBUG - if ([self isKindOfClass:NSClassFromString(@"NSString")] || - [self isKindOfClass:NSClassFromString(@"NSNumber")] || - [self isKindOfClass:NSClassFromString(@"NSDate")] || - [self isKindOfClass:NSClassFromString(@"NSNull")]) { - } - else { - HippyLogError(@"unsupport type to JSValue:%@", NSStringFromClass([self class])); - } -#endif //DEBUG - return [JSValue valueWithObject:self inContext:context]; - } -} - -@end - -@implementation NSArray (JSValue) - -- (JSValue *)toJSValueInContext:(JSContext *)context { - @autoreleasepool { - JSValue *value = [JSValue valueWithNewArrayInContext:context]; - for (int index = 0; index < [self count]; index++) { - id obj = [self objectAtIndex:index]; - value[index] = [obj toJSValueInContext:context]; - } - return value; - } -} - -@end - -@implementation NSDictionary (JSValue) - -- (JSValue *)toJSValueInContext:(JSContext *)context { - @autoreleasepool { - JSValue *dicValue = [JSValue valueWithNewObjectInContext:context]; - for (id key in self) { - id value = [self objectForKey:key]; - JSValue *JSKey = [key toJSValueInContext:context]; - JSValue *JSValue = [value toJSValueInContext:context]; - dicValue[JSKey] = JSValue; - } - return dicValue; - } -} - -@end - -@implementation NSData (JSValue) - -static void JSCCtx_dataBufferFree(void* bytes, void* deallocatorContext) { - free(bytes); -} - -- (JSValue *)toJSValueInContext:(JSContext *)context { - @autoreleasepool { - size_t length = [self length]; - void *data = malloc(length); - if (!data) { - HippyLogError(@"out of memory, NSData to JSValue memory allocation failure"); - return [JSValue valueWithObject:self inContext:context]; - } - [self getBytes:data length:length]; - JSValueRef exception = NULL; - JSValueRef value_ref = JSObjectMakeArrayBufferWithBytesNoCopy(context.JSGlobalContextRef, data, length, JSCCtx_dataBufferFree, NULL, &exception); - if (exception) { - return [JSValue valueWithUndefinedInContext:context]; - } - return [JSValue valueWithJSValueRef:value_ref inContext:context]; - } -} - -@end - -static NSString *StringFromJSStringRef(JSStringRef stringRef) { - @autoreleasepool { - if (!stringRef) { - return nil; - } - size_t size = JSStringGetMaximumUTF8CStringSize(stringRef); - void *buffer = malloc(size); - memset(buffer, 0, size); - JSStringGetUTF8CString(stringRef, buffer, size); - NSString *string = [NSString stringWithUTF8String:buffer]; - free(buffer); - return string; - } -} - -id ObjectFromJSValueRef(JSGlobalContextRef const context, JSValueRef const value, JSValueRef *exception) { - @autoreleasepool { - id object = nil; - if (JSValueIsUndefined(context, value)) { - } - else if (JSValueIsNull(context, value)) { - object = [NSNull null]; - } - else if (JSValueIsBoolean(context, value)) { - object = @(JSValueToBoolean(context, value)); - } - else if (JSValueIsString(context, value)) { - JSStringRef stringRef = JSValueToStringCopy(context, value, exception); - if (*exception) { - JSStringRelease(stringRef); - return nil; - } - object = StringFromJSStringRef(stringRef); - JSStringRelease(stringRef); - } - else if (JSValueIsNumber(context, value)) { - double number = JSValueToNumber(context, value, exception); - if (*exception) { - return nil; - } - object = @(number); - } - else if (JSValueIsArray(context, value)) { - JSObjectRef arrayRef = JSValueToObject(context, value, exception); - if (*exception) { - return nil; - } - if (!arrayRef) { - return nil; - } - static CFStringRef len_string = CFSTR("length"); - JSStringRef propName = JSStringCreateWithCFString(len_string); - JSValueRef val = JSObjectGetProperty(context, arrayRef, propName, exception); - if (*exception) { - JSStringRelease(propName); - return nil; - } - if (!val) { - JSStringRelease(propName); - return nil; - } - JSStringRelease(propName); - int32_t count = JSValueToNumber(context, val, exception); - if (*exception) { - return nil; - } - NSMutableArray *array = [NSMutableArray arrayWithCapacity:count]; - for (int32_t i = 0; i < count; ++i) { - JSValueRef element = JSObjectGetPropertyAtIndex(context, arrayRef, i, exception); - if (*exception) { - return nil; - } - if (!element) { - continue; - } - id elementObject = ObjectFromJSValueRef(context, element, exception); - if (*exception) { - return nil; - } - if (elementObject) { - [array addObject:elementObject]; - } - } - object = array; - } - else if (kJSTypedArrayTypeNone != JSValueGetTypedArrayType(context, value, exception)) { - JSTypedArrayType type = JSValueGetTypedArrayType(context, value, exception); - JSObjectRef objectRef = JSValueToObject(context, value, exception); - if (kJSTypedArrayTypeArrayBuffer == type) { - void *arrayBufferPtr = JSObjectGetArrayBufferBytesPtr(context, objectRef, exception); - if (*exception) { - return nil; - } - if (!arrayBufferPtr) { - return nil; - } - size_t length = JSObjectGetArrayBufferByteLength(context, objectRef, exception); - if (*exception) { - return nil; - } - object = [NSData dataWithBytes:arrayBufferPtr length:length]; - } - else if (kJSTypedArrayTypeNone != type) { - void *typedArrayPtr = JSObjectGetTypedArrayBytesPtr(context, objectRef, exception); - if (*exception) { - return nil; - } - if (typedArrayPtr) { - return nil; - } - size_t length = JSObjectGetTypedArrayByteLength(context, objectRef, exception); - if (*exception) { - return nil; - } - object = [NSData dataWithBytes:typedArrayPtr length:length]; - } - } - else if (JSValueIsObject(context, value)) { - JSObjectRef objectRef = JSValueToObject(context, value, exception); - if (*exception) { - return nil; - } - if (!objectRef) { - return nil; - } - JSPropertyNameArrayRef nameArray = JSObjectCopyPropertyNames(context, objectRef); - size_t len = JSPropertyNameArrayGetCount(nameArray); - NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithCapacity:len]; - for (size_t i = 0; i < len; i++) { - JSStringRef propertyNameRef = JSPropertyNameArrayGetNameAtIndex(nameArray, i); - JSValueRef valueRef = JSObjectGetProperty(context, objectRef, propertyNameRef, exception); - if (*exception) { - JSPropertyNameArrayRelease(nameArray); - return nil; - } - if (!valueRef) { - continue; - } - NSString *dicKey = StringFromJSStringRef(propertyNameRef); - id dicValue = ObjectFromJSValueRef(context, valueRef, exception); - if (dicKey && dicValue) { - dic[dicKey] = dicValue; - } - } - object = dic; - JSPropertyNameArrayRelease(nameArray); - } - return object; - } -} diff --git a/framework/ios/utils/v8/NSObject+V8Value.h b/framework/ios/utils/v8/NSObject+V8Value.h deleted file mode 100644 index 537426cb5c5..00000000000 --- a/framework/ios/utils/v8/NSObject+V8Value.h +++ /dev/null @@ -1,77 +0,0 @@ -/*! - * iOS SDK - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * Licensed 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 -#import "MacroDefines.h" - -#include "v8/v8.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface NSObject (V8Value) - -- (v8::Local)toV8ValueInIsolate:(v8::Isolate *)isolate context:(v8::Local)context; - -@end - -@interface NSArray (V8Value) - -- (v8::Local)toV8ValueInIsolate:(v8::Isolate *)isolate context:(v8::Local)context; - -@end - -@interface NSDictionary (V8Value) - -- (v8::Local)toV8ValueInIsolate:(v8::Isolate *)isolate context:(v8::Local)context; - -@end - -@interface NSData (V8Value) - -- (v8::Local)toV8ValueInIsolate:(v8::Isolate *)isolate context:(v8::Local)context; - -@end - -@interface NSString (V8Value) - -- (v8::Local)toV8ValueInIsolate:(v8::Isolate *)isolate context:(v8::Local)context; -- (v8::Local)toV8StringInIsolate:(v8::Isolate *)isolate; - -@end - -@interface NSNumber (V8Value) - -- (v8::Local)toV8ValueInIsolate:(v8::Isolate *)isolate context:(v8::Local)context; - -@end - -@interface NSNull (V8Value) - -- (v8::Local)toV8ValueInIsolate:(v8::Isolate *)isolate context:(v8::Local)context; - -@end - -HIPPY_EXTERN id ObjectFromV8Value(v8::Local value, v8::Isolate *isolate, v8::Local context); - -HIPPY_EXTERN NSString *TryToFetchStringFromV8Value(v8::Local value, v8::Isolate *isolate); - -NS_ASSUME_NONNULL_END diff --git a/framework/ios/utils/v8/NSObject+V8Value.mm b/framework/ios/utils/v8/NSObject+V8Value.mm deleted file mode 100644 index 5776b27dc7f..00000000000 --- a/framework/ios/utils/v8/NSObject+V8Value.mm +++ /dev/null @@ -1,268 +0,0 @@ -/*! - * iOS SDK - * - * Tencent is pleased to support the open source community by making - * Hippy available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. - * All rights reserved. - * - * Licensed 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 "NSObject+V8Value.h" -#import "HippyAsserts.h" - -@implementation NSObject (V8Value) - -- (v8::Local)toV8ValueInIsolate:(v8::Isolate *)isolate context:(v8::Local)context { - HippyAssert(isolate, @"ios must not be null for object convert"); -#ifdef DEBUG - BOOL isRightType = [self isKindOfClass:[NSArray class]] || - [self isKindOfClass:[NSDictionary class]] || - [self isKindOfClass:[NSData class]] || - [self isKindOfClass:[NSString class]] || - [self isKindOfClass:[NSNumber class]]; - HippyAssert(isRightType, @"toV8ValueInIsolate is not supported by %@ class", NSStringFromClass([self class])); -#endif - v8::Local object = v8::Object::New(isolate); - return object; -} - -@end - -@implementation NSArray (V8Value) - -- (v8::Local)toV8ValueInIsolate:(v8::Isolate *)isolate context:(v8::Local)context { - HippyAssert(isolate, @"ios must not be null for array convert"); - size_t count = [self count]; - v8::Local elements[count]; - for (size_t i = 0; i < count; i++) { - id obj = [self objectAtIndex:i]; - elements[i] = [obj toV8ValueInIsolate:isolate context:context]; - } - return v8::Array::New(isolate, elements, count); -} - -@end - -@implementation NSDictionary (V8Value) - -- (v8::Local)toV8ValueInIsolate:(v8::Isolate *)isolate context:(v8::Local)context { - HippyAssert(isolate, @"ios must not be null for dictionary convert"); - v8::Local object = v8::Object::New(isolate); - for (id key in self) { - id value = [self objectForKey:key]; - v8::Local v8Key = [key toV8ValueInIsolate:isolate context:context]; - v8::Local v8Value = [value toV8ValueInIsolate:isolate context:context]; - object->Set(context, v8Key, v8Value).FromMaybe(false); - } - return object; -} - -@end - -@implementation NSData (V8Value) - -#if V8_MAJOR_VERSION >= 9 -static void ArrayBufferDataDeleter(void* data, size_t length, void* deleter_data) { - free(data); -} -#endif //V8_MAJOR_VERSION >= 9 - -- (v8::Local)toV8ValueInIsolate:(v8::Isolate *)isolate context:(v8::Local)context { - HippyAssert(isolate, @"ios must not be null for data convert"); - size_t length = [self length]; - void *buffer = malloc(length); - if (!buffer) { - return v8::Undefined(isolate); - } - [self getBytes:buffer length:length]; -#if V8_MAJOR_VERSION < 9 - v8::Local array_buffer = v8::ArrayBuffer::New(isolate, buffer, length, v8::ArrayBufferCreationMode::kInternalized); -#else - auto backingStore = v8::ArrayBuffer::NewBackingStore(buffer, length, ArrayBufferDataDeleter,nullptr); - v8::Local array_buffer = v8::ArrayBuffer::New(isolate, std::move(backingStore)); -#endif //V8_MAJOR_VERSION >= 9 - return array_buffer; -} - -@end - -@implementation NSString (V8Value) - -- (v8::Local)toV8ValueInIsolate:(v8::Isolate *)isolate context:(v8::Local)context { - return [self toV8StringInIsolate:isolate]; -} - -- (v8::Local)toV8StringInIsolate:(v8::Isolate *)isolate { - HippyAssert(isolate, @"ios must not be null for string convert"); - const char *p = [self UTF8String]?:""; - v8::MaybeLocal string = v8::String::NewFromUtf8(isolate, p); - return string.ToLocalChecked(); -} - -@end - -@implementation NSNumber (V8Value) - -- (v8::Local)toV8ValueInIsolate:(v8::Isolate *)isolate context:(v8::Local)context { - HippyAssert(isolate, @"ios must not be null for number convert"); - v8::Local number = v8::Number::New(isolate, [self doubleValue]); - return number; -} - -@end - -@implementation NSNull (V8Value) - -- (v8::Local)toV8ValueInIsolate:(v8::Isolate *)isolate context:(v8::Local)context { - return v8::Undefined(isolate); -} - -@end - -id ObjectFromV8Value(v8::Local value, v8::Isolate *isolate, v8::Local context); -static id ObjectFromV8MaybeValue(v8::MaybeLocal maybeValue, v8::Isolate *isolate, v8::Local context) { - if (maybeValue.IsEmpty()) { - return nil; - } - return ObjectFromV8Value(maybeValue.ToLocalChecked(), isolate, context); -} - -id ObjectFromV8Value(v8::Local value, v8::Isolate *isolate, v8::Local context) { - if (value->IsUndefined()) { - return [NSNull null]; - } - else if (value->IsNull()) { - return nil; - } - else if (value->IsString()) { - HippyAssert(isolate, @"isolate must not be null for string value"); - v8::Local string = value.As(); - int len = string->Length(); - if (string->IsOneByte()) { - void *buffer = malloc(len); - string->WriteOneByte(isolate, reinterpret_cast(buffer)); - NSString *result = [[NSString alloc] initWithBytesNoCopy:buffer length:len encoding:NSUTF8StringEncoding freeWhenDone:YES]; - return result; - } - else { - void *buffer = malloc(len * 2); - string->Write(isolate, reinterpret_cast(buffer)); - NSString *result = [[NSString alloc] initWithBytesNoCopy:buffer length:len * 2 encoding:NSUTF16LittleEndianStringEncoding freeWhenDone:YES]; - return result; - } - } - else if (value->IsStringObject()) { - HippyAssert(isolate, @"isolate must not be null for string value"); - v8::Local stringObj = value.As(); - return ObjectFromV8Value(stringObj->ValueOf(), isolate, context); - } - else if (value->IsBoolean()) { - v8::Local b = value.As(); - return @(b->Value()); - } - else if (value->IsBooleanObject()) { - v8::Local b = value.As(); - return @(b->ValueOf()); - } - else if (value->IsMap()) { - v8::Local map = value.As(); - v8::Local array = map->AsArray(); - uint32_t length = array->Length(); - NSMutableDictionary *dicMap = [NSMutableDictionary dictionaryWithCapacity:length]; - for (uint32_t i = 0; i < length; i+=2) { - NSString *objKey = ObjectFromV8MaybeValue(array->Get(context, i), isolate, context); - id objValue = ObjectFromV8MaybeValue(array->Get(context, i + 1), isolate, context); - if (objKey && objValue) { - [dicMap setObject:objKey forKey:objValue]; - } - } - return [dicMap copy]; - } - else if (value->IsArray()) { - v8::Local array = value.As(); - uint32_t length = array->Length(); - NSMutableArray *objArray = [NSMutableArray arrayWithCapacity:length]; - for (uint32_t i = 0; i < length; i++) { - id objValue = ObjectFromV8MaybeValue(array->Get(context, i), isolate, context); - if (objValue) { - [objArray addObject:objValue]; - } - } - return [objArray copy]; - } - else if (value->IsSet()) { - v8::Local array = value.As()->AsArray(); - return ObjectFromV8Value(array, isolate, context); - } - else if (value->IsNumber()) { - return @(value->ToNumber(context).ToLocalChecked()->Value()); - } - else if (value->IsInt32()) { - return @(value->ToInt32(context).ToLocalChecked()->Value()); - } - else if (value->IsArrayBuffer()) { - v8::Local arrayBuffer = value.As(); - const void *data = nullptr; - size_t length = 0; -#if V8_MAJOR_VERSION < 9 - data = arrayBuffer->GetContents().Data(); - length = arrayBuffer->ByteLength(); -#else - data = arrayBuffer->GetBackingStore()->Data(); - length = arrayBuffer->ByteLength(); -#endif //V8_MAJOR_VERSION < 9 - return [NSData dataWithBytes:data length:length]; - } - else if (value->IsObject()) { - v8::Local object = value.As(); - v8::MaybeLocal maybeProps = object->GetOwnPropertyNames(context); - //GetPropertyNames(context); - if (maybeProps.IsEmpty()) { - return [NSDictionary dictionary]; - } - v8::Local props = maybeProps.ToLocalChecked(); - uint32_t length = props->Length(); - NSMutableDictionary *keysValues = [NSMutableDictionary dictionaryWithCapacity:length]; - for (uint32_t i = 0; i < length; i++) { - v8::Local key = props->Get(context, i).ToLocalChecked(); - HippyAssert(key->IsString(), @"ObjectFromV8Value only supports keys as string"); - if (!key->IsString()) { - continue; - } - NSString *objKey = ObjectFromV8Value(key, isolate, context); - id objValue = ObjectFromV8MaybeValue(object->Get(context, key), isolate, context); - if (objKey && objValue) { - [keysValues setObject:objValue forKey:objKey]; - } - } - return [keysValues copy]; - } - - else { -#ifdef DEBUG - HippyAssert(NO, @"no implementation ObjectFromV8Value for type %@", ObjectFromV8Value(value->TypeOf(isolate), isolate, context)); -#endif - return nil; - } -} - -NSString *TryToFetchStringFromV8Value(v8::Local value, v8::Isolate *isolate) { - if (value.IsEmpty()) { - return nil; - } - v8::String::Utf8Value u8String(isolate, value); - return [NSString stringWithUTF8String:*u8String]; -} diff --git a/hippy.podspec b/hippy.podspec index e1933efeeb1..d69ed9e39a7 100644 --- a/hippy.podspec +++ b/hippy.podspec @@ -64,21 +64,6 @@ Pod::Spec.new do |s| 'modules/vfs/ios/*.h', 'modules/ios/image/*.h', ] - if js_engine == "jsc" - framework.exclude_files = [ - 'framework/ios/base/enginewrapper/v8', - 'framework/ios/utils/v8'] - elsif js_engine == "v8" - framework.exclude_files = [ - 'framework/ios/base/enginewrapper/jsc', - 'framework/ios/utils/jsc'] - else - framework.exclude_files = [ - 'framework/ios/base/enginewrapper/jsc', - 'framework/ios/utils/jsc', - 'framework/ios/base/enginewrapper/v8', - 'framework/ios/utils/v8'] - end framework.libraries = 'c++' framework.frameworks = 'CoreServices' framework.pod_target_xcconfig = { diff --git a/modules/footstone/src/platform/ios/logging.cc b/modules/footstone/src/platform/ios/logging.cc index 3fc0146bf49..14ab0c58327 100644 --- a/modules/footstone/src/platform/ios/logging.cc +++ b/modules/footstone/src/platform/ios/logging.cc @@ -84,10 +84,6 @@ LogMessage::~LogMessage() { } else { default_delegate_(stream_, severity_); } - - if (severity_ >= TDF_LOG_FATAL) { - abort(); - } }