From 5e6823a0ba08c471f7e0f20476132d90428cf5cc Mon Sep 17 00:00:00 2001 From: wwwcg Date: Thu, 1 Aug 2024 21:56:10 +0800 Subject: [PATCH 01/47] fix(ios): add exception handle process for jsc (#3976) * fix(ios): add exception handle process for jsc * chore(ios): remove unnecessary exception check log --- driver/js/include/driver/scope.h | 19 +++++++++ driver/js/src/modules/timer_module.cc | 9 +++++ driver/js/src/napi/jsc/jsc_ctx.cc | 8 +--- driver/js/src/scope.cc | 1 + .../ios/base/executors/HippyJSExecutor.mm | 39 ++++++++++++++++++- 5 files changed, 67 insertions(+), 9 deletions(-) diff --git a/driver/js/include/driver/scope.h b/driver/js/include/driver/scope.h index bfed62e896b..0daf07568c6 100644 --- a/driver/js/include/driver/scope.h +++ b/driver/js/include/driver/scope.h @@ -166,6 +166,24 @@ class Scope : public std::enable_shared_from_this { inline std::any GetTurbo() { return turbo_; } inline void SetTurbo(std::any turbo) { turbo_ = turbo; } inline std::weak_ptr GetEngine() { return engine_; } + inline std::unique_ptr& GetRegisterMap() { return extra_function_map_; } + + inline bool RegisterExtraCallback(const std::string& key, RegisterFunction func) { + if (!func) { + return false; + } + (*extra_function_map_)[key] = std::move(func); + return true; + } + + inline bool GetExtraCallback(const std::string& key, RegisterFunction& outFunc) const { + auto it = extra_function_map_->find(key); + if (it != extra_function_map_->end()) { + outFunc = it->second; + return true; + } + return false; + } inline std::any GetClassTemplate(const string_view& name) { auto engine = engine_.lock(); @@ -466,6 +484,7 @@ class Scope : public std::enable_shared_from_this { std::any bridge_; std::any turbo_; std::string name_; + std::unique_ptr extra_function_map_; // store some callback functions uint32_t call_ui_function_callback_id_; std::unordered_map> call_ui_function_callback_holder_; std::unordered_map>>> diff --git a/driver/js/src/modules/timer_module.cc b/driver/js/src/modules/timer_module.cc index 771fe2b737e..fb38c6b5b94 100644 --- a/driver/js/src/modules/timer_module.cc +++ b/driver/js/src/modules/timer_module.cc @@ -216,6 +216,15 @@ std::shared_ptr TimerModule::Start( } std::shared_ptr context = scope->GetContext(); context->CallFunction(function, context->GetGlobalObject(), 0, nullptr); + +#if defined(JS_JSC) + // exception check for jsc + RegisterFunction func; + if (scope->GetExtraCallback(kAsyncTaskEndKey, func)) { + func(nullptr); + } +#endif /* defined(JS_JSC) */ + if (!repeat) { timer_map->erase(task_id); } diff --git a/driver/js/src/napi/jsc/jsc_ctx.cc b/driver/js/src/napi/jsc/jsc_ctx.cc index da7bdd15c6e..21669d0905f 100644 --- a/driver/js/src/napi/jsc/jsc_ctx.cc +++ b/driver/js/src/napi/jsc/jsc_ctx.cc @@ -359,7 +359,6 @@ std::shared_ptr JSCCtx::DefineClass(const string_view& name, JSObjectCallAsFunction(context_, define_property, object, 3, values, &exception); if (exception) { SetException(std::make_shared(context_, exception)); - FOOTSTONE_LOG(ERROR) << GetExceptionMessage(exception_); return nullptr; } } @@ -895,7 +894,6 @@ std::shared_ptr JSCCtx::CallFunction(const std::shared_ptr& auto function_object = JSValueToObject(context_, function_value->value_, &exception); if (exception) { SetException(std::make_shared(context_, exception)); - FOOTSTONE_LOG(ERROR) << GetExceptionMessage(exception_); return nullptr; } @@ -903,7 +901,6 @@ std::shared_ptr JSCCtx::CallFunction(const std::shared_ptr& auto receiver_object = JSValueToObject(context_, receiver_value->value_, &exception); if (exception) { SetException(std::make_shared(context_, exception)); - FOOTSTONE_LOG(ERROR) << GetExceptionMessage(exception_); return nullptr; } @@ -911,7 +908,6 @@ std::shared_ptr JSCCtx::CallFunction(const std::shared_ptr& auto ret_value_ref = JSObjectCallAsFunction(context_, function_object, receiver_object, 0, nullptr, &exception); if (exception) { SetException(std::make_shared(context_, exception)); - FOOTSTONE_LOG(ERROR) << GetExceptionMessage(exception_); return nullptr; } return std::make_shared(context_, ret_value_ref); @@ -926,7 +922,6 @@ std::shared_ptr JSCCtx::CallFunction(const std::shared_ptr& auto ret_value_ref = JSObjectCallAsFunction(context_, function_object, receiver_object, argc, values, &exception); if (exception) { SetException(std::make_shared(context_, exception)); - FOOTSTONE_LOG(ERROR) << GetExceptionMessage(exception_); return nullptr; } @@ -939,7 +934,7 @@ std::shared_ptr JSCCtx::CallFunction(const std::shared_ptr& string_view JSCCtx::GetExceptionMessage(const std::shared_ptr& exception) { if (!exception) { - return string_view(); + return string_view(""); } std::shared_ptr msg_obj = CopyNamedProperty(exception, string_view(kMessageStr, ARRAY_SIZE(kMessageStr) - 1)); @@ -1142,7 +1137,6 @@ std::shared_ptr JSCCtx::RunScript(const string_view& data, if (exception) { SetException(std::make_shared(context_, exception)); - FOOTSTONE_LOG(ERROR) << GetExceptionMessage(exception_); return nullptr; } diff --git a/driver/js/src/scope.cc b/driver/js/src/scope.cc index 56a97e40e76..8880775e5af 100644 --- a/driver/js/src/scope.cc +++ b/driver/js/src/scope.cc @@ -126,6 +126,7 @@ Scope::Scope(std::weak_ptr engine, context_(nullptr), name_(std::move(name)), call_ui_function_callback_id_(0), + extra_function_map_(std::make_unique()), performance_(std::make_shared()) {} Scope::~Scope() { diff --git a/framework/ios/base/executors/HippyJSExecutor.mm b/framework/ios/base/executors/HippyJSExecutor.mm index c01e4fad905..c6aed485dca 100644 --- a/framework/ios/base/executors/HippyJSExecutor.mm +++ b/framework/ios/base/executors/HippyJSExecutor.mm @@ -75,7 +75,7 @@ constexpr char kGlobalKey[] = "global"; constexpr char kHippyKey[] = "Hippy"; static NSString * const kHippyNativeGlobalKey = @"__HIPPYNATIVEGLOBAL__"; - +static const char * kHippyExceptionEventName = "uncaughtException"; @interface HippyJSExecutor () { @@ -102,8 +102,18 @@ - (void)setup { const char *pName = [self.enginekey UTF8String] ?: ""; auto scope = engine->GetEngine()->CreateScope(pName); + __weak __typeof(self)weakSelf = self; + hippy::base::RegisterFunction taskEndCB = [weakSelf](void *) { + @autoreleasepool { + HippyJSExecutor *strongSelf = weakSelf; + if (strongSelf) { + handleJsExcepiton(strongSelf->_pScope); + } + } + }; + scope->RegisterExtraCallback(hippy::kAsyncTaskEndKey, taskEndCB); + dispatch_semaphore_t scopeSemaphore = dispatch_semaphore_create(0); - __weak HippyJSExecutor *weakSelf = self; footstone::TimePoint startPoint = footstone::TimePoint::SystemNow(); engine->GetEngine()->GetJsTaskRunner()->PostTask([weakSelf, scopeSemaphore, startPoint](){ @autoreleasepool { @@ -727,4 +737,29 @@ - (NSString *)completeWSURLWithBridge:(HippyBridge *)bridge { return [devInfo assembleFullWSURLWithClientId:clientId contextName:bridge.contextName]; } + +#pragma mark - Exception Handle + +static void handleJsExcepiton(std::shared_ptr scope) { + if (!scope) { + return; + } + std::shared_ptr context = std::static_pointer_cast(scope->GetContext()); + std::shared_ptr exception = std::static_pointer_cast(context->GetException()); + if (exception) { + // if native does not handled, rethrow to js + if (!context->IsExceptionHandled()) { + hippy::vm::VM::HandleException(context, kHippyExceptionEventName, exception); + } + string_view exceptionStrView = context->GetExceptionMessage(exception); + auto errU8Str = StringViewUtils::ConvertEncoding(exceptionStrView, string_view::Encoding::Utf8).utf8_value(); + std::string errStr = StringViewUtils::ToStdString(errU8Str); + NSError *error = HippyErrorWithMessage([NSString stringWithUTF8String:errStr.c_str()]); + HippyFatal(error); + context->SetException(nullptr); + context->SetExceptionHandled(true); + } +} + + @end From 221358d48b87262b82a5bbab4ebd6f8bdcd8944a Mon Sep 17 00:00:00 2001 From: wwwcg Date: Mon, 5 Aug 2024 16:38:28 +0800 Subject: [PATCH 02/47] chore(ios): eliminate code warnings --- driver/js/src/scope.cc | 2 +- .../ios/debug/websocket/HippySRWebSocket.m | 104 +++++++++--------- framework/ios/utils/NSObject+CtxValue.mm | 2 +- 3 files changed, 54 insertions(+), 54 deletions(-) diff --git a/driver/js/src/scope.cc b/driver/js/src/scope.cc index 8880775e5af..e0520bf8e90 100644 --- a/driver/js/src/scope.cc +++ b/driver/js/src/scope.cc @@ -125,8 +125,8 @@ Scope::Scope(std::weak_ptr engine, : engine_(std::move(engine)), context_(nullptr), name_(std::move(name)), - call_ui_function_callback_id_(0), extra_function_map_(std::make_unique()), + call_ui_function_callback_id_(0), performance_(std::make_shared()) {} Scope::~Scope() { diff --git a/framework/ios/debug/websocket/HippySRWebSocket.m b/framework/ios/debug/websocket/HippySRWebSocket.m index d7cbb4f8161..bbe7374dbd1 100644 --- a/framework/ios/debug/websocket/HippySRWebSocket.m +++ b/framework/ios/debug/websocket/HippySRWebSocket.m @@ -111,14 +111,14 @@ @interface _HippySRRunLoopThread : NSThread @implementation NSData (HippySRWebSocket) -- (NSString *)stringBySHA1ThenBase64Encoding; +- (NSString *)stringBySHA1ThenBase64Encoding { return newSHA1String(self.bytes, self.length); } @end @implementation NSString (HippySRWebSocket) -- (NSString *)stringBySHA1ThenBase64Encoding; +- (NSString *)stringBySHA1ThenBase64Encoding { return newSHA1String(self.UTF8String, self.length); } @end @@ -253,7 +253,7 @@ @implementation HippySRWebSocket { static __strong NSData *CRLFCRLF; -+ (void)initialize; ++ (void)initialize { CRLFCRLF = [[NSData alloc] initWithBytes:"\r\n\r\n" length:4]; } - (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray *)protocols { @@ -270,13 +270,13 @@ - (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray *)protocols; +- (instancetype)initWithURL:(NSURL *)URL protocols:(NSArray *)protocols { NSMutableURLRequest *request; if (URL) { @@ -298,7 +298,7 @@ - (instancetype)initWithURL:(NSURL *)URL protocols:(NSArray *)protoc return [self initWithURLRequest:request protocols:protocols]; } -- (void)_HippySR_commonInit; +- (void)_HippySR_commonInit { NSString *scheme = _url.scheme.lowercaseString; assert( @@ -334,7 +334,7 @@ - (void)_HippySR_commonInit; // default handlers } -- (void)assertOnWorkQueue; +- (void)assertOnWorkQueue { assert(dispatch_get_specific((__bridge void *)self) == (__bridge void *)_workQueue); } - (void)dealloc { @@ -358,7 +358,7 @@ - (void)dealloc { #ifndef NDEBUG -- (void)setReadyState:(HippySRReadyState)aReadyState; +- (void)setReadyState:(HippySRReadyState)aReadyState { [self willChangeValueForKey:@"readyState"]; assert(aReadyState > _readyState); @@ -368,7 +368,7 @@ - (void)setReadyState:(HippySRReadyState)aReadyState; #endif -- (void)open; +- (void)open { assert(_url); HippyAssert(_readyState == HippySR_CONNECTING, @"Cannot call -(void)open on HippySRWebSocket more than once"); @@ -379,7 +379,7 @@ - (void)open; } // Calls block on delegate queue -- (void)_performDelegateBlock:(dispatch_block_t)block; +- (void)_performDelegateBlock:(dispatch_block_t)block { if (_delegateOperationQueue) { [_delegateOperationQueue addOperationWithBlock:block]; @@ -389,10 +389,10 @@ - (void)_performDelegateBlock:(dispatch_block_t)block; } } -- (void)setDelegateDispatchQueue:(dispatch_queue_t)queue; +- (void)setDelegateDispatchQueue:(dispatch_queue_t)queue { _delegateDispatchQueue = queue; } -- (BOOL)_checkHandshake:(CFHTTPMessageRef)httpMessage; +- (BOOL)_checkHandshake:(CFHTTPMessageRef)httpMessage { NSString *acceptHeader = CFBridgingRelease(CFHTTPMessageCopyHeaderFieldValue(httpMessage, CFSTR("Sec-WebSocket-Accept"))); @@ -406,7 +406,7 @@ - (BOOL)_checkHandshake:(CFHTTPMessageRef)httpMessage; return [acceptHeader isEqualToString:expectedAccept]; } -- (void)_HTTPHeadersDidFinish; +- (void)_HTTPHeadersDidFinish { NSInteger responseCode = CFHTTPMessageGetResponseStatusCode(_receivedHTTPHeaders); @@ -454,7 +454,7 @@ - (void)_HTTPHeadersDidFinish; }]; } -- (void)_readHTTPHeader; +- (void)_readHTTPHeader { if (_receivedHTTPHeaders == NULL) { _receivedHTTPHeaders = CFHTTPMessageCreateEmpty(NULL, NO); @@ -511,7 +511,7 @@ - (void)didConnect { [self _readHTTPHeader]; } -- (void)_initializeStreams; +- (void)_initializeStreams { assert(_url.port.unsignedIntValue <= UINT32_MAX); uint32_t port = _url.port.unsignedIntValue; @@ -553,7 +553,7 @@ - (void)_initializeStreams; _outputStream.delegate = self; } -- (void)_connect; +- (void)_connect { if (!_scheduledRunloops.count) { [self scheduleInRunLoop:[NSRunLoop HippySR_networkRunLoop] forMode:NSDefaultRunLoopMode]; @@ -563,7 +563,7 @@ - (void)_connect; [_inputStream open]; } -- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode; +- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode { [_outputStream scheduleInRunLoop:aRunLoop forMode:mode]; [_inputStream scheduleInRunLoop:aRunLoop forMode:mode]; @@ -571,7 +571,7 @@ - (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode; [_scheduledRunloops addObject:@[aRunLoop, mode]]; } -- (void)unscheduleFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode; +- (void)unscheduleFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode { [_outputStream removeFromRunLoop:aRunLoop forMode:mode]; [_inputStream removeFromRunLoop:aRunLoop forMode:mode]; @@ -583,7 +583,7 @@ - (void)close { [self closeWithCode:HippySRStatusCodeNormal reason:nil]; } -- (void)closeWithCode:(NSInteger)code reason:(NSString *)reason; +- (void)closeWithCode:(NSInteger)code reason:(NSString *)reason { dispatch_async(_workQueue, ^{ if (self.readyState == HippySR_CLOSING || self.readyState == HippySR_CLOSED) { @@ -631,7 +631,7 @@ - (void)closeWithCode:(NSInteger)code reason:(NSString *)reason; }); } -- (void)_closeWithProtocolError:(NSString *)message; +- (void)_closeWithProtocolError:(NSString *)message { // Need to shunt this on the _callbackQueue first to see if they received any messages [self _performDelegateBlock:^{ @@ -642,7 +642,7 @@ - (void)_closeWithProtocolError:(NSString *)message; }]; } -- (void)_failWithError:(NSError *)error; +- (void)_failWithError:(NSError *)error { dispatch_async(_workQueue, ^{ if (self.readyState != HippySR_CLOSED) { @@ -663,7 +663,7 @@ - (void)_failWithError:(NSError *)error; }); } -- (void)_writeData:(NSData *)data; +- (void)_writeData:(NSData *)data { [self assertOnWorkQueue]; @@ -674,7 +674,7 @@ - (void)_writeData:(NSData *)data; [self _pumpWriting]; } -- (void)send:(id)data; +- (void)send:(id)data { HippyAssert(self.readyState != HippySR_CONNECTING, @"Invalid State: Cannot call send: until connection is open"); // TODO: maybe not copy this for performance @@ -692,7 +692,7 @@ - (void)send:(id)data; }); } -- (void)sendPing:(NSData *)data; +- (void)sendPing:(NSData *)data { HippyAssert(self.readyState == HippySR_OPEN, @"Invalid State: Cannot call send: until connection is open"); // TODO: maybe not copy this for performance @@ -702,7 +702,7 @@ - (void)sendPing:(NSData *)data; }); } -- (void)handlePing:(NSData *)pingData; +- (void)handlePing:(NSData *)pingData { // Need to pingpong this off _callbackQueue first to make sure messages happen in order [self _performDelegateBlock:^{ @@ -712,7 +712,7 @@ - (void)handlePing:(NSData *)pingData; }]; } -- (void)handlePong:(NSData *)pongData; +- (void)handlePong:(NSData *)pongData { HippySRLog(@"Received pong"); [self _performDelegateBlock:^{ @@ -761,7 +761,7 @@ static inline BOOL closeCodeIsValid(int closeCode) { // encoded data with value /reason/, the interpretation of which is not // defined by this specification. -- (void)handleCloseWithData:(NSData *)data; +- (void)handleCloseWithData:(NSData *)data { size_t dataSize = data.length; __block uint16_t closeCode = 0; @@ -800,7 +800,7 @@ - (void)handleCloseWithData:(NSData *)data; }); } -- (void)_disconnect; +- (void)_disconnect { [self assertOnWorkQueue]; HippySRLog(@"Trying to disconnect"); @@ -808,7 +808,7 @@ - (void)_disconnect; [self _pumpWriting]; } -- (void)_handleFrameWithData:(NSData *)frameData opCode:(NSInteger)opcode; +- (void)_handleFrameWithData:(NSData *)frameData opCode:(NSInteger)opcode { // Check that the current data is valid UTF8 @@ -854,7 +854,7 @@ - (void)_handleFrameWithData:(NSData *)frameData opCode:(NSInteger)opcode; } } -- (void)_handleFrameHeader:(frame_header)frame_header curData:(NSData *)curData; +- (void)_handleFrameHeader:(frame_header)frame_header curData:(NSData *)curData { assert(frame_header.opcode != 0); @@ -936,7 +936,7 @@ - (void)_handleFrameHeader:(frame_header)frame_header curData:(NSData *)curData; static const uint8_t HippySRMaskMask = 0x80; static const uint8_t HippySRPayloadLenMask = 0x7F; -- (void)_readFrameContinue; +- (void)_readFrameContinue { assert((_currentFrameCount == 0 && _currentFrameOpcode == 0) || (_currentFrameCount > 0 && _currentFrameOpcode > 0)); @@ -1019,7 +1019,7 @@ - (void)_readFrameContinue; } readToCurrentFrame:NO unmaskBytes:NO]; } -- (void)_readFrameNew; +- (void)_readFrameNew { dispatch_async(_workQueue, ^{ self->_currentFrameData.length = 0; @@ -1033,7 +1033,7 @@ - (void)_readFrameNew; }); } -- (void)_pumpWriting; +- (void)_pumpWriting { [self assertOnWorkQueue]; @@ -1078,7 +1078,7 @@ - (void)_pumpWriting; } } -- (void)_addConsumerWithScanner:(stream_scanner)consumer callback:(data_callback)callback; +- (void)_addConsumerWithScanner:(stream_scanner)consumer callback:(data_callback)callback { [self assertOnWorkQueue]; [self _addConsumerWithScanner:consumer callback:callback dataLength:0]; @@ -1087,7 +1087,7 @@ - (void)_addConsumerWithScanner:(stream_scanner)consumer callback:(data_callback - (void)_addConsumerWithDataLength:(size_t)dataLength callback:(data_callback)callback readToCurrentFrame:(BOOL)readToCurrentFrame - unmaskBytes:(BOOL)unmaskBytes; + unmaskBytes:(BOOL)unmaskBytes { [self assertOnWorkQueue]; assert(dataLength); @@ -1097,7 +1097,7 @@ - (void)_addConsumerWithDataLength:(size_t)dataLength [self _pumpScanner]; } -- (void)_addConsumerWithScanner:(stream_scanner)consumer callback:(data_callback)callback dataLength:(size_t)dataLength; +- (void)_addConsumerWithScanner:(stream_scanner)consumer callback:(data_callback)callback dataLength:(size_t)dataLength { [self assertOnWorkQueue]; [_consumers addObject:[_consumerPool consumerWithScanner:consumer handler:callback bytesNeeded:dataLength readToCurrentFrame:NO unmaskBytes:NO]]; @@ -1106,10 +1106,10 @@ - (void)_addConsumerWithScanner:(stream_scanner)consumer callback:(data_callback static const char CRLFCRLFBytes[] = { '\r', '\n', '\r', '\n' }; -- (void)_readUntilHeaderCompleteWithCallback:(data_callback)dataHandler; +- (void)_readUntilHeaderCompleteWithCallback:(data_callback)dataHandler { [self _readUntilBytes:CRLFCRLFBytes length:sizeof(CRLFCRLFBytes) callback:dataHandler]; } -- (void)_readUntilBytes:(const void *)bytes length:(size_t)length callback:(data_callback)dataHandler; +- (void)_readUntilBytes:(const void *)bytes length:(size_t)length callback:(data_callback)dataHandler { // TODO: optimize so this can continue from where we last searched stream_scanner consumer = ^size_t(NSData *data) { @@ -1242,7 +1242,7 @@ - (BOOL)_innerPumpScanner { return didWork; } -- (void)_pumpScanner; +- (void)_pumpScanner { [self assertOnWorkQueue]; @@ -1262,7 +1262,7 @@ - (void)_pumpScanner; static const size_t HippySRFrameHeaderOverhead = 32; -- (void)_sendFrameWithOpcode:(HippySROpCode)opCode data:(id)data; +- (void)_sendFrameWithOpcode:(HippySROpCode)opCode data:(id)data { [self assertOnWorkQueue]; @@ -1333,7 +1333,7 @@ - (void)_sendFrameWithOpcode:(HippySROpCode)opCode data:(id)data; [self _writeData:frameData]; } -- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode; +- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode { if (_secure && !_pinnedCertFound && (eventCode == NSStreamEventHasBytesAvailable || eventCode == NSStreamEventHasSpaceAvailable)) { NSArray *sslCerts = _urlRequest.HippySR_SSLPinnedCertificates; @@ -1466,7 +1466,7 @@ - (void)setupWithScanner:(stream_scanner)scanner handler:(data_callback)handler bytesNeeded:(size_t)bytesNeeded readToCurrentFrame:(BOOL)readToCurrentFrame - unmaskBytes:(BOOL)unmaskBytes; + unmaskBytes:(BOOL)unmaskBytes { _consumer = [scanner copy]; _handler = [handler copy]; @@ -1483,7 +1483,7 @@ @implementation HippySRIOConsumerPool { NSMutableArray *_bufferedConsumers; } -- (instancetype)initWithBufferCapacity:(NSUInteger)poolSize; +- (instancetype)initWithBufferCapacity:(NSUInteger)poolSize { if ((self = [super init])) { _poolSize = poolSize; @@ -1500,7 +1500,7 @@ - (HippySRIOConsumer *)consumerWithScanner:(stream_scanner)scanner handler:(data_callback)handler bytesNeeded:(size_t)bytesNeeded readToCurrentFrame:(BOOL)readToCurrentFrame - unmaskBytes:(BOOL)unmaskBytes; + unmaskBytes:(BOOL)unmaskBytes { HippySRIOConsumer *consumer = nil; if (_bufferedConsumers.count) { @@ -1515,7 +1515,7 @@ - (HippySRIOConsumer *)consumerWithScanner:(stream_scanner)scanner return consumer; } -- (void)returnConsumer:(HippySRIOConsumer *)consumer; +- (void)returnConsumer:(HippySRIOConsumer *)consumer { if (_bufferedConsumers.count < _poolSize) { [_bufferedConsumers addObject:consumer]; @@ -1526,24 +1526,24 @@ - (void)returnConsumer:(HippySRIOConsumer *)consumer; @implementation NSURLRequest (CertificateAdditions) -- (NSArray *)HippySR_SSLPinnedCertificates; +- (NSArray *)HippySR_SSLPinnedCertificates { return [NSURLProtocol propertyForKey:@"HippySR_SSLPinnedCertificates" inRequest:self]; } @end @implementation NSMutableURLRequest (CertificateAdditions) -- (NSArray *)HippySR_SSLPinnedCertificates; +- (NSArray *)HippySR_SSLPinnedCertificates { return [NSURLProtocol propertyForKey:@"HippySR_SSLPinnedCertificates" inRequest:self]; } -- (void)setHippySR_SSLPinnedCertificates:(NSArray *)HippySR_SSLPinnedCertificates; +- (void)setHippySR_SSLPinnedCertificates:(NSArray *)HippySR_SSLPinnedCertificates { [NSURLProtocol setProperty:HippySR_SSLPinnedCertificates forKey:@"HippySR_SSLPinnedCertificates" inRequest:self]; } @end @implementation NSURL (HippySRWebSocket) -- (NSString *)HippySR_origin; +- (NSString *)HippySR_origin { NSString *scheme = self.scheme.lowercaseString; @@ -1597,7 +1597,7 @@ - (instancetype)init { return self; } -- (void)main; +- (void)main { @autoreleasepool { _runLoop = [NSRunLoop currentRunLoop]; @@ -1617,7 +1617,7 @@ - (void)step { // Does nothing } -- (NSRunLoop *)runLoop; +- (NSRunLoop *)runLoop { dispatch_group_wait(_waitGroup, DISPATCH_TIME_FOREVER); return _runLoop; diff --git a/framework/ios/utils/NSObject+CtxValue.mm b/framework/ios/utils/NSObject+CtxValue.mm index 1ee6b0c3fef..00cf1ab915f 100644 --- a/framework/ios/utils/NSObject+CtxValue.mm +++ b/framework/ios/utils/NSObject+CtxValue.mm @@ -30,7 +30,7 @@ @implementation NSObject (CtxValue) -- (CtxValuePtr)convertToCtxValue:(const CtxPtr &)context; { +- (CtxValuePtr)convertToCtxValue:(const CtxPtr &)context { @autoreleasepool { HippyLogWarn(@"%@ No convertToCtxValue method", NSStringFromClass([self class])); std::unordered_map valueMap; From e390c33a87b96dbe8f154e3c39d9f2b14a0dd4c1 Mon Sep 17 00:00:00 2001 From: siguangli Date: Tue, 6 Aug 2024 12:10:49 +0800 Subject: [PATCH 03/47] fix(android): onGlobalLayout use root view size (#3982) Co-authored-by: maxli --- .../com/tencent/mtt/hippy/utils/TimeMonitor.java | 4 ++-- .../java/com/tencent/mtt/hippy/HippyRootView.java | 13 +++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/modules/android/hippy_support/src/main/java/com/tencent/mtt/hippy/utils/TimeMonitor.java b/modules/android/hippy_support/src/main/java/com/tencent/mtt/hippy/utils/TimeMonitor.java index ab0a338b10a..fa3673120dc 100644 --- a/modules/android/hippy_support/src/main/java/com/tencent/mtt/hippy/utils/TimeMonitor.java +++ b/modules/android/hippy_support/src/main/java/com/tencent/mtt/hippy/utils/TimeMonitor.java @@ -157,9 +157,9 @@ void end() { void print() { if (mMonitorPoints != null) { - LogUtils.i(TAG, "group " + name + ", totalTime " + totalTime + "ms"); + LogUtils.e(TAG, "group " + name + ", totalTime " + totalTime + "ms"); for (MonitorPoint monitorPoint : mMonitorPoints) { - LogUtils.i(TAG, + LogUtils.e(TAG, monitorPoint.key + ": " + (monitorPoint.endTime - monitorPoint.startTime) + "ms"); } diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/HippyRootView.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/HippyRootView.java index 23a1cb21eff..585aa321c64 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/HippyRootView.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/HippyRootView.java @@ -34,6 +34,7 @@ import com.tencent.renderer.NativeRenderContext; import com.tencent.renderer.NativeRendererManager; +import java.lang.ref.WeakReference; import java.util.Map; import static android.content.res.Configuration.ORIENTATION_UNDEFINED; @@ -116,7 +117,7 @@ protected void onDetachedFromWindow() { private GlobalLayoutListener getGlobalLayoutListener() { if (mGlobalLayoutListener == null) { - mGlobalLayoutListener = new GlobalLayoutListener(); + mGlobalLayoutListener = new GlobalLayoutListener(this); } return mGlobalLayoutListener; } @@ -124,6 +125,11 @@ private GlobalLayoutListener getGlobalLayoutListener() { private class GlobalLayoutListener implements ViewTreeObserver.OnGlobalLayoutListener { private int mOrientation = ORIENTATION_UNDEFINED; + private final WeakReference mRootViewRef; + + GlobalLayoutListener(View rootView) { + mRootViewRef = new WeakReference<>(rootView); + } @Override public void onGlobalLayout() { @@ -137,7 +143,10 @@ public void onGlobalLayout() { sendOrientationChangeEvent(mOrientation); NativeRender nativeRenderer = NativeRendererManager.getNativeRenderer(context); if (nativeRenderer != null) { - nativeRenderer.updateDimension(-1, -1); + View rootView = mRootViewRef.get(); + int width = (rootView != null) ? rootView.getWidth() : -1; + int height = (rootView != null) ? rootView.getHeight() : -1; + nativeRenderer.updateDimension(width, height); } } } From 73e814eff1e8ccb00b6f949e8901e2b4749b183e Mon Sep 17 00:00:00 2001 From: wwwcg Date: Tue, 6 Aug 2024 18:29:27 +0800 Subject: [PATCH 04/47] refactor(ios): remove unused data structure in waterfall item --- .../waterfalllist/HippyShadowListView.h | 26 +-- .../waterfalllist/HippyShadowListView.m | 52 +++++ .../waterfalllist/HippyShadowListView.mm | 181 ------------------ .../waterfalllist/HippyShadowWaterfallItem.h | 9 +- ...fallItem.mm => HippyShadowWaterfallItem.m} | 0 .../waterfalllist/HippyWaterfallView.mm | 6 +- 6 files changed, 66 insertions(+), 208 deletions(-) create mode 100644 renderer/native/ios/renderer/component/waterfalllist/HippyShadowListView.m delete mode 100644 renderer/native/ios/renderer/component/waterfalllist/HippyShadowListView.mm rename renderer/native/ios/renderer/component/waterfalllist/{HippyShadowWaterfallItem.mm => HippyShadowWaterfallItem.m} (100%) diff --git a/renderer/native/ios/renderer/component/waterfalllist/HippyShadowListView.h b/renderer/native/ios/renderer/component/waterfalllist/HippyShadowListView.h index d055174d6ff..3ff7b045ab2 100644 --- a/renderer/native/ios/renderer/component/waterfalllist/HippyShadowListView.h +++ b/renderer/native/ios/renderer/component/waterfalllist/HippyShadowListView.h @@ -25,30 +25,12 @@ NS_ASSUME_NONNULL_BEGIN -@interface WaterfallItemChangeContext : NSObject - -- (NSHashTable<__kindof HippyShadowView *> *)addedItems; -- (NSHashTable<__kindof HippyShadowView *> *)frameChangedItems; -- (NSSet<__kindof HippyShadowView *> *)deletedItems; -- (NSHashTable<__kindof HippyShadowView *> *)movedItems; - -/// Clear all items recorded. -- (void)clear; - -/// Whether has changed item. -- (BOOL)hasChanges; - -/// Get all chaned items. -- (NSSet *)allChangedItems; - -@end - +/// ListView's shadowView @interface HippyShadowListView : HippyShadowView -///// Whether current ShadowList is dirty. -//@property (nonatomic, assign) BOOL isDirty; - -@property(nonatomic, readonly, strong)WaterfallItemChangeContext *itemChangeContext; +/// Whether current ShadowList is dirty. +/// Used to determine whether the list needs reload. +@property (nonatomic, assign) BOOL isDirty; @end diff --git a/renderer/native/ios/renderer/component/waterfalllist/HippyShadowListView.m b/renderer/native/ios/renderer/component/waterfalllist/HippyShadowListView.m new file mode 100644 index 00000000000..5f482d35a62 --- /dev/null +++ b/renderer/native/ios/renderer/component/waterfalllist/HippyShadowListView.m @@ -0,0 +1,52 @@ +/*! + * 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 "HippyShadowListView.h" +#import "HippyWaterfallView.h" +#import "HippyAssert.h" + + +@implementation HippyShadowListView + +- (void)insertHippySubview:(HippyShadowView *)subview atIndex:(NSUInteger)atIndex { + [super insertHippySubview:subview atIndex:atIndex]; + if ([subview isKindOfClass:[HippyShadowWaterfallItem class]]) { + HippyShadowWaterfallItem *objectItem = (HippyShadowWaterfallItem *)subview; + objectItem.observer = self; + } + self.isDirty = YES; +} + +- (void)removeHippySubview:(HippyShadowView *)subview { + [super removeHippySubview:subview]; + if ([subview isKindOfClass:[HippyShadowWaterfallItem class]]) { + HippyShadowWaterfallItem *objectItem = (HippyShadowWaterfallItem *)subview; + objectItem.observer = nil; + } + self.isDirty = YES; +} + +- (void)itemFrameChanged:(__kindof HippyShadowWaterfallItem *)item { + self.isDirty = YES; +} + +@end diff --git a/renderer/native/ios/renderer/component/waterfalllist/HippyShadowListView.mm b/renderer/native/ios/renderer/component/waterfalllist/HippyShadowListView.mm deleted file mode 100644 index cf19e5c4556..00000000000 --- a/renderer/native/ios/renderer/component/waterfalllist/HippyShadowListView.mm +++ /dev/null @@ -1,181 +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 "HippyShadowListView.h" -#import "HippyWaterfallView.h" -#import "HippyAssert.h" - -@interface WaterfallItemChangeContext () { - NSMutableSet *_deletedItems; - NSHashTable *_addedItems; - NSHashTable *_movedItems; - NSHashTable *_frameChangedItems; -} -//append methods -- (void)appendDeletedItem:(HippyShadowView *)objectView; -- (void)appendAddedItem:(HippyShadowView *)objectView; -- (void)appendMovedItem:(HippyShadowView *)objectView; -- (void)appendFrameChangedItem:(HippyShadowView *)objectView; - -@end - -@implementation WaterfallItemChangeContext - -- (instancetype)init { - self = [super init]; - if (self) { - _deletedItems = [NSMutableSet set]; - _addedItems = [NSHashTable weakObjectsHashTable]; - _movedItems = [NSHashTable weakObjectsHashTable]; - _frameChangedItems = [NSHashTable weakObjectsHashTable]; - } - return self; -} - -- (id)copyWithZone:(NSZone *)zone { - WaterfallItemChangeContext *context = [[WaterfallItemChangeContext allocWithZone:zone] init]; - context->_deletedItems = [_deletedItems mutableCopy]; - context->_addedItems = [_addedItems copy]; - context->_movedItems = [_movedItems copy]; - context->_frameChangedItems = [_frameChangedItems copy]; - return context; -} - -- (void)appendDeletedItem:(__kindof HippyShadowView *)objectView { - [_deletedItems addObject:objectView]; -} - -- (void)appendAddedItem:(__kindof HippyShadowView *)objectView{ - [_addedItems addObject:objectView]; -} - -- (void)appendMovedItem:(__kindof HippyShadowView *)objectView { - [_movedItems addObject:objectView]; -} - -- (void)appendFrameChangedItem:(__kindof HippyShadowView *)objectView { - // _frameChangedItems may be also in other addedItems/movedItems - [_frameChangedItems addObject:objectView]; -} - -- (NSSet<__kindof HippyShadowView *> *)deletedItems { - return [_deletedItems copy]; -} - -- (NSMapTable<__kindof HippyShadowView *, NSNumber *> *)addedItems { - return [_addedItems copy]; -} - -- (NSMapTable<__kindof HippyShadowView *, NSValue *> *)movedItems { - return [_movedItems copy]; -} - -- (NSHashTable<__kindof HippyShadowView *> *)frameChangedItems { - return [_frameChangedItems copy]; -} - -- (BOOL)hasChanges { - return _addedItems.count != 0 || _deletedItems.count != 0 || - _movedItems.count != 0 || _frameChangedItems.count != 0; -} - -- (NSSet *)allChangedItems { - NSMutableSet *allChanges = [NSMutableSet set]; - [allChanges addObjectsFromArray:_addedItems.allObjects]; - [allChanges addObjectsFromArray:_deletedItems.allObjects]; - [allChanges addObjectsFromArray:_movedItems.allObjects]; - [allChanges addObjectsFromArray:_frameChangedItems.allObjects]; - return allChanges; -} - -- (void)clear { - [_deletedItems removeAllObjects]; - [_addedItems removeAllObjects]; - [_movedItems removeAllObjects]; - [_frameChangedItems removeAllObjects]; -} - -- (NSString *)description { - NSString *description = [NSString stringWithFormat:@"<%@: %p deleted items: %lu, added items: %lu, moved items: %lu, frame changed items: %lu>", - NSStringFromClass([self class]), - self, - [_deletedItems count], - [_addedItems count], - [_movedItems count], - [_frameChangedItems count]]; - return description; -} - -@end - - -#pragma mark - - -@interface HippyShadowListView () { - WaterfallItemChangeContext *_itemChangeContext; -} - -@end - -@implementation HippyShadowListView - -- (instancetype)init{ - self = [super init]; - if (self) { - _itemChangeContext = [[WaterfallItemChangeContext alloc] init]; - } - return self; -} - -- (WaterfallItemChangeContext *)itemChangeContext { - return _itemChangeContext; -} - -- (void)insertHippySubview:(HippyShadowView *)subview atIndex:(NSUInteger)atIndex { - [super insertHippySubview:subview atIndex:atIndex]; - if ([subview isKindOfClass:[HippyShadowWaterfallItem class]]) { - HippyShadowWaterfallItem *objectItem = (HippyShadowWaterfallItem *)subview; - objectItem.observer = self; - } - [_itemChangeContext appendAddedItem:subview]; -} - -- (void)removeHippySubview:(HippyShadowView *)subview { - [super removeHippySubview:subview]; - if ([subview isKindOfClass:[HippyShadowWaterfallItem class]]) { - HippyShadowWaterfallItem *objectItem = (HippyShadowWaterfallItem *)subview; - objectItem.observer = nil; - } - [_itemChangeContext appendDeletedItem:subview]; -} - -- (void)moveHippySubview:(id)subview toIndex:(NSUInteger)atIndex { - [super moveHippySubview:subview toIndex:atIndex]; - [_itemChangeContext appendMovedItem:subview]; -} - -- (void)itemFrameChanged:(__kindof HippyShadowWaterfallItem *)item { - [_itemChangeContext appendFrameChangedItem:item]; -} - - -@end diff --git a/renderer/native/ios/renderer/component/waterfalllist/HippyShadowWaterfallItem.h b/renderer/native/ios/renderer/component/waterfalllist/HippyShadowWaterfallItem.h index 7c123460d2f..fee091dcf58 100644 --- a/renderer/native/ios/renderer/component/waterfalllist/HippyShadowWaterfallItem.h +++ b/renderer/native/ios/renderer/component/waterfalllist/HippyShadowWaterfallItem.h @@ -29,14 +29,19 @@ NS_ASSUME_NONNULL_BEGIN @protocol HippyShadowWaterfallItemFrameChangedProtocol @required +/// Calledn when item frame changed +/// - Parameter item: shadow waterfall item - (void)itemFrameChanged:(__kindof HippyShadowWaterfallItem *)item; @end +/// Waterfall item's shadowView @interface HippyShadowWaterfallItem : HippyShadowView -@property(nonatomic, assign, getter=isLayoutDirty) BOOL layoutDirty; -@property(nonatomic, weak) id observer; +@property (nonatomic, assign, getter=isLayoutDirty) BOOL layoutDirty; + +/// frame change observer, usually is shadowListView +@property (nonatomic, weak) id observer; @end diff --git a/renderer/native/ios/renderer/component/waterfalllist/HippyShadowWaterfallItem.mm b/renderer/native/ios/renderer/component/waterfalllist/HippyShadowWaterfallItem.m similarity index 100% rename from renderer/native/ios/renderer/component/waterfalllist/HippyShadowWaterfallItem.mm rename to renderer/native/ios/renderer/component/waterfalllist/HippyShadowWaterfallItem.m diff --git a/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.mm b/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.mm index f46f7ddbf61..78925f3d7b3 100644 --- a/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.mm +++ b/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.mm @@ -198,11 +198,11 @@ - (BOOL)isManualScrolling { - (void)hippyBridgeDidFinishTransaction { HippyShadowListView *listNode = self.hippyShadowView; - if (!_dataSource || (listNode && listNode.itemChangeContext.hasChanges)) { - HippyLogTrace(@"🔥 %@ Reload %@", self.hippyTag, [[listNode itemChangeContext] description]); + if (!_dataSource || (listNode && listNode.isDirty)) { + HippyLogTrace(@"🔥 %@ Reload", self.hippyTag); [self cacheVisibleCellViewsForReuse]; [self reloadData]; - [listNode.itemChangeContext clear]; + listNode.isDirty = NO; } } From 4b2506e59b522fa0648620a2e0f244422a958a09 Mon Sep 17 00:00:00 2001 From: wwwcg Date: Tue, 6 Aug 2024 18:30:12 +0800 Subject: [PATCH 05/47] refactor(ios): subcomponents to hippySubviews prop for compatibility Earlier Hippy3 versions used subcomponents to represent children, For better compatibility with Hippy2, change back to hippySubviews --- renderer/native/ios/renderer/HippyComponent.h | 2 +- .../ios/renderer/HippyRootShadowView.mm | 2 +- .../native/ios/renderer/HippyUIManager.mm | 4 ++-- .../listview/HippyNextBaseListView.mm | 2 +- .../component/scrollview/HippyScrollView.mm | 2 +- .../NativeRenderSmartViewPagerView.mm | 4 ++-- .../component/text/HippyShadowText.mm | 10 +++++----- .../ios/renderer/component/text/HippyText.mm | 6 +++--- .../component/text/HippyTextManager.mm | 4 ++-- .../component/view/HippyShadowView.mm | 14 ++++++------- .../view/UIView+DirectionalLayout.mm | 2 +- .../renderer/component/view/UIView+Hippy.mm | 20 +++++++++---------- .../waterfalllist/HippyShadowWaterfallItem.m | 2 +- .../waterfalllist/HippyWaterfallView.mm | 2 +- 14 files changed, 38 insertions(+), 38 deletions(-) diff --git a/renderer/native/ios/renderer/HippyComponent.h b/renderer/native/ios/renderer/HippyComponent.h index 66cebab031d..9c44b1af7b4 100644 --- a/renderer/native/ios/renderer/HippyComponent.h +++ b/renderer/native/ios/renderer/HippyComponent.h @@ -47,7 +47,7 @@ typedef void (^HippyDirectEventBlock)(NSDictionary *body); @property (nonatomic, weak) __kindof id parent; /// Subviews of current component -- (NSArray<__kindof id> *)subcomponents; +- (NSArray<__kindof id> *)hippySubviews; /// Inset /// - Parameters: diff --git a/renderer/native/ios/renderer/HippyRootShadowView.mm b/renderer/native/ios/renderer/HippyRootShadowView.mm index 8609254e851..4c77c621b76 100644 --- a/renderer/native/ios/renderer/HippyRootShadowView.mm +++ b/renderer/native/ios/renderer/HippyRootShadowView.mm @@ -30,7 +30,7 @@ - (void)applySizeConstraints { } - (void)amendLayoutBeforeMount:(NSMutableSet *)blocks { - for (HippyShadowView *renderObject in self.subcomponents) { + for (HippyShadowView *renderObject in self.hippySubviews) { [renderObject amendLayoutBeforeMount:blocks]; } } diff --git a/renderer/native/ios/renderer/HippyUIManager.mm b/renderer/native/ios/renderer/HippyUIManager.mm index 23e9dfb2169..c063ad487ad 100644 --- a/renderer/native/ios/renderer/HippyUIManager.mm +++ b/renderer/native/ios/renderer/HippyUIManager.mm @@ -157,7 +157,7 @@ - (void)removeAllObjects { static void NativeRenderTraverseViewNodes(id view, void (^block)(id)) { if (view.hippyTag != nil) { block(view); - for (id subview in view.subcomponents) { + for (id subview in view.hippySubviews) { NativeRenderTraverseViewNodes(subview, block); } } @@ -597,7 +597,7 @@ - (UIView *)createViewRecursiveFromRenderObjectWithNOLock:(HippyShadowView *)sha } NSUInteger index = 0; - for (HippyShadowView *subRenderObject in shadowView.subcomponents) { + for (HippyShadowView *subRenderObject in shadowView.hippySubviews) { UIView *subview = [self createViewRecursiveFromRenderObjectWithNOLock:subRenderObject]; [view insertHippySubview:subview atIndex:index]; index++; diff --git a/renderer/native/ios/renderer/component/listview/HippyNextBaseListView.mm b/renderer/native/ios/renderer/component/listview/HippyNextBaseListView.mm index 2a5a19c951c..f299e3d83b7 100644 --- a/renderer/native/ios/renderer/component/listview/HippyNextBaseListView.mm +++ b/renderer/native/ios/renderer/component/listview/HippyNextBaseListView.mm @@ -142,7 +142,7 @@ - (void)setScrollEnabled:(BOOL)value { // here we use super's hippyBridgeDidFinishTransaction imp to trigger reload, // and override reloadData to handle special logic - (void)reloadData { - NSArray *datasource = [self.hippyShadowView.subcomponents copy]; + NSArray *datasource = [self.hippyShadowView.hippySubviews copy]; self->_dataSource = [[HippyNextBaseListViewDataSource alloc] initWithDataSource:datasource itemViewName:[self compoentItemName] containBannerView:NO]; diff --git a/renderer/native/ios/renderer/component/scrollview/HippyScrollView.mm b/renderer/native/ios/renderer/component/scrollview/HippyScrollView.mm index 968b9fa0dad..ecc2017025c 100644 --- a/renderer/native/ios/renderer/component/scrollview/HippyScrollView.mm +++ b/renderer/native/ios/renderer/component/scrollview/HippyScrollView.mm @@ -262,7 +262,7 @@ - (void)insertHippySubview:(UIView *)view atIndex:(NSInteger)atIndex { } } -- (NSArray *)subcomponents { +- (NSArray *)hippySubviews { return _contentView ? [NSMutableArray arrayWithObject:_contentView] : nil; } diff --git a/renderer/native/ios/renderer/component/smartViewPager/NativeRenderSmartViewPagerView.mm b/renderer/native/ios/renderer/component/smartViewPager/NativeRenderSmartViewPagerView.mm index abac1ef5f3e..a10ca363f35 100644 --- a/renderer/native/ios/renderer/component/smartViewPager/NativeRenderSmartViewPagerView.mm +++ b/renderer/native/ios/renderer/component/smartViewPager/NativeRenderSmartViewPagerView.mm @@ -313,8 +313,8 @@ - (NSArray *)refreshItemIndexArrayWithOldArrayLength:(NSInteger)length { } - (void)refreshItemNodes { - [self.dataSource setDataSource:self.hippyShadowView.subcomponents containBannerView:NO]; - _itemIndexArray = [self refreshItemIndexArrayWithOldArrayLength:self.hippyShadowView.subcomponents.count]; + [self.dataSource setDataSource:self.hippyShadowView.hippySubviews containBannerView:NO]; + _itemIndexArray = [self refreshItemIndexArrayWithOldArrayLength:self.hippyShadowView.hippySubviews.count]; [self setPreviousMargin:_previousMargin nextMargin:_nextMargin pageGap:_pageGap]; } diff --git a/renderer/native/ios/renderer/component/text/HippyShadowText.mm b/renderer/native/ios/renderer/component/text/HippyShadowText.mm index eb79f1399b7..b8d3d4b59df 100644 --- a/renderer/native/ios/renderer/component/text/HippyShadowText.mm +++ b/renderer/native/ios/renderer/component/text/HippyShadowText.mm @@ -311,7 +311,7 @@ - (void)amendLayoutBeforeMount:(NSMutableSet *)blocks // so only call amendXxx when subcomponent is not a . if (NativeRenderUpdateLifecycleComputed != _propagationLifecycle) { _propagationLifecycle = NativeRenderUpdateLifecycleComputed; - for (HippyShadowView *shadowView in self.subcomponents) { + for (HippyShadowView *shadowView in self.hippySubviews) { if (![shadowView isKindOfClass:HippyShadowText.class]) { [shadowView amendLayoutBeforeMount:blocks]; } @@ -441,7 +441,7 @@ - (NSAttributedString *)attributedString { info.foregroundColor = self.color ?: [UIColor blackColor]; info.backgroundColor = self.backgroundColor; info.opacity = self.opacity; - info.isNestedText = self.subcomponents.count > 0; + info.isNestedText = self.hippySubviews.count > 0; _isNestedText = info.isNestedText; return [self _attributedStringWithStyleInfo:info]; } @@ -496,7 +496,7 @@ - (NSAttributedString *)_attributedStringWithStyleInfo:(HippyAttributedStringSty CGFloat heightOfTallestSubview = 0.0; NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:self.text ?: @""]; - for (HippyShadowView *child in [self subcomponents]) { + for (HippyShadowView *child in [self hippySubviews]) { if ([child isKindOfClass:[HippyShadowText class]]) { HippyShadowText *childShadowText = (HippyShadowText *)child; HippyAttributedStringStyleInfo *childInfo = [HippyAttributedStringStyleInfo new]; @@ -966,7 +966,7 @@ - (void)setAllowFontScaling:(BOOL)allowFontScaling { return; } _allowFontScaling = allowFontScaling; - for (HippyShadowView *child in [self subcomponents]) { + for (HippyShadowView *child in [self hippySubviews]) { if ([child isKindOfClass:[HippyShadowText class]]) { ((HippyShadowText *)child).allowFontScaling = allowFontScaling; } @@ -983,7 +983,7 @@ - (void)setFontSizeMultiplier:(CGFloat)fontSizeMultiplier { HippyLogError(@"fontSizeMultiplier value must be > zero."); _fontSizeMultiplier = 1.0; } - for (HippyShadowView *child in [self subcomponents]) { + for (HippyShadowView *child in [self hippySubviews]) { if ([child isKindOfClass:[HippyShadowText class]]) { ((HippyShadowText *)child).fontSizeMultiplier = fontSizeMultiplier; } diff --git a/renderer/native/ios/renderer/component/text/HippyText.mm b/renderer/native/ios/renderer/component/text/HippyText.mm index 3dc00febcae..2e9ebd1a129 100644 --- a/renderer/native/ios/renderer/component/text/HippyText.mm +++ b/renderer/native/ios/renderer/component/text/HippyText.mm @@ -27,7 +27,7 @@ #import "HippyLog.h" static void collectNonTextDescendants(HippyText *view, NSMutableArray *nonTextDescendants) { - for (UIView *child in view.subcomponents) { + for (UIView *child in view.hippySubviews) { if ([child isKindOfClass:[HippyText class]]) { collectNonTextDescendants((HippyText *)child, nonTextDescendants); } else { @@ -65,11 +65,11 @@ - (void)hippySetFrame:(CGRect)frame { } - (void)removeHippySubview:(UIView *)subview { - if ([[self subcomponents] containsObject:subview]) { + if ([[self hippySubviews] containsObject:subview]) { [super removeHippySubview:subview]; } else { - NSArray *hippySubviews = [self subcomponents]; + NSArray *hippySubviews = [self hippySubviews]; for (UIView *hippySubview in hippySubviews) { [hippySubview removeHippySubview:subview]; } diff --git a/renderer/native/ios/renderer/component/text/HippyTextManager.mm b/renderer/native/ios/renderer/component/text/HippyTextManager.mm index b8f539b4300..bc2159baf1a 100644 --- a/renderer/native/ios/renderer/component/text/HippyTextManager.mm +++ b/renderer/native/ios/renderer/component/text/HippyTextManager.mm @@ -28,7 +28,7 @@ #import "UIView+Hippy.h" static void collectDirtyNonTextDescendants(HippyShadowText *renderObject, NSMutableArray *nonTextDescendants) { - for (HippyShadowView *child in renderObject.subcomponents) { + for (HippyShadowView *child in renderObject.hippySubviews) { if ([child isKindOfClass:[HippyShadowText class]]) { collectDirtyNonTextDescendants((HippyShadowText *)child, nonTextDescendants); } else if ([child isTextDirty]) { @@ -109,7 +109,7 @@ - (HippyViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(NSDictionary *)blocks return; } _propagationLifecycle = NativeRenderUpdateLifecycleComputed; - for (HippyShadowView *renderObjectView in self.subcomponents) { + for (HippyShadowView *renderObjectView in self.hippySubviews) { [renderObjectView amendLayoutBeforeMount:blocks]; } } @@ -160,15 +160,15 @@ - (void)setTextComputed { - (void)synchronousRecusivelySetCreationTypeToInstant { self.creationType = HippyCreationTypeInstantly; - for (HippyShadowView *subShadowView in self.subcomponents) { + for (HippyShadowView *subShadowView in self.hippySubviews) { [subShadowView synchronousRecusivelySetCreationTypeToInstant]; } } - (UIView *)createView:(HippyViewCreationBlock)creationBlock insertChildren:(HippyViewInsertionBlock)insertionBlock { UIView *container = creationBlock(self); - NSMutableArray *children = [NSMutableArray arrayWithCapacity:[self.subcomponents count]]; - for (HippyShadowView *subviews in self.subcomponents) { + NSMutableArray *children = [NSMutableArray arrayWithCapacity:[self.hippySubviews count]]; + for (HippyShadowView *subviews in self.hippySubviews) { UIView *subview = [subviews createView:creationBlock insertChildren:insertionBlock]; if (subview) { [children addObject:subview]; @@ -217,7 +217,7 @@ - (void)removeFromHippySuperview { [superview removeHippySubview:self]; } -- (NSArray *)subcomponents { +- (NSArray *)hippySubviews { return _objectSubviews; } @@ -415,7 +415,7 @@ - (void)setConfirmedLayoutDirection:(hippy::Direction)confirmedLayoutDirection { - (void)applyConfirmedLayoutDirectionToSubviews:(hippy::Direction)confirmedLayoutDirection { _confirmedLayoutDirection = confirmedLayoutDirection; - for (HippyShadowView *subviews in self.subcomponents) { + for (HippyShadowView *subviews in self.hippySubviews) { [subviews applyConfirmedLayoutDirectionToSubviews:confirmedLayoutDirection]; } } @@ -448,7 +448,7 @@ - (void)checkLayoutDirection:(NSMutableSet *)viewsSet directi - (void)superviewLayoutDirectionChangedTo:(hippy::Direction)direction { if (hippy::Direction::Inherit == self.layoutDirection) { self.confirmedLayoutDirection = ((HippyShadowView *)[self parent]).confirmedLayoutDirection; - for (HippyShadowView *subview in self.subcomponents) { + for (HippyShadowView *subview in self.hippySubviews) { [subview superviewLayoutDirectionChangedTo:self.confirmedLayoutDirection]; } } diff --git a/renderer/native/ios/renderer/component/view/UIView+DirectionalLayout.mm b/renderer/native/ios/renderer/component/view/UIView+DirectionalLayout.mm index 933ced8e60c..e1c5a8b2ea7 100644 --- a/renderer/native/ios/renderer/component/view/UIView+DirectionalLayout.mm +++ b/renderer/native/ios/renderer/component/view/UIView+DirectionalLayout.mm @@ -67,7 +67,7 @@ - (void)checkLayoutDirection:(NSMutableSet *)viewsSet direction:(hippy - (void)superviewLayoutDirectionChangedTo:(hippy::Direction)direction { if (hippy::Direction::Inherit == self.layoutDirection) { self.confirmedLayoutDirection = [self superview].confirmedLayoutDirection; - for (UIView *subview in self.subcomponents) { + for (UIView *subview in self.hippySubviews) { [subview superviewLayoutDirectionChangedTo:self.confirmedLayoutDirection]; } } diff --git a/renderer/native/ios/renderer/component/view/UIView+Hippy.mm b/renderer/native/ios/renderer/component/view/UIView+Hippy.mm index fff8fa4dc93..34b7a2e270b 100644 --- a/renderer/native/ios/renderer/component/view/UIView+Hippy.mm +++ b/renderer/native/ios/renderer/component/view/UIView+Hippy.mm @@ -140,7 +140,7 @@ - (NSNumber *)hippyTagAtPoint:(CGPoint)point { return view.hippyTag; } -- (NSArray *)subcomponents { +- (NSArray<__kindof id> *)hippySubviews { return objc_getAssociatedObject(self, _cmd); } @@ -160,14 +160,14 @@ - (void)setParent:(id)parent { - (void)insertHippySubview:(UIView *)subview atIndex:(NSUInteger)atIndex { // We access the associated object directly here in case someone overrides - // the `subcomponents` getter method and returns an immutable array. + // the `hippySubviews` getter method and returns an immutable array. if (nil == subview) { return; } - NSMutableArray *subviews = objc_getAssociatedObject(self, @selector(subcomponents)); + NSMutableArray *subviews = objc_getAssociatedObject(self, @selector(hippySubviews)); if (!subviews) { subviews = [NSMutableArray new]; - objc_setAssociatedObject(self, @selector(subcomponents), subviews, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + objc_setAssociatedObject(self, @selector(hippySubviews), subviews, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } if (atIndex <= [subviews count]) { @@ -188,8 +188,8 @@ - (void)moveHippySubview:(UIView *)subview toIndex:(NSUInteger)atIndex { - (void)removeHippySubview:(UIView *)subview { // We access the associated object directly here in case someone overrides - // the `subcomponents` getter method and returns an immutable array. - NSMutableArray *subviews = objc_getAssociatedObject(self, @selector(subcomponents)); + // the `hippySubviews` getter method and returns an immutable array. + NSMutableArray *subviews = objc_getAssociatedObject(self, @selector(hippySubviews)); [subviews removeObject:subview]; [subview sendDetachedFromWindowEvent]; [subview removeFromSuperview]; @@ -201,7 +201,7 @@ - (void)removeFromHippySuperview { } - (void)resetHippySubviews { - NSMutableArray *subviews = objc_getAssociatedObject(self, @selector(subcomponents)); + NSMutableArray *subviews = objc_getAssociatedObject(self, @selector(hippySubviews)); if (subviews) { [subviews makeObjectsPerformSelector:@selector(sendDetachedFromWindowEvent)]; [subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; @@ -241,13 +241,13 @@ - (void)setHippySubviewsUpdated:(BOOL)subViewsUpdated { if (!subviews) { // Check if sorting is required - in most cases it won't be BOOL sortingRequired = NO; - for (UIView *subview in self.subcomponents) { + for (UIView *subview in self.hippySubviews) { if (subview.hippyZIndex != 0) { sortingRequired = YES; break; } } - subviews = sortingRequired ? [self.subcomponents sortedArrayUsingComparator:^NSComparisonResult(UIView *a, UIView *b) { + subviews = sortingRequired ? [self.hippySubviews sortedArrayUsingComparator:^NSComparisonResult(UIView *a, UIView *b) { if (a.hippyZIndex > b.hippyZIndex) { return NSOrderedDescending; } else { @@ -255,7 +255,7 @@ - (void)setHippySubviewsUpdated:(BOOL)subViewsUpdated { // that original order is preserved return NSOrderedAscending; } - }] : self.subcomponents; + }] : self.hippySubviews; objc_setAssociatedObject(self, _cmd, subviews, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } return subviews; diff --git a/renderer/native/ios/renderer/component/waterfalllist/HippyShadowWaterfallItem.m b/renderer/native/ios/renderer/component/waterfalllist/HippyShadowWaterfallItem.m index c5a1844cc13..ff409d7e967 100644 --- a/renderer/native/ios/renderer/component/waterfalllist/HippyShadowWaterfallItem.m +++ b/renderer/native/ios/renderer/component/waterfalllist/HippyShadowWaterfallItem.m @@ -54,7 +54,7 @@ - (void)amendLayoutBeforeMount:(NSMutableSet *)blocks _layoutDirty = YES; } _propagationLifecycle = NativeRenderUpdateLifecycleComputed; - for (HippyShadowView *renderObjectView in self.subcomponents) { + for (HippyShadowView *renderObjectView in self.hippySubviews) { [renderObjectView amendLayoutBeforeMount:blocks]; } } diff --git a/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.mm b/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.mm index 78925f3d7b3..36739531ff7 100644 --- a/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.mm +++ b/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.mm @@ -207,7 +207,7 @@ - (void)hippyBridgeDidFinishTransaction { } - (void)reloadData { - NSArray *datasource = [self.hippyShadowView.subcomponents copy]; + NSArray *datasource = [self.hippyShadowView.hippySubviews copy]; _dataSource = [[HippyWaterfallViewDataSource alloc] initWithDataSource:datasource itemViewName:[self compoentItemName] containBannerView:_containBannerView]; From 22c99ec71d03683bc942efb54b43b6f843bb8935 Mon Sep 17 00:00:00 2001 From: wwwcg Date: Tue, 6 Aug 2024 21:33:29 +0800 Subject: [PATCH 06/47] fix(ios): remove invalid if statement at cell reuse --- .../component/listview/HippyNextBaseListView.mm | 4 +--- .../waterfalllist/HippyShadowWaterfallItem.h | 2 -- .../waterfalllist/HippyShadowWaterfallItem.m | 12 +----------- .../component/waterfalllist/HippyWaterfallView.mm | 4 +--- 4 files changed, 3 insertions(+), 19 deletions(-) diff --git a/renderer/native/ios/renderer/component/listview/HippyNextBaseListView.mm b/renderer/native/ios/renderer/component/listview/HippyNextBaseListView.mm index f299e3d83b7..40daabd1b53 100644 --- a/renderer/native/ios/renderer/component/listview/HippyNextBaseListView.mm +++ b/renderer/native/ios/renderer/component/listview/HippyNextBaseListView.mm @@ -269,9 +269,7 @@ - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cell UIView *cellView = nil; UIView *cachedVisibleCellView = [_cachedWeakCellViews objectForKey:shadowView.hippyTag]; - if (cachedVisibleCellView && - [shadowView isKindOfClass:HippyShadowWaterfallItem.class] && - !((HippyShadowWaterfallItem *)shadowView).layoutDirty) { + if (cachedVisibleCellView) { cellView = cachedVisibleCellView; HippyLogTrace(@"🟢 use cached visible cellView at %@ for %@", indexPath, shadowView.hippyTag); } else { diff --git a/renderer/native/ios/renderer/component/waterfalllist/HippyShadowWaterfallItem.h b/renderer/native/ios/renderer/component/waterfalllist/HippyShadowWaterfallItem.h index fee091dcf58..8e75ba48228 100644 --- a/renderer/native/ios/renderer/component/waterfalllist/HippyShadowWaterfallItem.h +++ b/renderer/native/ios/renderer/component/waterfalllist/HippyShadowWaterfallItem.h @@ -38,8 +38,6 @@ NS_ASSUME_NONNULL_BEGIN /// Waterfall item's shadowView @interface HippyShadowWaterfallItem : HippyShadowView -@property (nonatomic, assign, getter=isLayoutDirty) BOOL layoutDirty; - /// frame change observer, usually is shadowListView @property (nonatomic, weak) id observer; diff --git a/renderer/native/ios/renderer/component/waterfalllist/HippyShadowWaterfallItem.m b/renderer/native/ios/renderer/component/waterfalllist/HippyShadowWaterfallItem.m index ff409d7e967..167412d8707 100644 --- a/renderer/native/ios/renderer/component/waterfalllist/HippyShadowWaterfallItem.m +++ b/renderer/native/ios/renderer/component/waterfalllist/HippyShadowWaterfallItem.m @@ -46,17 +46,7 @@ - (void)amendLayoutBeforeMount:(NSMutableSet *)blocks // If item has not yet been created, then no need to collect blocks. return; } - _layoutDirty = NO; - if (NativeRenderUpdateLifecycleComputed == _propagationLifecycle) { - return; - } - if (NativeRenderUpdateLifecycleLayoutDirtied == _propagationLifecycle) { - _layoutDirty = YES; - } - _propagationLifecycle = NativeRenderUpdateLifecycleComputed; - for (HippyShadowView *renderObjectView in self.hippySubviews) { - [renderObjectView amendLayoutBeforeMount:blocks]; - } + [super amendLayoutBeforeMount:blocks]; } @end diff --git a/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.mm b/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.mm index 36739531ff7..8561640ad85 100644 --- a/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.mm +++ b/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.mm @@ -263,9 +263,7 @@ - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cell UIView *cellView = nil; UIView *cachedCellView = [_cachedWeakCellViews objectForKey:shadowView.hippyTag]; - if (cachedCellView && - [shadowView isKindOfClass:HippyShadowWaterfallItem.class] && - !((HippyShadowWaterfallItem *)shadowView).layoutDirty) { + if (cachedCellView) { cellView = cachedCellView; } else { cellView = [self.uiManager createViewForShadowListItem:shadowView]; From a8f4bdf7c6c37655872de4a868c8efcba57e4d81 Mon Sep 17 00:00:00 2001 From: maxli Date: Mon, 12 Aug 2024 10:56:38 +0800 Subject: [PATCH 07/47] fix(android): delete virtual child node when parent deleted --- .../mtt/hippy/uimanager/RenderManager.java | 16 +++++++++++++++- .../java/com/tencent/renderer/NativeRender.java | 2 ++ .../com/tencent/renderer/NativeRenderer.java | 5 +++++ .../tencent/renderer/node/RootRenderNode.java | 5 +++-- 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/RenderManager.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/RenderManager.java index 85676097fd3..4e6f9ae199f 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/RenderManager.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/RenderManager.java @@ -16,10 +16,10 @@ package com.tencent.mtt.hippy.uimanager; +import static com.tencent.mtt.hippy.dom.node.NodeProps.TEXT_CLASS_NAME; import static com.tencent.renderer.NativeRenderer.NODE_ID; import static com.tencent.renderer.NativeRenderer.NODE_INDEX; import static com.tencent.renderer.node.RenderNode.FLAG_ALREADY_DELETED; -import static com.tencent.renderer.node.RenderNode.FLAG_LAZY_LOAD; import static com.tencent.renderer.node.RenderNode.FLAG_UPDATE_TOTAL_PROPS; import android.content.Context; @@ -29,6 +29,7 @@ import androidx.annotation.NonNull; import com.openhippy.pool.BasePool.PoolType; +import com.tencent.renderer.NativeRender; import com.tencent.renderer.NativeRenderContext; import com.tencent.renderer.NativeRendererManager; import com.tencent.renderer.Renderer; @@ -39,6 +40,7 @@ import com.tencent.renderer.node.TextRenderNode; import com.tencent.renderer.node.RenderNode; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -66,8 +68,11 @@ public class RenderManager { private final ControllerManager mControllerManager; @NonNull private final Map> mUIUpdateNodes = new HashMap<>(); + @Nullable + private final WeakReference mRendererWeakRef; public RenderManager(Renderer renderer) { + mRendererWeakRef = new WeakReference<>(renderer); mControllerManager = new ControllerManager(renderer); } @@ -381,6 +386,12 @@ private void deleteSelfFromParent(int rootId, @Nullable RenderNode node) { node.getParent().removeChild(node); } removeRenderNode(rootId, node.getId()); + if (node.getClassName().equals(TEXT_CLASS_NAME)) { + Renderer renderer = mRendererWeakRef.get(); + if (renderer instanceof NativeRender) { + ((NativeRender) renderer).deleteVirtualChildNode(rootId, node.getId()); + } + } node.setNodeFlag(FLAG_ALREADY_DELETED); node.onDeleted(); } @@ -389,6 +400,9 @@ private void removeRenderNode(int rootId, int nodeId) { RootRenderNode rootNode = NativeRendererManager.getRootNode(rootId); if (rootId == nodeId) { NativeRendererManager.removeRootNode(rootId); + if (rootNode != null) { + rootNode.clear(); + } } if (rootNode != null) { rootNode.removeRenderNode(nodeId); diff --git a/renderer/native/android/src/main/java/com/tencent/renderer/NativeRender.java b/renderer/native/android/src/main/java/com/tencent/renderer/NativeRender.java index 0a3e18eeb4c..64dfbffe267 100644 --- a/renderer/native/android/src/main/java/com/tencent/renderer/NativeRender.java +++ b/renderer/native/android/src/main/java/com/tencent/renderer/NativeRender.java @@ -67,6 +67,8 @@ public interface NativeRender extends RenderExceptionHandler, RenderLogHandler { @Nullable BaseEngineContext getEngineContext(); + void deleteVirtualChildNode(int rootId, int nodeId); + int getEngineId(); /** diff --git a/renderer/native/android/src/main/java/com/tencent/renderer/NativeRenderer.java b/renderer/native/android/src/main/java/com/tencent/renderer/NativeRenderer.java index 70d5badc961..d328690f033 100644 --- a/renderer/native/android/src/main/java/com/tencent/renderer/NativeRenderer.java +++ b/renderer/native/android/src/main/java/com/tencent/renderer/NativeRenderer.java @@ -635,6 +635,11 @@ public void updateNode(final int rootId, @NonNull List nodeList) } } + @Override + public void deleteVirtualChildNode(int rootId, int nodeId) { + mVirtualNodeManager.deleteNode(rootId, nodeId); + } + @Override public void deleteNode(final int rootId, @NonNull int[] ids) throws NativeRenderException { final List taskList = new ArrayList<>(ids.length); diff --git a/renderer/native/android/src/main/java/com/tencent/renderer/node/RootRenderNode.java b/renderer/native/android/src/main/java/com/tencent/renderer/node/RootRenderNode.java index 6952fce7e72..149187c0b19 100644 --- a/renderer/native/android/src/main/java/com/tencent/renderer/node/RootRenderNode.java +++ b/renderer/native/android/src/main/java/com/tencent/renderer/node/RootRenderNode.java @@ -23,12 +23,13 @@ import com.tencent.renderer.utils.ChoreographerUtils; import java.util.Map; import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; public class RootRenderNode extends RenderNode { private final int mRendererId; private final SparseArray mNodes = new SparseArray<>(80); - private final SparseArray mVirtualNodes = new SparseArray<>(40); + private final ConcurrentHashMap mVirtualNodes = new ConcurrentHashMap<>(40); public RootRenderNode(int rootId, int id, int rendererId, @NonNull String className, @NonNull ControllerManager controllerManager) { @@ -68,7 +69,7 @@ public void addVirtualNode(@NonNull VirtualNode node) { } public void removeVirtualNode(int id) { - mVirtualNodes.delete(id); + mVirtualNodes.remove(id); } @Override From 482e258f0e8ad18870694b5e362db9c4d78792ac Mon Sep 17 00:00:00 2001 From: maxli Date: Mon, 12 Aug 2024 14:33:15 +0800 Subject: [PATCH 08/47] fix(android): add ControllerRegistry destroy --- .../com/tencent/mtt/hippy/uimanager/ControllerManager.java | 4 ++-- .../com/tencent/mtt/hippy/uimanager/ControllerRegistry.java | 6 +++++- .../tencent/mtt/hippy/uimanager/ControllerUpdateManger.java | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerManager.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerManager.java index b0c676e4da5..7f42e845def 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerManager.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerManager.java @@ -178,8 +178,8 @@ public HippyCustomPropsController getCustomPropsController() { } public void destroy() { - mControllerRegistry.clear(); - mControllerUpdateManger.clear(); + mControllerRegistry.destroy(); + mControllerUpdateManger.destroy(); for (Pool pool : mPreCreateViewPools.values()) { pool.clear(); } diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerRegistry.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerRegistry.java index 0c49a43df16..09953cd0573 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerRegistry.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerRegistry.java @@ -49,7 +49,11 @@ public ControllerRegistry(@NonNull Renderer renderer) { mRendererWeakRef = new WeakReference<>(renderer); } - public void clear() {} + void destroy() { + mViews.clear(); + mRootViews.clear(); + mControllers.clear(); + } public void addControllerHolder(String name, ControllerHolder controllerHolder) { mControllers.put(name, controllerHolder); diff --git a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerUpdateManger.java b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerUpdateManger.java index 8e228392c0f..8631ba0c494 100644 --- a/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerUpdateManger.java +++ b/renderer/native/android/src/main/java/com/tencent/mtt/hippy/uimanager/ControllerUpdateManger.java @@ -83,7 +83,7 @@ public ControllerUpdateManger(@NonNull Renderer renderer) { mRendererWeakRef = new WeakReference<>(renderer); } - public void clear() { + void destroy() { } From 9eec723a6fdd32bbb17384658332406ceba0bff9 Mon Sep 17 00:00:00 2001 From: wwwcg Date: Tue, 13 Aug 2024 21:29:24 +0800 Subject: [PATCH 09/47] fix(ios): resolve floating point size comparison issues (#3989) --- .../native/ios/renderer/HippyUIManager.mm | 2 +- .../component/scrollview/HippyScrollView.mm | 3 +- .../component/textinput/HippyTextView.mm | 4 +- .../component/view/HippyShadowView.mm | 3 +- .../ios/renderer/component/view/HippyView.m | 5 +- .../component/viewPager/HippyViewPager.mm | 8 +- .../waterfalllist/HippyShadowWaterfallItem.m | 3 +- renderer/native/ios/utils/HippyRenderUtils.h | 11 +- renderer/native/ios/utils/HippyRenderUtils.m | 51 ++++- tests/ios/HippyRenderUtilsTest.m | 175 ++++++++++++++++++ 10 files changed, 244 insertions(+), 21 deletions(-) create mode 100644 tests/ios/HippyRenderUtilsTest.m diff --git a/renderer/native/ios/renderer/HippyUIManager.mm b/renderer/native/ios/renderer/HippyUIManager.mm index c063ad487ad..2891ddea9ab 100644 --- a/renderer/native/ios/renderer/HippyUIManager.mm +++ b/renderer/native/ios/renderer/HippyUIManager.mm @@ -426,7 +426,7 @@ - (void)setFrame:(CGRect)frame forView:(UIView *)view{ return; } - if (!CGRectEqualToRect(frame, renderObject.frame)) { + if (!HippyCGRectRoundInPixelNearlyEqual(frame, renderObject.frame)) { //renderObject.frame = frame; [renderObject setLayoutFrame:frame]; std::weak_ptr rootNode = [strongSelf->_shadowViewRegistry rootNodeForTag:rootTag]; diff --git a/renderer/native/ios/renderer/component/scrollview/HippyScrollView.mm b/renderer/native/ios/renderer/component/scrollview/HippyScrollView.mm index ecc2017025c..4c526add9c5 100644 --- a/renderer/native/ios/renderer/component/scrollview/HippyScrollView.mm +++ b/renderer/native/ios/renderer/component/scrollview/HippyScrollView.mm @@ -25,6 +25,7 @@ #import "UIView+Hippy.h" #import "UIView+MountEvent.h" #import "UIView+DirectionalLayout.h" +#import "HippyRenderUtils.h" @implementation HippyCustomScrollView @@ -661,7 +662,7 @@ - (CGSize)contentSize { - (void)hippyBridgeDidFinishTransaction { CGSize contentSize = self.contentSize; - if (!CGSizeEqualToSize(_scrollView.contentSize, contentSize)) { + if (!HippyCGSizeRoundInPixelNearlyEqual(_scrollView.contentSize, contentSize)) { // When contentSize is set manually, ScrollView internals will reset // contentOffset to {0, 0}. Since we potentially set contentSize whenever // anything in the ScrollView updates, we workaround this issue by manually diff --git a/renderer/native/ios/renderer/component/textinput/HippyTextView.mm b/renderer/native/ios/renderer/component/textinput/HippyTextView.mm index ac1ac05cb92..95c6fbdff9f 100644 --- a/renderer/native/ios/renderer/component/textinput/HippyTextView.mm +++ b/renderer/native/ios/renderer/component/textinput/HippyTextView.mm @@ -27,6 +27,7 @@ #import "HippyUtils.h" #import "HippyTextSelection.h" #import "UIView+Hippy.h" +#import "HippyRenderUtils.h" @implementation HippyUITextView @@ -290,7 +291,8 @@ - (void)updateContentSize { CGSize contentSize = (CGSize) { CGRectGetMaxX(_scrollView.frame), INFINITY }; contentSize.height = [_textView sizeThatFits:contentSize].height; - if (_viewDidCompleteInitialLayout && _onContentSizeChange && !CGSizeEqualToSize(_previousContentSize, contentSize)) { + if (_viewDidCompleteInitialLayout && _onContentSizeChange + && !HippyCGSizeRoundInPixelNearlyEqual(_previousContentSize, contentSize)) { _previousContentSize = contentSize; _onContentSizeChange(@{ @"contentSize": @ { diff --git a/renderer/native/ios/renderer/component/view/HippyShadowView.mm b/renderer/native/ios/renderer/component/view/HippyShadowView.mm index 759988a8e04..17875abdf35 100644 --- a/renderer/native/ios/renderer/component/view/HippyShadowView.mm +++ b/renderer/native/ios/renderer/component/view/HippyShadowView.mm @@ -28,6 +28,7 @@ #import "UIView+Hippy.h" #import "HippyShadowView+Internal.h" #import "HippyAssert.h" +#import "HippyRenderUtils.h" static NSString *const HippyBackgroundColorPropKey = @"backgroundColor"; @@ -286,7 +287,7 @@ - (void)setLayoutFrame:(CGRect)frame { - (void)setLayoutFrame:(CGRect)frame dirtyPropagation:(BOOL)dirtyPropagation { CGRect currentFrame = self.frame; - if (CGRectEqualToRect(currentFrame, frame)) { + if (HippyCGRectRoundInPixelNearlyEqual(currentFrame, frame)) { return; } [self setFrame:frame]; diff --git a/renderer/native/ios/renderer/component/view/HippyView.m b/renderer/native/ios/renderer/component/view/HippyView.m index d577002c0ba..77e0b33d068 100644 --- a/renderer/native/ios/renderer/component/view/HippyView.m +++ b/renderer/native/ios/renderer/component/view/HippyView.m @@ -27,6 +27,7 @@ #import "HippyView.h" #import "UIView+DomEvent.h" #import "UIView+Hippy.h" +#import "HippyRenderUtils.h" static CGSize makeSizeConstrainWithType(CGSize originSize, CGSize constrainSize, NSString *resizeMode) { // width / height @@ -169,7 +170,7 @@ - (void)hippySetFrame:(CGRect)frame { // TODO: detect up-front if re-rendering is necessary CGSize oldSize = self.bounds.size; [super hippySetFrame:frame]; - if (!CGSizeEqualToSize(self.bounds.size, oldSize)) { + if (!HippyCGSizeNearlyEqual(self.bounds.size, oldSize)) { [self.layer setNeedsDisplay]; } } @@ -235,7 +236,7 @@ - (CALayerContentsFilter)magnificationFilter { } - (void)displayLayer:(CALayer *)layer { - if (CGSizeEqualToSize(layer.bounds.size, CGSizeZero)) { + if (HippyCGSizeNearlyEqual(layer.bounds.size, CGSizeZero)) { return; } diff --git a/renderer/native/ios/renderer/component/viewPager/HippyViewPager.mm b/renderer/native/ios/renderer/component/viewPager/HippyViewPager.mm index e190e2b2e95..68ad2dee578 100644 --- a/renderer/native/ios/renderer/component/viewPager/HippyViewPager.mm +++ b/renderer/native/ios/renderer/component/viewPager/HippyViewPager.mm @@ -26,8 +26,8 @@ #import "UIView+DirectionalLayout.h" #import "UIView+MountEvent.h" #import "HippyLog.h" +#import "HippyRenderUtils.h" -#include "float.h" @interface HippyViewPager () @property (nonatomic, strong) NSMutableArray *viewPagerItems; @@ -435,8 +435,8 @@ - (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated { } - (void)hippyBridgeDidFinishTransaction { - BOOL isFrameEqual = CGRectEqualToRect(self.frame, self.previousFrame); - BOOL isContentSizeEqual = CGSizeEqualToSize(self.contentSize, self.previousSize); + BOOL isFrameEqual = HippyCGRectRoundInPixelNearlyEqual(self.frame, self.previousFrame); + BOOL isContentSizeEqual = HippyCGSizeRoundInPixelNearlyEqual(self.contentSize, self.previousSize); if (!isContentSizeEqual || !isFrameEqual) { self.previousFrame = self.frame; self.previousSize = self.contentSize; @@ -474,7 +474,7 @@ - (void)layoutSubviews { CGSize updatedSize = CGSizeMake(lastViewPagerItem.frame.origin.x + lastViewPagerItem.frame.size.width, lastViewPagerItem.frame.origin.y + lastViewPagerItem.frame.size.height); - if (!CGSizeEqualToSize(self.contentSize, updatedSize)) { + if (!HippyCGSizeRoundInPixelNearlyEqual(self.contentSize, updatedSize)) { self.contentSize = updatedSize; } diff --git a/renderer/native/ios/renderer/component/waterfalllist/HippyShadowWaterfallItem.m b/renderer/native/ios/renderer/component/waterfalllist/HippyShadowWaterfallItem.m index 167412d8707..b5271f0000f 100644 --- a/renderer/native/ios/renderer/component/waterfalllist/HippyShadowWaterfallItem.m +++ b/renderer/native/ios/renderer/component/waterfalllist/HippyShadowWaterfallItem.m @@ -21,6 +21,7 @@ */ #import "HippyShadowWaterfallItem.h" +#import "HippyRenderUtils.h" @implementation HippyShadowWaterfallItem @@ -35,7 +36,7 @@ - (instancetype)init { - (void)setFrame:(CGRect)frame { CGRect originFrame = self.frame; [super setFrame:frame]; - if (!CGSizeEqualToSize(originFrame.size, frame.size) && + if (!HippyCGSizeRoundInPixelNearlyEqual(originFrame.size, frame.size) && [self.observer respondsToSelector:@selector(itemFrameChanged:)]) { [self.observer itemFrameChanged:self]; } diff --git a/renderer/native/ios/utils/HippyRenderUtils.h b/renderer/native/ios/utils/HippyRenderUtils.h index 99a544eb3b8..651802ba505 100644 --- a/renderer/native/ios/utils/HippyRenderUtils.h +++ b/renderer/native/ios/utils/HippyRenderUtils.h @@ -34,11 +34,18 @@ HIPPY_EXTERN CGFloat HippyRoundPixelValue(CGFloat value); HIPPY_EXTERN CGFloat HippyCeilPixelValue(CGFloat value); HIPPY_EXTERN CGFloat HippyFloorPixelValue(CGFloat value); -// Convert a size in points to pixels, rounded up to the nearest integral size -HIPPY_EXTERN CGSize HippySizeInPixels(CGSize pointSize, CGFloat scale); +/// Convert a size in points to pixels, rounded up to the nearest integral size +FOUNDATION_EXTERN CGSize HippySizeCeilInPixels(CGSize pointSize, CGFloat scale); +/// Convert a size in points to pixels, rounded to the nearest integral size +FOUNDATION_EXTERN CGSize HippySizeRoundInPixels(CGSize pointSize, CGFloat scale); HIPPY_EXTERN BOOL HippyCGRectNearlyEqual(CGRect frame1, CGRect frame2); HIPPY_EXTERN BOOL HippyCGPointNearlyEqual(CGPoint point1, CGPoint point2); HIPPY_EXTERN BOOL HippyCGSizeNearlyEqual(CGSize size1, CGSize size2); +/// First convert size in points to pixels by HippySizeRoundInPixels, then compare. +HIPPY_EXTERN BOOL HippyCGSizeRoundInPixelNearlyEqual(CGSize size1, CGSize size2); +HIPPY_EXTERN BOOL HippyCGRectRoundInPixelNearlyEqual(CGRect frame1, CGRect frame2); +HIPPY_EXTERN BOOL HippyCGPointRoundInPixelNearlyEqual(CGPoint point1, CGPoint point2); + NS_ASSUME_NONNULL_END diff --git a/renderer/native/ios/utils/HippyRenderUtils.m b/renderer/native/ios/utils/HippyRenderUtils.m index 29252b937ec..475244ac255 100644 --- a/renderer/native/ios/utils/HippyRenderUtils.m +++ b/renderer/native/ios/utils/HippyRenderUtils.m @@ -23,13 +23,15 @@ #import "HippyUtils.h" #import "HippyRenderUtils.h" +// Use global variable to facilitate unit test +CGFloat gHippyScreenScaleValue = CGFLOAT_MAX; + CGFloat HippyScreenScale(void) { - static CGFloat scale = CGFLOAT_MAX; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - scale = [UIScreen mainScreen].scale; + gHippyScreenScaleValue = [UIScreen mainScreen].scale; }); - return scale; + return gHippyScreenScaleValue; } CGSize HippyScreenSize(void) { @@ -56,24 +58,57 @@ CGFloat HippyFloorPixelValue(CGFloat value) { return floor(value * scale) / scale; } -CGSize HippySizeInPixels(CGSize pointSize, CGFloat scale) { +CGSize HippySizeCeilInPixels(CGSize pointSize, CGFloat scale) { return (CGSize) { ceil(pointSize.width * scale), ceil(pointSize.height * scale), }; } +CGSize HippySizeRoundInPixels(CGSize pointSize, CGFloat scale) { + return (CGSize) { + round(pointSize.width * scale), + round(pointSize.height * scale), + }; +} + BOOL HippyCGRectNearlyEqual(CGRect frame1, CGRect frame2) { return HippyCGPointNearlyEqual(frame1.origin, frame2.origin) && HippyCGSizeNearlyEqual(frame1.size, frame2.size); } BOOL HippyCGPointNearlyEqual(CGPoint point1, CGPoint point2) { - return fabs(point1.x - point2.x) < CGFLOAT_EPSILON && - fabs(point1.y - point2.y) < CGFLOAT_EPSILON; + return fabs(point1.x - point2.x) < 3 * CGFLOAT_EPSILON && + fabs(point1.y - point2.y) < 3 * CGFLOAT_EPSILON; } BOOL HippyCGSizeNearlyEqual(CGSize size1, CGSize size2) { - return fabs(size1.width - size2.width) < CGFLOAT_EPSILON && - fabs(size1.height - size2.height) < CGFLOAT_EPSILON; + return fabs(size1.width - size2.width) < 3 * CGFLOAT_EPSILON && + fabs(size1.height - size2.height) < 3 * CGFLOAT_EPSILON; +} + +BOOL HippyCGSizeRoundInPixelNearlyEqual(CGSize size1, CGSize size2) { + CGFloat scale = HippyScreenScale(); + CGSize sizeA = HippySizeRoundInPixels(size1, scale); + CGSize sizeB = HippySizeRoundInPixels(size2, scale); + return HippyCGSizeNearlyEqual(sizeA,sizeB); +} + +BOOL HippyCGPointRoundInPixelNearlyEqual(CGPoint point1, CGPoint point2) { + CGFloat scale = HippyScreenScale(); + CGPoint pointA = (CGPoint) { + round(point1.x * scale), + round(point1.y * scale), + }; + CGPoint pointB = (CGPoint) { + round(point2.x * scale), + round(point2.y * scale), + }; + return fabs(pointA.x - pointB.x) < CGFLOAT_EPSILON && + fabs(pointA.y - pointB.y) < CGFLOAT_EPSILON; +} + +BOOL HippyCGRectRoundInPixelNearlyEqual(CGRect frame1, CGRect frame2) { + return HippyCGPointRoundInPixelNearlyEqual(frame1.origin, frame2.origin) && + HippyCGSizeRoundInPixelNearlyEqual(frame1.size, frame2.size); } diff --git a/tests/ios/HippyRenderUtilsTest.m b/tests/ios/HippyRenderUtilsTest.m new file mode 100644 index 00000000000..38d587a83dd --- /dev/null +++ b/tests/ios/HippyRenderUtilsTest.m @@ -0,0 +1,175 @@ +/*! + * 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 + + +@interface HippyRenderUtilsTest : XCTestCase + +@end + +@implementation HippyRenderUtilsTest + +// defined in HippyRenderUtils +extern CGFloat gHippyScreenScaleValue; + +- (void)setUp { + // assume that the screen scale is 2.0. + gHippyScreenScaleValue = 3.0; +} + +- (void)tearDown { + // nop +} + +- (void)testHippyCGSizeCompare { + CGSize size1 = CGSizeMake(10.5, 20.5); + CGSize size2 = CGSizeMake(10.5, 20.5); + XCTAssertTrue(HippyCGSizeNearlyEqual(size1, size2)); + BOOL result = HippyCGSizeRoundInPixelNearlyEqual(size1, size2); + XCTAssertTrue(result, @"Sizes should be nearly equal"); + + // assume that the screen scale is 2.0. + gHippyScreenScaleValue = 2.0; + CGSize size3 = CGSizeMake(10.0, 20.5); + CGSize size4 = CGSizeMake(10.0, 21.0); + XCTAssertFalse(HippyCGSizeNearlyEqual(size3, size4)); + result = HippyCGSizeRoundInPixelNearlyEqual(size3, size4); + XCTAssertFalse(result, @"Sizes should not be nearly equal"); + + // assume that the screen scale is 3.0. + gHippyScreenScaleValue = 3.0; + size3 = CGSizeMake(10.333, 20.5); + size4 = CGSizeMake(10.666, 20.5); + XCTAssertFalse(HippyCGSizeNearlyEqual(size3, size4)); + result = HippyCGSizeRoundInPixelNearlyEqual(size3, size4); + XCTAssertFalse(result, @"Sizes should not be nearly equal"); + + CGSize size5 = CGSizeMake(1.3333356, 1.3333356); + CGSize size6 = CGSizeMake(1.3333289, 1.3333289); + XCTAssertFalse(CGSizeEqualToSize(size5, size6)); + XCTAssertFalse(HippyCGSizeNearlyEqual(size5, size6)); + result = HippyCGSizeRoundInPixelNearlyEqual(size5, size6); + XCTAssertTrue(result, @"Sizes should be nearly equal in edge case"); +} + +- (void)testHippyCGPointCompare { + CGPoint point1 = CGPointMake(10.5, 20.5); + CGPoint point2 = CGPointMake(10.5, 20.5); + XCTAssertTrue(HippyCGPointNearlyEqual(point1, point2)); + BOOL result = HippyCGPointRoundInPixelNearlyEqual(point1, point2); + XCTAssertTrue(result, @"Points should be nearly equal"); + + CGPoint point3 = CGPointMake(10.3, 20.5); + CGPoint point4 = CGPointMake(10.6, 20.5); + XCTAssertFalse(HippyCGPointNearlyEqual(point3, point4)); + result = HippyCGPointRoundInPixelNearlyEqual(point3, point4); + XCTAssertFalse(result, @"Points should not be nearly equal"); + + CGPoint point5 = CGPointMake(1.3333356, 1.3333356); + CGPoint point6 = CGPointMake(1.3333289, 1.3333289); + XCTAssertFalse(CGPointEqualToPoint(point5, point6)); + XCTAssertFalse(HippyCGPointNearlyEqual(point5, point6)); + result = HippyCGPointRoundInPixelNearlyEqual(point5, point6); + XCTAssertTrue(result, @"Points should be nearly equal in edge case"); +} + +- (void)testHippyCGRectCompare { + CGRect rect1 = CGRectMake(10.5, 20.5, 30.5, 40.5); + CGRect rect2 = CGRectMake(10.5, 20.5, 30.5, 40.5); + XCTAssertTrue(HippyCGRectNearlyEqual(rect1, rect2)); + BOOL result = HippyCGRectRoundInPixelNearlyEqual(rect1, rect2); + XCTAssertTrue(result, @"Rects should be nearly equal"); + + CGRect rect3 = CGRectMake(10.3, 20.5, 30.5, 40.5); + CGRect rect4 = CGRectMake(10.6, 20.5, 30.5, 40.5); + XCTAssertFalse(HippyCGRectNearlyEqual(rect3, rect4)); + result = HippyCGRectRoundInPixelNearlyEqual(rect3, rect4); + XCTAssertFalse(result, @"Rects should not be nearly equal"); + + CGRect rect5 = CGRectMake(1.3333356, 1.3333356, 1.3333356, 1.3333356); + CGRect rect6 = CGRectMake(1.3333289, 1.3333289, 1.3333289, 1.3333289); + XCTAssertFalse(CGRectEqualToRect(rect5, rect6)); + XCTAssertFalse(HippyCGRectNearlyEqual(rect5, rect6)); + result = HippyCGRectRoundInPixelNearlyEqual(rect5, rect6); + XCTAssertTrue(result, @"Rects should be nearly equal in edge case"); +} + +- (void)testHippyRoundPixelValue { + CGFloat value1 = 1.3333356; + CGFloat expected1 = round(value1 * HippyScreenScale()) / HippyScreenScale(); + CGFloat result1 = HippyRoundPixelValue(value1); + XCTAssertEqual(result1, expected1, @"Rounded pixel value should be equal"); + + CGFloat value2 = 1.3333289; + CGFloat expected2 = round(value2 * HippyScreenScale()) / HippyScreenScale(); + CGFloat result2 = HippyRoundPixelValue(value2); + XCTAssertEqual(result2, expected2, @"Rounded pixel value should be equal"); +} + +- (void)testHippyCeilPixelValue { + CGFloat value1 = 1.3333356; + CGFloat expected1 = ceil(value1 * HippyScreenScale()) / HippyScreenScale(); + CGFloat result1 = HippyCeilPixelValue(value1); + XCTAssertEqual(result1, expected1, @"Ceil pixel value should be equal"); + + CGFloat value2 = 1.3333289; + CGFloat expected2 = ceil(value2 * HippyScreenScale()) / HippyScreenScale(); + CGFloat result2 = HippyCeilPixelValue(value2); + XCTAssertEqual(result2, expected2, @"Ceil pixel value should be equal"); +} + +- (void)testHippyFloorPixelValue { + CGFloat value1 = 1.3333356; + CGFloat expected1 = floor(value1 * HippyScreenScale()) / HippyScreenScale(); + CGFloat result1 = HippyFloorPixelValue(value1); + XCTAssertEqual(result1, expected1, @"Floor pixel value should be equal"); + + CGFloat value2 = 1.3333289; + CGFloat expected2 = floor(value2 * HippyScreenScale()) / HippyScreenScale(); + CGFloat result2 = HippyFloorPixelValue(value2); + XCTAssertEqual(result2, expected2, @"Floor pixel value should be equal"); +} + +- (void)testHippySizeCeilInPixels { + CGSize size1 = CGSizeMake(1.3333356, 1.3333356); + CGFloat scale = HippyScreenScale(); + CGSize expected1 = (CGSize){ + ceil(size1.width * scale), + ceil(size1.height * scale), + }; + CGSize result1 = HippySizeCeilInPixels(size1, scale); + XCTAssertTrue(CGSizeEqualToSize(result1, expected1), @"Ceil size in pixels should be equal"); + + CGSize size2 = CGSizeMake(1.3333289, 1.3333289); + CGSize expected2 = (CGSize){ + ceil(size2.width * scale), + ceil(size2.height * scale), + }; + CGSize result2 = HippySizeCeilInPixels(size2, scale); + XCTAssertTrue(CGSizeEqualToSize(result2, expected2), @"Ceil size in pixels should be equal"); +} + + +@end From 9ba8426b2254d92a552f67a58b5a45fdeed1ee01 Mon Sep 17 00:00:00 2001 From: maxli Date: Wed, 7 Aug 2024 17:41:36 +0800 Subject: [PATCH 10/47] fix(android): add buildTruncateAtEndStaticLayout impl --- .../renderer/node/TextVirtualNode.java | 46 ++++++++++++++----- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/renderer/native/android/src/main/java/com/tencent/renderer/node/TextVirtualNode.java b/renderer/native/android/src/main/java/com/tencent/renderer/node/TextVirtualNode.java index 238d78f6955..fb4d89e38d6 100644 --- a/renderer/native/android/src/main/java/com/tencent/renderer/node/TextVirtualNode.java +++ b/renderer/native/android/src/main/java/com/tencent/renderer/node/TextVirtualNode.java @@ -31,6 +31,7 @@ import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; +import android.text.TextUtils.TruncateAt; import android.text.style.AbsoluteSizeSpan; import android.text.style.BackgroundColorSpan; import android.text.style.ImageSpan; @@ -557,16 +558,20 @@ protected Layout createLayout(final float width, final FlexMeasureMode widthMode || desiredWidth > width)) { desiredWidth = width; } - layout = buildStaticLayout(mSpanned, textPaint, (int) Math.ceil(desiredWidth)); - if (mNumberOfLines > 0 && layout.getLineCount() > mNumberOfLines) { - int lastLineStart = layout.getLineStart(mNumberOfLines - 1); - int lastLineEnd = layout.getLineEnd(mNumberOfLines - 1); - if (lastLineStart < lastLineEnd) { - int measureWidth = (int) Math.ceil(unconstrainedWidth ? desiredWidth : width); - try { - layout = truncateLayoutWithNumberOfLine(layout, measureWidth, mNumberOfLines); - } catch (Exception e) { - e.printStackTrace(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && MODE_TAIL.equals(mEllipsizeMode)) { + layout = buildTruncateAtEndStaticLayout(mSpanned, textPaint, (int) Math.ceil(desiredWidth), mNumberOfLines); + } else { + layout = buildStaticLayout(mSpanned, textPaint, (int) Math.ceil(desiredWidth)); + if (mNumberOfLines > 0 && layout.getLineCount() > mNumberOfLines) { + int lastLineStart = layout.getLineStart(mNumberOfLines - 1); + int lastLineEnd = layout.getLineEnd(mNumberOfLines - 1); + if (lastLineStart < lastLineEnd) { + int measureWidth = (int) Math.ceil(unconstrainedWidth ? desiredWidth : width); + try { + layout = truncateLayoutWithNumberOfLine(layout, measureWidth, mNumberOfLines); + } catch (Exception e) { + e.printStackTrace(); + } } } } @@ -618,6 +623,26 @@ private TextPaint getTextPaint() { return mTextPaintInstance; } + @RequiresApi(api = Build.VERSION_CODES.M) + private StaticLayout buildTruncateAtEndStaticLayout(CharSequence source, TextPaint paint, int width, int numberOfLines) { + Layout.Alignment alignment = mAlignment; + if (I18nUtil.isRTL()) { + BidiFormatter bidiFormatter = BidiFormatter.getInstance(); + if (bidiFormatter.isRtl(source.toString()) + && mAlignment == Layout.Alignment.ALIGN_OPPOSITE) { + alignment = Layout.Alignment.ALIGN_NORMAL; + } + } + return StaticLayout.Builder.obtain(source, 0, source.length(), paint, width) + .setAlignment(alignment) + .setLineSpacing(mLineSpacingExtra, getLineSpacingMultiplier()) + .setIncludePad(true) + .setMaxLines(numberOfLines) + .setEllipsize(TruncateAt.END) + .setBreakStrategy(getBreakStrategy()) + .build(); + } + private StaticLayout buildStaticLayout(CharSequence source, TextPaint paint, int width) { Layout.Alignment alignment = mAlignment; if (I18nUtil.isRTL()) { @@ -705,7 +730,6 @@ private StaticLayout truncateLayoutWithNumberOfLine(Layout preLayout, int width, ? ((SpannableStringBuilder) formerLines).append(lastLine) : ((StringBuilder) formerLines).append(lastLine); } - return buildStaticLayout(truncated, paint, width); } From b95df1bfea872145c50880d92e347a6bc3dc0c88 Mon Sep 17 00:00:00 2001 From: wwwcg Date: Thu, 15 Aug 2024 17:45:38 +0800 Subject: [PATCH 11/47] refactor(ios): remove all context wrapper classes (#3994) --- framework/ios/base/bridge/HippyBridge.h | 10 +- framework/ios/base/bridge/HippyBridge.mm | 86 ++- .../base/enginewrapper/HippyContextWrapper.h | 92 --- .../jsc/HippyJSCContextWrapper.h | 36 - .../jsc/HippyJSCContextWrapper.mm | 448 ----------- .../enginewrapper/v8/HippyV8ContextWrapper.h | 32 - .../enginewrapper/v8/HippyV8ContextWrapper.mm | 701 ------------------ .../ios/base/executors/HippyJSExecutor.h | 19 +- .../ios/base/executors/HippyJSExecutor.mm | 264 +++---- framework/ios/base/modules/HippyModuleData.mm | 8 +- framework/ios/utils/jsc/NSObject+JSValue.h | 55 -- framework/ios/utils/jsc/NSObject+JSValue.m | 253 ------- framework/ios/utils/v8/NSObject+V8Value.h | 77 -- framework/ios/utils/v8/NSObject+V8Value.mm | 268 ------- hippy.podspec | 15 - modules/footstone/src/platform/ios/logging.cc | 4 - 16 files changed, 205 insertions(+), 2163 deletions(-) delete mode 100644 framework/ios/base/enginewrapper/HippyContextWrapper.h delete mode 100644 framework/ios/base/enginewrapper/jsc/HippyJSCContextWrapper.h delete mode 100644 framework/ios/base/enginewrapper/jsc/HippyJSCContextWrapper.mm delete mode 100644 framework/ios/base/enginewrapper/v8/HippyV8ContextWrapper.h delete mode 100644 framework/ios/base/enginewrapper/v8/HippyV8ContextWrapper.mm delete mode 100644 framework/ios/utils/jsc/NSObject+JSValue.h delete mode 100644 framework/ios/utils/jsc/NSObject+JSValue.m delete mode 100644 framework/ios/utils/v8/NSObject+V8Value.h delete mode 100644 framework/ios/utils/v8/NSObject+V8Value.mm 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(); - } } From b04da96119d7ee71b906d0c39b542364e87ff555 Mon Sep 17 00:00:00 2001 From: zealotchen <92966734+zealotchen0@users.noreply.github.com> Date: Mon, 19 Aug 2024 16:55:38 +0800 Subject: [PATCH 12/47] feat(vue-next): fix onInterceptTouchEvent not work (#3995) * feat(vue-next): fix onInterceptTouchEvent not work * fix(vue-next): fix remove attr not update * fix(vue-next): revert vue-next version --- driver/js/packages/hippy-vue-next/src/modules/attrs.ts | 4 +--- driver/js/packages/hippy-vue-next/src/patch-prop.ts | 6 +++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/driver/js/packages/hippy-vue-next/src/modules/attrs.ts b/driver/js/packages/hippy-vue-next/src/modules/attrs.ts index 7800ffabb20..5112f1775af 100644 --- a/driver/js/packages/hippy-vue-next/src/modules/attrs.ts +++ b/driver/js/packages/hippy-vue-next/src/modules/attrs.ts @@ -35,9 +35,7 @@ export function patchAttr( nextValue: NeedToTyped, ): void { // set attr when next value is not equal before value - if (nextValue === null) { - el.removeAttribute(key); - } else if (prevValue !== nextValue) { + if (prevValue !== nextValue) { el.setAttribute(key, nextValue); } } diff --git a/driver/js/packages/hippy-vue-next/src/patch-prop.ts b/driver/js/packages/hippy-vue-next/src/patch-prop.ts index 04d57d0db5d..f864b739227 100644 --- a/driver/js/packages/hippy-vue-next/src/patch-prop.ts +++ b/driver/js/packages/hippy-vue-next/src/patch-prop.ts @@ -50,7 +50,7 @@ export function patchProp( patchStyle(el, prevValue, nextValue); break; default: - if (isOn(key)) { + if (isOn(key) && !isNativeEvent(key)) { // event prop patchEvent(el, key, prevValue, nextValue, parentComponent); } else { @@ -60,3 +60,7 @@ export function patchProp( break; } } + +export function isNativeEvent(key: string) { + return ['onInterceptTouchEvent', 'onInterceptPullUpEvent'].indexOf(key) >= 0; +} From 269c33dad0e9f543b30b660bd9ec6230916479a9 Mon Sep 17 00:00:00 2001 From: maxli Date: Tue, 20 Aug 2024 15:29:58 +0800 Subject: [PATCH 13/47] fix(android): append init props for image load --- .../renderer/component/image/ImageLoader.java | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/renderer/native/android/src/main/java/com/tencent/renderer/component/image/ImageLoader.java b/renderer/native/android/src/main/java/com/tencent/renderer/component/image/ImageLoader.java index 3a0bd902702..dd21fc09fb1 100644 --- a/renderer/native/android/src/main/java/com/tencent/renderer/component/image/ImageLoader.java +++ b/renderer/native/android/src/main/java/com/tencent/renderer/component/image/ImageLoader.java @@ -155,9 +155,29 @@ private void handleRequestProgress(final long total, final long loaded, } } + private void appendCustomRequestParams(@NonNull HashMap requestParams, + @NonNull Map initProps) { + for (Map.Entry entry : initProps.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + try { + requestParams.put(key, String.valueOf(value)); + } catch (Exception ignore) { + // For now, support custom attributes that can be converted to strings + } + } + } + @NonNull - private HashMap generateRequestParams(int width, int height) { + private HashMap generateRequestParams(int width, int height, + @Nullable Map initProps) { HashMap requestParams = new HashMap<>(); + if (initProps != null) { + Object value = initProps.get("props"); + if (value instanceof Map) { + appendCustomRequestParams(requestParams, (Map) value); + } + } requestParams.put("width", String.valueOf(width)); requestParams.put("height", String.valueOf(height)); requestParams.put(REQUEST_CONTENT_TYPE, REQUEST_CONTENT_TYPE_IMAGE); @@ -167,7 +187,7 @@ private HashMap generateRequestParams(int width, int height) { @Nullable public ImageDataSupplier fetchImageSync(@NonNull String url, @Nullable Map initProps, int width, int height) { - HashMap requestParams = generateRequestParams(width, height); + HashMap requestParams = generateRequestParams(width, height, initProps); ResourceDataHolder dataHolder = mVfsManager.fetchResourceSync(url, null, requestParams); byte[] bytes = dataHolder.getBytes(); if (dataHolder.resultCode @@ -215,7 +235,7 @@ public void fetchImageAsync(@NonNull final String url, if (checkRepeatRequest(urlKey, listener)) { return; } - HashMap requestParams = generateRequestParams(width, height); + HashMap requestParams = generateRequestParams(width, height, initProps); mVfsManager.fetchResourceAsync(url, null, requestParams, new FetchResourceCallback() { @Override From 49fdb34a5cddb965af0458113f17ede09bcfea9c Mon Sep 17 00:00:00 2001 From: maxli Date: Thu, 22 Aug 2024 14:38:16 +0800 Subject: [PATCH 14/47] fix(android): use Spanned to getSpans --- .../java/com/tencent/renderer/component/Component.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/renderer/native/android/src/main/java/com/tencent/renderer/component/Component.java b/renderer/native/android/src/main/java/com/tencent/renderer/component/Component.java index 69c9b60d252..73e66202029 100644 --- a/renderer/native/android/src/main/java/com/tencent/renderer/component/Component.java +++ b/renderer/native/android/src/main/java/com/tencent/renderer/component/Component.java @@ -29,6 +29,7 @@ import android.text.Layout; import android.text.Spannable; +import android.text.Spanned; import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -336,10 +337,10 @@ public void setTextLayout(@NonNull Object layout) { assert mTextDrawable != null; if (mTextDrawable.getTextLayout() != null) { CharSequence textSequence = mTextDrawable.getTextLayout().getText(); - if (textSequence instanceof Spannable) { - Spannable spannable = (Spannable) textSequence; - TextGestureSpan[] spans = spannable - .getSpans(0, spannable.length(), TextGestureSpan.class); + if (textSequence instanceof Spanned) { + Spanned spannedText = (Spanned) textSequence; + TextGestureSpan[] spans = spannedText + .getSpans(0, spannedText.length(), TextGestureSpan.class); setGestureEnable((spans != null && spans.length > 0)); } } From ac3fd3dbce1498f5acee41d0e0bfe9ef1f3f7aa3 Mon Sep 17 00:00:00 2001 From: zealotchen Date: Mon, 26 Aug 2024 14:30:37 +0800 Subject: [PATCH 15/47] fix(vue-next): fix beforeLoadStyle not work --- .../hippy-vue-next-demo/src/main-native.ts | 20 +++++++++++++++++++ .../src/style-match/css-map.ts | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/driver/js/examples/hippy-vue-next-demo/src/main-native.ts b/driver/js/examples/hippy-vue-next-demo/src/main-native.ts index 89e0db5e097..5e22a426ece 100644 --- a/driver/js/examples/hippy-vue-next-demo/src/main-native.ts +++ b/driver/js/examples/hippy-vue-next-demo/src/main-native.ts @@ -4,6 +4,7 @@ import { EventBus, setScreenSize, BackAndroid, + Native, } from '@hippy/vue-next'; import App from './app.vue'; @@ -45,6 +46,25 @@ const app: HippyApp = createApp(App, { * default is true, if set false, it will follow vue-loader compilerOptions whitespace setting */ trimWhitespace: true, + styleOptions: { + beforeLoadStyle: (decl) => { + let { value } = decl; + // 比如可以对 rem 单位进行处理 + if (typeof value === 'string' && /rem$/.test(value)) { + // get the numeric value of rem + + const { screen } = Native.Dimensions; + // 比如可以对 rem 单位进行处理 + if (typeof value === 'string' && /rem$/.test(value)) { + const { width, height } = screen; + // 防止hippy 旋转后,宽度发生变化 + const realWidth = width > height ? width : height; + value = Number(parseFloat(`${(realWidth * 100 * Number(value.replace('rem', ''))) / 844}`).toFixed(2)); + } + } + return { ...decl, value }; + }, + }, }); // create router const router = createRouter(); diff --git a/driver/js/packages/hippy-vue-next-style-parser/src/style-match/css-map.ts b/driver/js/packages/hippy-vue-next-style-parser/src/style-match/css-map.ts index 1d4f0373abc..29e021fa60a 100644 --- a/driver/js/packages/hippy-vue-next-style-parser/src/style-match/css-map.ts +++ b/driver/js/packages/hippy-vue-next-style-parser/src/style-match/css-map.ts @@ -220,7 +220,7 @@ export function getCssMap( * Here is a secret startup option: beforeStyleLoadHook. * Usage for process the styles while styles loading. */ - const cssRules = fromAstNodes(styleCssMap); + const cssRules = fromAstNodes(styleCssMap, beforeLoadStyle); if (globalCssMap) { globalCssMap.append(cssRules); } else { From d27e8abe0001582193a10eb63c4005aa34673d17 Mon Sep 17 00:00:00 2001 From: wwwcg Date: Wed, 28 Aug 2024 15:39:56 +0800 Subject: [PATCH 16/47] fix(ios): resolve reload not working (#4006) refactor hippy demo code --- .../HippyDemo.xcodeproj/project.pbxproj | 6 -- .../RenderPage/HippyDemoViewController.m | 98 ++++++------------- framework/ios/base/bridge/HippyBridge.mm | 46 ++++----- renderer/native/ios/renderer/HippyRootView.mm | 6 -- .../native/ios/renderer/HippyUIManager.mm | 4 + 5 files changed, 56 insertions(+), 104 deletions(-) diff --git a/framework/examples/ios-demo/HippyDemo.xcodeproj/project.pbxproj b/framework/examples/ios-demo/HippyDemo.xcodeproj/project.pbxproj index 1635dc009ab..6ba3dd85e65 100644 --- a/framework/examples/ios-demo/HippyDemo.xcodeproj/project.pbxproj +++ b/framework/examples/ios-demo/HippyDemo.xcodeproj/project.pbxproj @@ -27,7 +27,6 @@ 9C99A05896359E49AE9A8352 /* MyView.m in Sources */ = {isa = PBXBuildFile; fileRef = 90F34E176169143334EDFC28 /* MyView.m */; }; 9CF888F990C83ECD4F6C78AA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5EF877A8CB4B2AD68A780A12 /* Assets.xcassets */; }; A3F629CA4C94D65F42BB4B33 /* HippyDemoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9EB0CD5FCC3F38E3C7DC5E00 /* HippyDemoViewController.m */; }; - B8AA2B793BE43710EFC9D4DC /* TestModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = D2241406CEF00D2FF5938BB2 /* TestModule.mm */; }; BD5196B65EE0B712FDA2EB9B /* UIViewController+Title.m in Sources */ = {isa = PBXBuildFile; fileRef = C412B5D210F1E3359523628C /* UIViewController+Title.m */; }; C1A78F8868963E6C790472AA /* PageCreationCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 25B65684EC9C9AF27BB04D21 /* PageCreationCell.xib */; }; C94B7BB8A618F36A1F58C270 /* HomePageViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 90B5552FD45612EC5EC4CB45 /* HomePageViewController.mm */; }; @@ -96,7 +95,6 @@ 9EB0CD5FCC3F38E3C7DC5E00 /* HippyDemoViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HippyDemoViewController.m; sourceTree = ""; }; A066953E3614D26125F617EF /* HippyPageCacheContainerView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HippyPageCacheContainerView.m; sourceTree = ""; }; B2FA2A97C78628634C6AFC9A /* TTTGB-Medium.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "TTTGB-Medium.otf"; sourceTree = ""; }; - B5A22F93EAA399DE400CED88 /* TestModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestModule.h; sourceTree = ""; }; BD54126F3E80B297E2109B40 /* DebugCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DebugCell.m; sourceTree = ""; }; BF84819C1E7CCD88BCBEA4D7 /* HippyPageCache.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HippyPageCache.h; sourceTree = ""; }; C412B5D210F1E3359523628C /* UIViewController+Title.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+Title.m"; sourceTree = ""; }; @@ -104,7 +102,6 @@ C6BAC7BC0021E9E21B04E496 /* SettingsInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SettingsInfo.m; sourceTree = ""; }; C7504BC18486120B29F3D9FA /* PageCreationCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PageCreationCell.h; sourceTree = ""; }; CC8AEAE8BF116954FB41BDF9 /* TurboBaseModule.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = TurboBaseModule.mm; sourceTree = ""; }; - D2241406CEF00D2FF5938BB2 /* TestModule.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = TestModule.mm; sourceTree = ""; }; D2EE3455BE6DD7D2ADA20093 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; DC53FC9D9560D6AD989F8540 /* HomePageView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = HomePageView.xib; sourceTree = ""; }; DDD052D2760E830B1E0095EA /* UIViewController+Title.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIViewController+Title.h"; sourceTree = ""; }; @@ -141,8 +138,6 @@ 17AB7FB6346FE861C9D953F5 /* IconUtils.m */, 177A9E8373F2682A9A831991 /* Info.plist */, D2EE3455BE6DD7D2ADA20093 /* main.m */, - B5A22F93EAA399DE400CED88 /* TestModule.h */, - D2241406CEF00D2FF5938BB2 /* TestModule.mm */, DDD052D2760E830B1E0095EA /* UIViewController+Title.h */, C412B5D210F1E3359523628C /* UIViewController+Title.m */, 4CF6648308C60D57DD274D30 /* HomePage */, @@ -393,7 +388,6 @@ DCCEB3FED1802C0D9C21AB11 /* PageManagerViewController.m in Sources */, F3F6D205C6FBA36CB262A28E /* SettingsInfo.m in Sources */, 380469787621147052854E8F /* SettingsViewController.m in Sources */, - B8AA2B793BE43710EFC9D4DC /* TestModule.mm in Sources */, 74C51526435B1AB788CBF991 /* TurboBaseModule.mm in Sources */, 72328C3389BA8DD5E54D7D5F /* TurboConfig.m in Sources */, BD5196B65EE0B712FDA2EB9B /* UIViewController+Title.m in Sources */, diff --git a/framework/examples/ios-demo/HippyDemo/RenderPage/HippyDemoViewController.m b/framework/examples/ios-demo/HippyDemo/RenderPage/HippyDemoViewController.m index b3439997871..926c1bfdeaa 100644 --- a/framework/examples/ios-demo/HippyDemo/RenderPage/HippyDemoViewController.m +++ b/framework/examples/ios-demo/HippyDemo/RenderPage/HippyDemoViewController.m @@ -25,15 +25,13 @@ #import "HippyPageCache.h" #import "DemoConfigs.h" -#import "HippyMethodInterceptorProtocol.h" - #import #import #import #import #import +#import -static NSString *const engineKey = @"Demo"; static NSString *formatLog(NSDate *timestamp, HippyLogLevel level, NSString *fileName, NSNumber *lineNumber, NSString *message) { static NSArray *logLevelMap; @@ -48,7 +46,7 @@ NSString *levelStr = level < 0 || level > logLevelMap.count ? logLevelMap[1] : logLevelMap[level]; if(fileName){ - return [[NSString alloc] initWithFormat:@"[%@][%@:%d][%@]%@", + return [[NSString alloc] initWithFormat:@"[%@][%@:%d][%@] %@", [formatter stringFromDate:timestamp], fileName.lastPathComponent, lineNumber.intValue, @@ -142,89 +140,49 @@ - (void)runHippyCache { } - (void)runHippyDemo { - NSDictionary *launchOptions = @{@"EnableTurbo": @(DEMO_ENABLE_TURBO), @"DebugMode": @(_isDebugMode)}; - NSString *uniqueEngineKey = [NSString stringWithFormat:@"%@_%u", engineKey, arc4random()]; - - _hippyBridge = [[HippyBridge alloc] initWithDelegate:self - moduleProvider:nil - launchOptions:launchOptions - executorKey:uniqueEngineKey]; - _hippyBridge.methodInterceptor = self; - - [_hippyBridge setInspectable:YES]; - - [self mountConnector:_hippyBridge]; -} - -- (void)mountConnector:(HippyBridge *)hippyBridge { - BOOL isSimulator = NO; -#if TARGET_IPHONE_SIMULATOR - isSimulator = YES; -#endif - -#if USE_NEW_LOAD - HippyRootView *rootView = [[HippyRootView alloc] initWithBridge:hippyBridge - moduleName:@"Demo" - initialProperties:@{@"isSimulator": @(isSimulator)} - delegate:self]; + // Necessary configuration: + NSString *moduleName = @"Demo"; + NSDictionary *launchOptions = @{ @"DebugMode": @(_isDebugMode) }; + NSDictionary *initialProperties = @{ @"isSimulator": @(TARGET_OS_SIMULATOR) }; - if (_isDebugMode) { - hippyBridge.sandboxDirectory = [_debugURL URLByDeletingLastPathComponent]; - [hippyBridge loadBundleURL:_debugURL completion:^(NSURL * _Nullable, NSError * _Nullable) { - [rootView runHippyApplication]; - }]; - } else { - NSURL *vendorBundleURL = [self vendorBundleURL]; - [hippyBridge loadBundleURL:vendorBundleURL completion:^(NSURL * _Nullable, NSError * _Nullable) { - NSLog(@"url %@ load finish", vendorBundleURL); - }]; - NSURL *indexBundleURL = [self indexBundleURL]; - hippyBridge.sandboxDirectory = [indexBundleURL URLByDeletingLastPathComponent]; - [hippyBridge loadBundleURL:indexBundleURL completion:^(NSURL * _Nullable, NSError * _Nullable) { - NSLog(@"url %@ load finish", indexBundleURL); - [rootView runHippyApplication]; - }]; - } - -#else + HippyBridge *bridge = nil; HippyRootView *rootView = nil; - if (_isDebugMode) { - hippyBridge.sandboxDirectory = [_debugURL URLByDeletingLastPathComponent]; - rootView = [[HippyRootView alloc] initWithBridge:hippyBridge - businessURL:_debugURL - moduleName:@"Demo" - initialProperties:@{@"isSimulator": @(isSimulator)} + bridge = [[HippyBridge alloc] initWithDelegate:self + bundleURL:_debugURL + moduleProvider:nil + launchOptions:launchOptions + executorKey:nil]; + rootView = [[HippyRootView alloc] initWithBridge:bridge + moduleName:moduleName + initialProperties:initialProperties delegate:self]; } else { NSURL *vendorBundleURL = [self vendorBundleURL]; NSURL *indexBundleURL = [self indexBundleURL]; - [hippyBridge loadBundleURL:vendorBundleURL - bundleType:HippyBridgeBundleTypeVendor - completion:^(NSURL * _Nullable url, NSError * _Nullable error) { - NSLog(@"url %@ load finish", vendorBundleURL); - }]; - hippyBridge.sandboxDirectory = [indexBundleURL URLByDeletingLastPathComponent]; - rootView = [[HippyRootView alloc] initWithBridge:hippyBridge + HippyBridge *bridge = [[HippyBridge alloc] initWithDelegate:self + bundleURL:vendorBundleURL + moduleProvider:nil + launchOptions:launchOptions + executorKey:nil]; + rootView = [[HippyRootView alloc] initWithBridge:bridge businessURL:indexBundleURL - moduleName:@"Demo" - initialProperties:@{@"isSimulator": @(isSimulator)} + moduleName:moduleName + initialProperties:initialProperties delegate:self]; } -#endif - + bridge.methodInterceptor = self; + [bridge setInspectable:YES]; + _hippyBridge = bridge; rootView.frame = self.contentAreaView.bounds; rootView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; - [self.contentAreaView addSubview:rootView]; _hippyRootView = rootView; } -- (void)viewDidLayoutSubviews { - [super viewDidLayoutSubviews]; - _hippyRootView.frame = self.contentAreaView.bounds; -} + +#pragma mark - - (NSURL *)vendorBundleURL { NSString *path = nil; diff --git a/framework/ios/base/bridge/HippyBridge.mm b/framework/ios/base/bridge/HippyBridge.mm index e5517b92c36..0f5c1b5f81c 100644 --- a/framework/ios/base/bridge/HippyBridge.mm +++ b/framework/ios/base/bridge/HippyBridge.mm @@ -234,40 +234,24 @@ - (instancetype)initWithDelegate:(id)delegate _debugMode = [launchOptions[@"DebugMode"] boolValue]; _enableTurbo = !!launchOptions[@"EnableTurbo"] ? [launchOptions[@"EnableTurbo"] boolValue] : YES; _engineKey = executorKey.length > 0 ? executorKey : [NSString stringWithFormat:@"%p", self]; - _invalidateReason = HippyInvalidateReasonDealloc; - _valid = YES; _bundlesQueue = [[HippyBundleOperationQueue alloc] init]; - _startTime = footstone::TimePoint::SystemNow(); + HippyLogInfo(@"HippyBridge init begin, self:%p", self); + + // Set the log delegate for hippy core module registerLogDelegateToHippyCore(); - - HippyExecuteOnMainThread(^{ - self->_isOSNightMode = [HippyDeviceBaseInfo isUIScreenInOSDarkMode]; - self.cachedDimensionsInfo = hippyExportedDimensions(self); - }, YES); + // Setup [self setUp]; - [self addImageProviderClass:[HippyDefaultImageProvider class]]; - [self setVfsUriLoader:[self createURILoaderIfNeeded]]; - [self setUpNativeRenderManager]; - + // Record bridge instance for RedBox (Debug Only) [HippyBridge setCurrentBridge:self]; - - [self loadPendingVendorBundleURLIfNeeded]; - - // Set the default sandbox directory - [self setSandboxDirectory:[bundleURL URLByDeletingLastPathComponent]]; HippyLogInfo(@"HippyBridge init end, self:%p", self); } return self; } - (void)dealloc { - /** - * This runs only on the main thread, but crashes the subclass - * HippyAssertMainQueue(); - */ HippyLogInfo(@"[Hippy_OC_Log][Life_Circle],%@ dealloc %p", NSStringFromClass([self class]), self); [[NSNotificationCenter defaultCenter] removeObserver:self]; self.invalidateReason = HippyInvalidateReasonDealloc; @@ -442,6 +426,14 @@ - (void)requestReload { - (void)setUp { _valid = YES; + _startTime = footstone::TimePoint::SystemNow(); + + // Get global enviroment info + HippyExecuteOnMainThread(^{ + self->_isOSNightMode = [HippyDeviceBaseInfo isUIScreenInOSDarkMode]; + self.cachedDimensionsInfo = hippyExportedDimensions(self); + }, YES); + self.moduleSemaphore = dispatch_semaphore_create(0); @try { __weak HippyBridge *weakSelf = self; @@ -478,6 +470,16 @@ - (void)setUp { } @catch (NSException *exception) { HippyBridgeHandleException(exception, self); } + + [self addImageProviderClass:[HippyDefaultImageProvider class]]; + [self setVfsUriLoader:[self createURILoaderIfNeeded]]; + [self setUpNativeRenderManager]; + + // Load pending js bundles + [self loadPendingVendorBundleURLIfNeeded]; + + // Set the default sandbox directory + [self setSandboxDirectory:[_pendingLoadingVendorBundleURL URLByDeletingLastPathComponent]]; } @@ -1274,7 +1276,7 @@ - (void)setRootView:(UIView *)rootView { _rootNode->SetRootOrigin(rootView.frame.origin.x, rootView.frame.origin.y); //set rendermanager for dommanager - if (!domManager->GetRenderManager().lock()) { + if (domManager->GetRenderManager().lock() != _renderManager) { domManager->SetRenderManager(_renderManager); } //bind rootview and root node diff --git a/renderer/native/ios/renderer/HippyRootView.mm b/renderer/native/ios/renderer/HippyRootView.mm index 9b40d29c24b..a5389fed0e2 100644 --- a/renderer/native/ios/renderer/HippyRootView.mm +++ b/renderer/native/ios/renderer/HippyRootView.mm @@ -291,12 +291,6 @@ - (NSNumber *)hippyTag { return super.hippyTag; } -- (void)bridgeDidReload { - HippyAssertMainQueue(); - // Clear the hippyTag so it can be re-assigned - self.hippyTag = nil; -} - #pragma mark - Notification Handlers diff --git a/renderer/native/ios/renderer/HippyUIManager.mm b/renderer/native/ios/renderer/HippyUIManager.mm index 2891ddea9ab..451aa0c4298 100644 --- a/renderer/native/ios/renderer/HippyUIManager.mm +++ b/renderer/native/ios/renderer/HippyUIManager.mm @@ -245,6 +245,10 @@ - (void)invalidate { }); } +- (void)dealloc { + HippyLogInfo(@"[Hippy_OC_Log][Life_Circle], HippyUIManager(%p) dealloc", self); +} + #pragma mark Setter & Getter - (void)registRenderManager:(std::weak_ptr)renderManager { From 4ce199fc1de71b5b1e387441329b45e39ea63fe9 Mon Sep 17 00:00:00 2001 From: wwwcg Date: Wed, 28 Aug 2024 16:51:22 +0800 Subject: [PATCH 17/47] fix(ios): resolve conversion error between NSString and CtxValue (#4007) add unit test for data conversion --- driver/js/include/driver/napi/jsc/jsc_ctx.h | 3 +- framework/ios/base/bridge/HippyBridge.mm | 3 +- framework/ios/utils/NSObject+CtxValue.mm | 26 ++-- tests/ios/HippyCtxValueConvertTest.mm | 134 ++++++++++++++++++++ 4 files changed, 148 insertions(+), 18 deletions(-) create mode 100644 tests/ios/HippyCtxValueConvertTest.mm diff --git a/driver/js/include/driver/napi/jsc/jsc_ctx.h b/driver/js/include/driver/napi/jsc/jsc_ctx.h index 8f0975c28ab..d8d6e12e74f 100644 --- a/driver/js/include/driver/napi/jsc/jsc_ctx.h +++ b/driver/js/include/driver/napi/jsc/jsc_ctx.h @@ -127,8 +127,7 @@ class JSCCtx : public Ctx { virtual std::shared_ptr CreateObject() override; virtual std::shared_ptr CreateNumber(double number) override; virtual std::shared_ptr CreateBoolean(bool b) override; - virtual std::shared_ptr CreateString( - const string_view& string) override; + virtual std::shared_ptr CreateString(const string_view& string) override; virtual std::shared_ptr CreateUndefined() override; virtual std::shared_ptr CreateNull() override; virtual std::shared_ptr CreateObject(const std::unordered_map< diff --git a/framework/ios/base/bridge/HippyBridge.mm b/framework/ios/base/bridge/HippyBridge.mm index 0f5c1b5f81c..022b9e72e8c 100644 --- a/framework/ios/base/bridge/HippyBridge.mm +++ b/framework/ios/base/bridge/HippyBridge.mm @@ -787,8 +787,7 @@ - (void)actuallyInvokeAndProcessModule:(NSString *)module method:(NSString *)met - (void)dispatchBlock:(dispatch_block_t)block queue:(dispatch_queue_t)queue { if (HippyJSThread == queue) { [_javaScriptExecutor executeBlockOnJavaScriptQueue:block]; - } - else { + } else { dispatch_async(queue, block); } } diff --git a/framework/ios/utils/NSObject+CtxValue.mm b/framework/ios/utils/NSObject+CtxValue.mm index 00cf1ab915f..c7177eeade8 100644 --- a/framework/ios/utils/NSObject+CtxValue.mm +++ b/framework/ios/utils/NSObject+CtxValue.mm @@ -152,20 +152,17 @@ id ObjectFromCtxValue(CtxPtr context, CtxValuePtr value) { if (context->IsString(value)) { footstone::string_view view; if (context->GetValueString(value, &view)) { - view = footstone::StringViewUtils::ConvertEncoding(view, footstone::string_view::Encoding::Utf16); + view = footstone::StringViewUtils::CovertToUtf16(view, view.encoding()); footstone::string_view::u16string &u16String = view.utf16_value(); - NSString *string = - [NSString stringWithCharacters:(const unichar *)u16String.c_str() length:u16String.length()]; + NSString *string = [NSString stringWithCharacters:(const unichar *)u16String.c_str() length:u16String.length()]; return string; } - } - else if (context->IsNumber(value)) { + } else if (context->IsNumber(value)) { double number = 0; if (context->GetValueNumber(value, &number)) { return @(number); } - } - else if (context->IsArray(value)) { + } else if (context->IsArray(value)) { uint32_t length = context->GetArrayLength(value); NSMutableArray *array = [NSMutableArray arrayWithCapacity:length]; for (uint32_t index = 0; index < length; index++) { @@ -183,8 +180,7 @@ id ObjectFromCtxValue(CtxPtr context, CtxValuePtr value) { if (context->GetByteBuffer(value, &bytes, length, type)) { return [NSData dataWithBytes:bytes length:length]; } - } - else if (context->IsObject(value)) { + } else if (context->IsObject(value)) { std::unordered_map map; if (context->GetEntriesFromObject(value, map)) { NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:map.size()]; @@ -194,17 +190,19 @@ id ObjectFromCtxValue(CtxPtr context, CtxValuePtr value) { if (!flag) { continue; } - const auto &u16String = footstone::StringViewUtils::CovertToUtf16(string_view, string_view.encoding()).utf16_value(); - NSString *string = [NSString stringWithCharacters:(const unichar *)u16String.c_str() length:u16String.length()]; + // Note that reference value (const auto &) cannot be used directly here, + // since the temporary string_view object will destruct the uft16 value. + // a wrong example is: + // const auto &u16Str = footstone::StringViewUtils::CovertToUtf16(string_view, string_view.encoding()).utf16_value(); + string_view = footstone::StringViewUtils::CovertToUtf16(string_view, string_view.encoding()); + footstone::string_view::u16string &u16Str = string_view.utf16_value(); + NSString *string = [NSString stringWithCharacters:(const unichar *)u16Str.c_str() length:u16Str.length()]; auto &value = it.second; id obj = ObjectFromCtxValue(context, value); [dictionary setObject:obj forKey:string]; } return [dictionary copy]; } - } - else { - } return [NSNull null]; } diff --git a/tests/ios/HippyCtxValueConvertTest.mm b/tests/ios/HippyCtxValueConvertTest.mm new file mode 100644 index 00000000000..040def8b410 --- /dev/null +++ b/tests/ios/HippyCtxValueConvertTest.mm @@ -0,0 +1,134 @@ +/*! + * 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 +#include "driver/engine.h" +#include "driver/vm/js_vm.h" +#include "driver/napi/js_ctx.h" + + +@interface HippyCtxValueConvertTest : XCTestCase + +/// hippy vm for test +@property (nonatomic, assign) std::shared_ptr vm; +/// context for test +@property (nonatomic, assign) std::shared_ptr context; + +@end + +@implementation HippyCtxValueConvertTest + +- (void)setUp { + _vm = hippy::CreateVM(std::make_shared()); + _context = _vm->CreateContext(); +} + +- (void)tearDown { + // nop +} + +- (void)testCtxStringToNSString { + std::shared_ptr ctxStr = _context->CreateString(u"shouldIgnoreLatestLogin"); + id ocObj = ObjectFromCtxValue(_context, ctxStr); + XCTAssert([ocObj isEqualToString:@"shouldIgnoreLatestLogin"]); +} + +- (void)testCtxObjectToNSDictionary { + const char *testKey = "MyVeryVeryLongStringKeyForUnitTest"; + std::shared_ptr ctxStr = _context->CreateString(u"myTestVeryLongStringValue"); + std::unordered_map> map = { {testKey , ctxStr} }; + std::shared_ptr ctxValue = _context->CreateObject(map); + id ocObj = ObjectFromCtxValue(_context, ctxValue); + XCTAssert([ocObj isKindOfClass:NSDictionary.class]); + XCTAssertTrue([[((NSDictionary *)ocObj) objectForKey:@(testKey)] isEqualToString:@"myTestVeryLongStringValue"]); +} + +// NSString +- (void)testNSStringToCtxValue { + NSString *testOCString = @"Hello Hippy"; + CtxValuePtr ctxValue = [testOCString convertToCtxValue:_context]; + XCTAssert(_context->IsString(ctxValue)); + XCTAssert([ObjectFromCtxValue(_context, ctxValue) isEqualToString:testOCString]); +} + +// NSNumber +- (void)testNSNumberToCtxValue { + NSNumber *testOCNumber = @42; + CtxValuePtr ctxValue = [testOCNumber convertToCtxValue:_context]; + XCTAssert(_context->IsNumber(ctxValue)); + XCTAssertTrue([ObjectFromCtxValue(_context, ctxValue) isEqualToNumber:testOCNumber]); +} + +// NSArray +- (void)testNSArrayToCtxValue { + NSArray *testOCArray = @[@"Hello", @42, @YES]; + CtxValuePtr ctxValue = [testOCArray convertToCtxValue:_context]; + XCTAssert(_context->IsArray(ctxValue)); + XCTAssert([ObjectFromCtxValue(_context, ctxValue) isEqualToArray:testOCArray]); +} + +// NSDictionary +- (void)testNSDictionaryToCtxValue { + NSDictionary *testOCDict = @{@"key1": @"value1", @"key2": @42}; + CtxValuePtr ctxValue = [testOCDict convertToCtxValue:_context]; + XCTAssert(_context->IsObject(ctxValue)); + XCTAssert([ObjectFromCtxValue(_context, ctxValue) isEqualToDictionary:testOCDict]); +} + +// NSData +- (void)testNSDataToCtxValue { + NSData *testOCData = [@"Hello Hippy" dataUsingEncoding:NSUTF8StringEncoding]; + CtxValuePtr ctxValue = [testOCData convertToCtxValue:_context]; + XCTAssert(_context->IsByteBuffer(ctxValue)); + XCTAssert([ObjectFromCtxValue(_context, ctxValue) isEqualToData:testOCData]); +} + +// NSNull +- (void)testNSNullToCtxValue { + NSNull *testOCNull = [NSNull null]; + CtxValuePtr ctxValue = [testOCNull convertToCtxValue:_context]; + XCTAssert(_context->IsNull(ctxValue)); + XCTAssert([ObjectFromCtxValue(_context, ctxValue) isKindOfClass:[NSNull class]]); +} + +// NSError +- (void)testNSErrorToCtxValue { + NSError *testOCError = [NSError errorWithDomain:@"com.example" code:42 userInfo:nil]; + CtxValuePtr ctxValue = [testOCError convertToCtxValue:_context]; + XCTAssert(_context->IsString(ctxValue)); // NSErrors are converted as string + NSString *resultDesc = ObjectFromCtxValue(_context, ctxValue); + XCTAssert([resultDesc isKindOfClass:[NSString class]]); + XCTAssertEqualObjects(resultDesc, testOCError.description); +} + +// NSURL +- (void)testNSURLToCtxValue { + NSURL *testOCURL = [NSURL URLWithString:@"https://www.example.com"]; + CtxValuePtr ctxValue = [testOCURL convertToCtxValue:_context]; + XCTAssert(_context->IsString(ctxValue)); // Assuming URLs are converted to strings + XCTAssert([ObjectFromCtxValue(_context, ctxValue) isEqualToString:[testOCURL absoluteString]]); +} + +@end From 48f746dca88d6dd6c92fa04685f67eac4ed0b43a Mon Sep 17 00:00:00 2001 From: wwwcg Date: Wed, 28 Aug 2024 16:49:37 +0800 Subject: [PATCH 18/47] chore(ios): update demo and eliminate some warnings --- driver/js/src/napi/jsc/jsc_ctx.cc | 2 +- .../HippyDemo/PageManager/HippyPageCache.h | 3 +- .../PageManager/PageCreationViewController.m | 34 +++-- .../RenderPage/HippyDemoViewController.m | 102 ++++--------- .../examples/ios-demo/HippyDemo/TestModule.h | 27 ---- .../examples/ios-demo/HippyDemo/TestModule.mm | 136 ------------------ modules/ios/base/HippyLog.mm | 15 +- .../waterfalllist/HippyWaterfallView.mm | 5 +- 8 files changed, 61 insertions(+), 263 deletions(-) delete mode 100644 framework/examples/ios-demo/HippyDemo/TestModule.h delete mode 100644 framework/examples/ios-demo/HippyDemo/TestModule.mm diff --git a/driver/js/src/napi/jsc/jsc_ctx.cc b/driver/js/src/napi/jsc/jsc_ctx.cc index 21669d0905f..dd88e02b860 100644 --- a/driver/js/src/napi/jsc/jsc_ctx.cc +++ b/driver/js/src/napi/jsc/jsc_ctx.cc @@ -320,7 +320,7 @@ std::shared_ptr JSCCtx::DefineClass(const string_view& name, JSStringRef set_key_name = JSStringCreateWithCharacters(reinterpret_cast(kSetStr), ARRAY_SIZE(kSetStr) - 1); JSStringRef define_property_name = JSStringCreateWithCharacters(reinterpret_cast(kDefinePropertyStr), ARRAY_SIZE(kDefinePropertyStr) - 1); JSStringRef object_name = JSStringCreateWithCharacters(reinterpret_cast(kObjectStr), ARRAY_SIZE(kObjectStr) - 1); - for (auto i = 0; i < property_count; ++i) { + for (size_t i = 0; i < property_count; ++i) { auto property_descriptor = properties[i]; auto property_object = JSObjectMake(context_, parent_class_ref, nullptr); if (property_descriptor->getter) { diff --git a/framework/examples/ios-demo/HippyDemo/PageManager/HippyPageCache.h b/framework/examples/ios-demo/HippyDemo/PageManager/HippyPageCache.h index 3aa05d6be61..1bc08be8aea 100644 --- a/framework/examples/ios-demo/HippyDemo/PageManager/HippyPageCache.h +++ b/framework/examples/ios-demo/HippyDemo/PageManager/HippyPageCache.h @@ -27,7 +27,8 @@ NS_ASSUME_NONNULL_BEGIN typedef NS_ENUM(NSUInteger, DriverType) { DriverTypeReact, - DriverTypeVue, + DriverTypeVue2, + DriverTypeVue3 }; typedef NS_ENUM(NSUInteger, RenderType) { diff --git a/framework/examples/ios-demo/HippyDemo/PageManager/PageCreationViewController.m b/framework/examples/ios-demo/HippyDemo/PageManager/PageCreationViewController.m index 52cf8226b02..b1ccf371e1b 100644 --- a/framework/examples/ios-demo/HippyDemo/PageManager/PageCreationViewController.m +++ b/framework/examples/ios-demo/HippyDemo/PageManager/PageCreationViewController.m @@ -32,14 +32,15 @@ static NSString *const kDebugCell = @"debugCell"; static NSString *const kDriverTypeReact = @"JS React"; -static NSString *const kDriverTypeVue = @"JS Vue"; +static NSString *const kDriverTypeVue2 = @"JS Vue2"; +static NSString *const kDriverTypeVue3 = @"JS Vue3"; static NSString *const kRenderTypeNative = @"Native"; static NSString *const kCancel = @"取消"; @interface PageCreationViewController () { - NSString *_currentDriver; + DriverType _currentDriver; NSString *_renderer; UITableView *_tableView; BOOL _debugMode; @@ -54,7 +55,7 @@ - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. [self setNavigationItemTitle:@"Page Managerment"]; - _currentDriver = kDriverTypeReact; + _currentDriver = DriverTypeReact; _renderer = kRenderTypeNative; [self setNavigationAreaBackground:[UIColor whiteColor]]; CGFloat ratio = 229.f / 255.f; @@ -120,13 +121,14 @@ - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPa } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + if (0 == [indexPath section]) { PageCreationCell *cell = (PageCreationCell *)[tableView dequeueReusableCellWithIdentifier:kNormalCell forIndexPath:indexPath]; cell.summaryImageView.image = [UIImage imageFromIconName:@"driver_icon"]; cell.typeLabel.text = @"Driver"; - cell.subTypeLabel.text = _currentDriver; + cell.subTypeLabel.text = @[kDriverTypeReact, kDriverTypeVue2, kDriverTypeVue3][_currentDriver]; return cell; } else if (1 == [indexPath section]) { @@ -202,19 +204,25 @@ - (void)showDriverSelectMenu { [alert addAction:[UIAlertAction actionWithTitle:kDriverTypeReact style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { PageCreationViewController *strongVC = weakVC; if (strongVC) { - strongVC->_currentDriver = action.title; + strongVC->_currentDriver = DriverTypeReact; [strongVC->_tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationAutomatic]; } }]]; - [alert addAction:[UIAlertAction actionWithTitle:kDriverTypeVue style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + [alert addAction:[UIAlertAction actionWithTitle:kDriverTypeVue2 style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { PageCreationViewController *strongVC = weakVC; if (strongVC) { - strongVC->_currentDriver = action.title; + strongVC->_currentDriver = DriverTypeVue2; [strongVC->_tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone]; } }]]; - [alert addAction:[UIAlertAction actionWithTitle:kCancel style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { + [alert addAction:[UIAlertAction actionWithTitle:kDriverTypeVue3 style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { + PageCreationViewController *strongVC = weakVC; + if (strongVC) { + strongVC->_currentDriver = DriverTypeVue3; + [strongVC->_tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone]; + } }]]; + [alert addAction:[UIAlertAction actionWithTitle:kCancel style:UIAlertActionStyleCancel handler:nil]]; [self presentViewController:alert animated:YES completion:NULL]; } @@ -251,18 +259,18 @@ - (void)showRenderSelectMenu { } - (void)createDemoAction { - PageCreationCell *cell0 = [_tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]]; - DriverType driverType = [[cell0 subTypeLabel].text isEqualToString:@"JS React"]?DriverTypeReact:DriverTypeVue; -// PageCreationCell *cell1 = [_tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]]; + DriverType driverType = _currentDriver; RenderType renderType = RenderTypeNative; - //[cell1.subTypeLabel.text isEqualToString:@"Native"]?RenderTypeNative:RenderTypeNative; NSURL *debugURL = nil; if (_debugMode) { DebugCell *cell2 = [_tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:2]]; NSString *debugString = [cell2 debugURLString]; debugURL = [NSURL URLWithString:debugString]; } - HippyDemoViewController *vc = [[HippyDemoViewController alloc] initWithDriverType:driverType renderType:renderType debugURL:debugURL isDebugMode:_debugMode]; + HippyDemoViewController *vc = [[HippyDemoViewController alloc] initWithDriverType:driverType + renderType:renderType + debugURL:debugURL + isDebugMode:_debugMode]; NSMutableArray<__kindof UIViewController *> *viewControllers = [[self.navigationController viewControllers] mutableCopy]; [viewControllers removeLastObject]; [viewControllers addObject:vc]; diff --git a/framework/examples/ios-demo/HippyDemo/RenderPage/HippyDemoViewController.m b/framework/examples/ios-demo/HippyDemo/RenderPage/HippyDemoViewController.m index 926c1bfdeaa..74af3afde60 100644 --- a/framework/examples/ios-demo/HippyDemo/RenderPage/HippyDemoViewController.m +++ b/framework/examples/ios-demo/HippyDemo/RenderPage/HippyDemoViewController.m @@ -33,34 +33,6 @@ #import -static NSString *formatLog(NSDate *timestamp, HippyLogLevel level, NSString *fileName, NSNumber *lineNumber, NSString *message) { - static NSArray *logLevelMap; - static NSDateFormatter *formatter; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - logLevelMap = @[@"TRACE", @"INFO", @"WARN", @"ERROR", @"FATAL"]; - formatter = [NSDateFormatter new]; - formatter.dateFormat = formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss.SSS"; - }); - - NSString *levelStr = level < 0 || level > logLevelMap.count ? logLevelMap[1] : logLevelMap[level]; - - if(fileName){ - return [[NSString alloc] initWithFormat:@"[%@][%@:%d][%@] %@", - [formatter stringFromDate:timestamp], - fileName.lastPathComponent, - lineNumber.intValue, - levelStr, - message - ]; - }else{ - return [[NSString alloc] initWithFormat:@"[%@]%@", - [formatter stringFromDate:timestamp], - message - ]; - } -} - @interface HippyDemoViewController () { DriverType _driverType; RenderType _renderType; @@ -123,22 +95,19 @@ - (void)viewDidLoad { } } -- (void)registerLogFunction { - HippySetLogFunction(^(HippyLogLevel level, HippyLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { - NSString *log = formatLog([NSDate date], level, fileName, lineNumber, message); - if([log hasSuffix:@"\n"]){ - fprintf(stderr, "%s", log.UTF8String); - }else{ - fprintf(stderr, "%s\n", log.UTF8String); - } - }); -} - - (void)runHippyCache { _hippyRootView.frame = self.contentAreaView.bounds; [self.contentAreaView addSubview:_hippyRootView]; } +#pragma mark - Hippy Setup + +- (void)registerLogFunction { + // Register your custom log function for Hippy, + // use HippyDefaultLogFunction as an example, it outputs logs to stderr. + HippySetLogFunction(HippyDefaultLogFunction); +} + - (void)runHippyDemo { // Necessary configuration: NSString *moduleName = @"Demo"; @@ -172,54 +141,43 @@ - (void)runHippyDemo { delegate:self]; } - bridge.methodInterceptor = self; + // // Config whether jsc is inspectable, Highly recommended setting, + // since inspectable of JSC is disabled by default since iOS 16.4 [bridge setInspectable:YES]; _hippyBridge = bridge; rootView.frame = self.contentAreaView.bounds; rootView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; [self.contentAreaView addSubview:rootView]; _hippyRootView = rootView; + + + // Optional configs: + bridge.methodInterceptor = self; // see HippyMethodInterceptorProtocol } -#pragma mark - +#pragma mark - Helpers -- (NSURL *)vendorBundleURL { - NSString *path = nil; - if (DriverTypeReact == _driverType) { - path = [[NSBundle mainBundle] pathForResource:@"vendor.ios" ofType:@"js" inDirectory:@"res/react"]; +- (NSString *)currentJSBundleDir { + NSString *dir = nil; + if (DriverTypeVue2 == _driverType) { + dir = @"res/vue2"; + } else if (DriverTypeVue3 == _driverType) { + dir = @"res/vue3"; + } else if (DriverTypeReact == _driverType) { + dir = @"res/react"; } - else if (DriverTypeVue == _driverType) { - path = [[NSBundle mainBundle] pathForResource:@"vendor.ios" ofType:@"js" inDirectory:@"res/vue3"]; - } - return [NSURL fileURLWithPath:path]; + return dir; } -- (NSURL *)indexBundleURL { - NSString *path = nil; - if (DriverTypeReact == _driverType) { - path = [[NSBundle mainBundle] pathForResource:@"index.ios" ofType:@"js" inDirectory:@"res/react"]; - } - else if (DriverTypeVue == _driverType) { - path = [[NSBundle mainBundle] pathForResource:@"index.ios" ofType:@"js" inDirectory:@"res/vue3"]; - } +- (NSURL *)vendorBundleURL { + NSString *path = [[NSBundle mainBundle] pathForResource:@"vendor.ios" ofType:@"js" inDirectory:[self currentJSBundleDir]]; return [NSURL fileURLWithPath:path]; } -- (DriverType)driverType { - return _driverType; -} - -- (RenderType)renderType { - return _renderType; -} - -- (NSURL *)debugURL { - return _debugURL; -} - -- (BOOL)isDebugMode { - return _isDebugMode; +- (NSURL *)indexBundleURL { + NSString *path = [[NSBundle mainBundle] pathForResource:@"index.ios" ofType:@"js" inDirectory:[self currentJSBundleDir]]; + return [NSURL fileURLWithPath:path]; } - (void)removeRootView:(NSNumber *)rootTag bridge:(HippyBridge *)bridge { @@ -258,7 +216,7 @@ - (BOOL)shouldStartInspector:(HippyBridge *)bridge { } -#pragma mark - HippyMethodInterceptorProtocol +#pragma mark - Optional - HippyMethodInterceptorProtocol - (BOOL)shouldInvokeWithModuleName:(NSString *)moduleName methodName:(NSString *)methodName diff --git a/framework/examples/ios-demo/HippyDemo/TestModule.h b/framework/examples/ios-demo/HippyDemo/TestModule.h deleted file mode 100644 index b461e122363..00000000000 --- a/framework/examples/ios-demo/HippyDemo/TestModule.h +++ /dev/null @@ -1,27 +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 "HippyBridgeModule.h" - -@interface TestModule : NSObject - -@end diff --git a/framework/examples/ios-demo/HippyDemo/TestModule.mm b/framework/examples/ios-demo/HippyDemo/TestModule.mm deleted file mode 100644 index 69a0e711364..00000000000 --- a/framework/examples/ios-demo/HippyDemo/TestModule.mm +++ /dev/null @@ -1,136 +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 "AppDelegate.h" -#import "TestModule.h" -#import "HippyBundleURLProvider.h" -#import "HippyJSEnginesMapper.h" -#import "HippyRootView.h" -#import "UIView+Hippy.h" -#import "HippyLog.h" -#import "HippyRedBox.h" -#import "DemoConfigs.h" -#import "HippyMethodInterceptorProtocol.h" -#import "HippyAssert.h" - -static NSString *const engineKey = @"Demo"; - -@interface TestModule () { - HippyBridge *_connector; -} - -@end - -@implementation TestModule - -HIPPY_EXPORT_MODULE() - -- (dispatch_queue_t)methodQueue { - return dispatch_get_main_queue(); -} - -HIPPY_EXPORT_METHOD(debug:(nonnull NSNumber *)instanceId) { -} - -HIPPY_EXPORT_METHOD(remoteDebug:(nonnull NSNumber *)instanceId bundleUrl:(nonnull NSString *)bundleUrl) { - [self runCommonDemo:bundleUrl]; -} - -- (void)runCommonDemo:(nonnull NSString *)bundleUrl { - BOOL isSimulator = NO; - #if TARGET_IPHONE_SIMULATOR - isSimulator = YES; - #endif - AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate]; - UIViewController *rootViewController = delegate.window.rootViewController; - UIViewController *vc = [[UIViewController alloc] init]; - //JS Contexts holding the same engine key will share VM - NSURL *url = [NSURL URLWithString:bundleUrl]; - NSDictionary *launchOptions = @{@"EnableTurbo": @(DEMO_ENABLE_TURBO), @"DebugMode": @(YES), @"DebugURL": url}; - NSURL *sandboxDirectory = [url URLByDeletingLastPathComponent]; - _connector = [[HippyBridge alloc] initWithDelegate:self - moduleProvider:nil - launchOptions:launchOptions - executorKey:engineKey]; - [_connector setInspectable:YES]; - //set custom vfs loader - _connector.sandboxDirectory = sandboxDirectory; - _connector.contextName = @"Demo"; - _connector.moduleName = @"Demo"; - _connector.methodInterceptor = self; - vc.modalPresentationStyle = UIModalPresentationFullScreen; - [self mountConnector:_connector onView:vc.view]; - [rootViewController presentViewController:vc animated:YES completion:NULL]; -} - -- (void)mountConnector:(HippyBridge *)connector onView:(UIView *)view { - BOOL isSimulator = NO; -#if TARGET_IPHONE_SIMULATOR - isSimulator = YES; -#endif - - NSString *bundleStr = [HippyBundleURLProvider sharedInstance].bundleURLString; - NSURL *bundleUrl = [NSURL URLWithString:bundleStr]; - - HippyRootView *rootView = [[HippyRootView alloc] initWithFrame:view.bounds]; - rootView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; - [_connector setRootView:rootView]; - NSNumber *rootTag = [rootView hippyTag]; - [connector loadBundleURL:bundleUrl - bundleType:HippyBridgeBundleTypeBusiness - completion:^(NSURL * _Nullable bundleURL, NSError * _Nullable error) { - NSLog(@"url %@ load finish", bundleStr); - [connector loadInstanceForRootView:rootTag withProperties:@{@"isSimulator": @(isSimulator)}]; - }]; - [view addSubview:rootView]; -} - -- (void)reload:(HippyBridge *)bridge { - AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate]; - UIViewController *rootViewController = delegate.window.rootViewController; - UIViewController *vc = rootViewController.presentedViewController; - [self mountConnector:_connector onView:vc.view]; -} - -- (void)removeRootView:(NSNumber *)rootTag bridge:(HippyBridge *)bridge { - AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate]; - UIViewController *rootViewController = delegate.window.rootViewController; - UIViewController *vc = rootViewController.presentedViewController; - [[[vc.view subviews] firstObject] removeFromSuperview]; -} - -- (BOOL)shouldStartInspector:(HippyBridge *)bridge { - return bridge.debugMode; -} - -- (BOOL)shouldInvokeWithModuleName:(NSString *)moduleName methodName:(NSString *)methodName arguments:(NSArray> *)arguments argumentsValues:(NSArray *)argumentsValue containCallback:(BOOL)containCallback { - HippyAssert(moduleName, @"module name must not be null"); - HippyAssert(methodName, @"method name must not be null"); - return YES; -} - -- (BOOL)shouldCallbackBeInvokedWithModuleName:(NSString *)moduleName methodName:(NSString *)methodName callbackId:(NSNumber *)cbId arguments:(id)arguments { - HippyAssert(moduleName, @"module name must not be null"); - HippyAssert(methodName, @"method name must not be null"); - return YES; -} -@end diff --git a/modules/ios/base/HippyLog.mm b/modules/ios/base/HippyLog.mm index 33d4489932d..3bdf57eae3d 100644 --- a/modules/ios/base/HippyLog.mm +++ b/modules/ios/base/HippyLog.mm @@ -151,19 +151,12 @@ void HippyPerformBlockWithLogPrefix(void (^block)(void), NSString *prefix) { }); [log appendString:[formatter stringFromDate:timestamp]]; } - if (level) { - [log appendFormat:@"[%s]", HippyLogLevels[level]]; - } - - [log appendFormat:@"[tid:%@]", currentThreadName()]; - + [log appendFormat:@"[%s]", HippyLogLevels[level]]; + [log appendFormat:@"[%@]", currentThreadName()]; + if (fileName) { fileName = fileName.lastPathComponent; - if (lineNumber) { - [log appendFormat:@"[%@:%@]", fileName, lineNumber]; - } else { - [log appendFormat:@"[%@]", fileName]; - } + [log appendFormat:@"[%@:%@]", fileName, lineNumber]; } if (message) { [log appendString:@" "]; diff --git a/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.mm b/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.mm index 8561640ad85..6545dff75a0 100644 --- a/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.mm +++ b/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.mm @@ -520,8 +520,9 @@ - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView { } } -- (nullable UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView; -{ return nil; } +- (nullable UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { + return nil; +} - (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view { for (NSObject *scrollViewListener in [self scrollListeners]) { From 0bd662309caee33af508b1a09bee7cd33a44254d Mon Sep 17 00:00:00 2001 From: wwwcg Date: Mon, 2 Sep 2024 21:43:43 +0800 Subject: [PATCH 19/47] fix(ios): onShow event of modal component not working (#4012) remove obsolete onLayout property of shadowView --- .../src/components/Modal/index.jsx | 1 + .../native/ios/renderer/HippyComponentData.mm | 6 ++--- .../native/ios/renderer/HippyUIManager.mm | 26 +------------------ .../renderer/component/view/HippyShadowView.h | 1 - .../component/view/HippyViewManager.mm | 2 -- 5 files changed, 4 insertions(+), 32 deletions(-) diff --git a/driver/js/examples/hippy-react-demo/src/components/Modal/index.jsx b/driver/js/examples/hippy-react-demo/src/components/Modal/index.jsx index 7b2f772c5d3..1d59f0d1332 100644 --- a/driver/js/examples/hippy-react-demo/src/components/Modal/index.jsx +++ b/driver/js/examples/hippy-react-demo/src/components/Modal/index.jsx @@ -154,6 +154,7 @@ export default class ModalExpo extends React.Component { transparent={true} animationType={this.state.animationType} visible={visible} + onShow={() => { console.log('modal show'); }} requestClose={() => { /* Trigger when hardware back pressed */ }} orientationChange={(evt) => { console.log('orientation changed', evt.orientation); }} supportedOrientations={['portrait']} diff --git a/renderer/native/ios/renderer/HippyComponentData.mm b/renderer/native/ios/renderer/HippyComponentData.mm index 30f376fd65d..3eeaa26c128 100644 --- a/renderer/native/ios/renderer/HippyComponentData.mm +++ b/renderer/native/ios/renderer/HippyComponentData.mm @@ -192,11 +192,9 @@ - (HippyPropBlock)propBlockForKey:(NSString *)name inDictionary:(NSMutableDictio // Build setter block void (^setterBlock)(id target, id json) = nil; - if (type == NSSelectorFromString(@"HippyDirectEventBlock:")) { - //TODO - //The component event response logic no longer executes this code - } else { + { // Ordinary property handlers + // In hippy3, component's event property do not go here. NSMethodSignature *typeSignature = [[HippyConvert class] methodSignatureForSelector:type]; if (!typeSignature) { HippyLogError(@"No +[HippyConvert %@] function found.", NSStringFromSelector(type)); diff --git a/renderer/native/ios/renderer/HippyUIManager.mm b/renderer/native/ios/renderer/HippyUIManager.mm index 451aa0c4298..a91f31beb13 100644 --- a/renderer/native/ios/renderer/HippyUIManager.mm +++ b/renderer/native/ios/renderer/HippyUIManager.mm @@ -825,14 +825,6 @@ - (void)createRenderNodes:(std::vector> &&)nodes [uiManager->_componentTransactionListeners addObject:view]; } [tempCreatedViews addObject:view]; - - // TODO: hippy3 events binding handling, performance needs to be improved here. - const std::vector &eventNames = [shadowView allEventNames]; - for (auto &event : eventNames) { - [uiManager addEventNameInMainThread:event - forView:view - onRootNode:shadowView.rootNode]; - } } }]; } @@ -1169,12 +1161,6 @@ - (void)addEventName:(const std::string &)name UIView *view = viewRegistry[@(node_id)]; [uiManager addTouchEventListenerForType:name_ forView:view onRootNode:rootNode]; }]; - } else if (name == hippy::kShowEvent || name == hippy::kDismissEvent) { - std::string name_ = name; - [self addUIBlock:^(HippyUIManager *uiManager, NSDictionary *viewRegistry) { - UIView *view = viewRegistry[@(node_id)]; - [uiManager addShowEventListenerForType:name_ forView:view onRootNode:rootNode]; - }]; } else if (name == hippy::kPressIn || name == hippy::kPressOut) { std::string name_ = name; [self addUIBlock:^(HippyUIManager *uiManager, NSDictionary *viewRegistry) { @@ -1204,8 +1190,7 @@ - (void)addEventName:(const std::string &)name } forKey:vsyncKey]; } }]; - } - else { + } else { std::string name_ = name; [self addUIBlock:^(HippyUIManager *uiManager, NSDictionary *viewRegistry) { UIView *view = viewRegistry[@(node_id)]; @@ -1226,8 +1211,6 @@ - (void)addEventNameInMainThread:(const std::string &)name } else if (name == hippy::kTouchStartEvent || name == hippy::kTouchMoveEvent || name == hippy::kTouchEndEvent || name == hippy::kTouchCancelEvent) { [self addTouchEventListenerForType:name forView:view onRootNode:rootNode]; - } else if (name == hippy::kShowEvent || name == hippy::kDismissEvent) { - [self addShowEventListenerForType:name forView:view onRootNode:rootNode]; } else if (name == hippy::kPressIn || name == hippy::kPressOut) { [self addPressEventListenerForType:name forView:view onRootNode:rootNode]; } else { @@ -1384,13 +1367,6 @@ - (void)addTouchEventListenerForType:(const std::string &)type } } -- (void)addShowEventListenerForType:(const std::string &)type - forView:(UIView *)view - onRootNode:(std::weak_ptr)rootNode { - // Note: not implemented - // iOS do not have these event. -} - - (void)removeEventName:(const std::string &)eventName forDomNodeId:(int32_t)node_id onRootNode:(std::weak_ptr)rootNode { diff --git a/renderer/native/ios/renderer/component/view/HippyShadowView.h b/renderer/native/ios/renderer/component/view/HippyShadowView.h index df00d7a953b..07448d6d4d0 100644 --- a/renderer/native/ios/renderer/component/view/HippyShadowView.h +++ b/renderer/native/ios/renderer/component/view/HippyShadowView.h @@ -62,7 +62,6 @@ typedef void (^HippyViewInsertionBlock)(UIView *container, NSArray *ch @property(nonatomic, strong) UIColor *backgroundColor; // Used to propagate to children -@property(nonatomic, copy) HippyDirectEventBlock onLayout; @property(nonatomic, readonly) BOOL confirmedLayoutDirectionDidUpdated; /** diff --git a/renderer/native/ios/renderer/component/view/HippyViewManager.mm b/renderer/native/ios/renderer/component/view/HippyViewManager.mm index c0e80e02415..05cbaa8948e 100644 --- a/renderer/native/ios/renderer/component/view/HippyViewManager.mm +++ b/renderer/native/ios/renderer/component/view/HippyViewManager.mm @@ -571,8 +571,6 @@ - (void)loadImageSource:(NSString *)path forView:(HippyView *)view { HIPPY_EXPORT_SHADOW_PROPERTY(overflow, NSString) -HIPPY_EXPORT_SHADOW_PROPERTY(onLayout, HippyDirectEventBlock) - HIPPY_EXPORT_VIEW_PROPERTY(onDidMount, HippyDirectEventBlock) HIPPY_EXPORT_VIEW_PROPERTY(onDidUnmount, HippyDirectEventBlock) HIPPY_EXPORT_VIEW_PROPERTY(onAttachedToWindow, HippyDirectEventBlock) From 05b0ba18ddf02161689d45350c58454c8946e996 Mon Sep 17 00:00:00 2001 From: wwwcg Date: Tue, 3 Sep 2024 11:06:05 +0800 Subject: [PATCH 20/47] refactor(ios): remove unused code in scope and update demo (#4013) --- driver/js/include/driver/scope.h | 9 ------ .../RenderPage/HippyDemoViewController.m | 25 ++++++--------- framework/ios/base/bridge/HippyBridge.mm | 31 ++++++++----------- 3 files changed, 23 insertions(+), 42 deletions(-) diff --git a/driver/js/include/driver/scope.h b/driver/js/include/driver/scope.h index 0daf07568c6..fb67ae06533 100644 --- a/driver/js/include/driver/scope.h +++ b/driver/js/include/driver/scope.h @@ -304,14 +304,6 @@ class Scope : public std::enable_shared_from_this { inline std::weak_ptr GetDomManager() { return dom_manager_; } - inline void SetRenderManager(std::shared_ptr render_manager) { - render_manager_ = render_manager; - } - - inline std::weak_ptr GetRenderManager() { - return render_manager_; - } - inline std::weak_ptr GetRootNode() { return root_node_; } @@ -493,7 +485,6 @@ class Scope : public std::enable_shared_from_this { std::unique_ptr wrapper_; std::weak_ptr loader_; std::weak_ptr dom_manager_; - std::weak_ptr render_manager_; std::weak_ptr root_node_; std::unordered_map> module_object_map_; std::unordered_map> javascript_class_map_; diff --git a/framework/examples/ios-demo/HippyDemo/RenderPage/HippyDemoViewController.m b/framework/examples/ios-demo/HippyDemo/RenderPage/HippyDemoViewController.m index 74af3afde60..dde46817a75 100644 --- a/framework/examples/ios-demo/HippyDemo/RenderPage/HippyDemoViewController.m +++ b/framework/examples/ios-demo/HippyDemo/RenderPage/HippyDemoViewController.m @@ -34,11 +34,6 @@ @interface HippyDemoViewController () { - DriverType _driverType; - RenderType _renderType; - BOOL _isDebugMode; - NSURL *_debugURL; - HippyBridge *_hippyBridge; HippyRootView *_hippyRootView; BOOL _fromCache; @@ -57,7 +52,7 @@ - (instancetype)initWithDriverType:(DriverType)driverType _driverType = driverType; _renderType = renderType; _debugURL = debugURL; - _isDebugMode = isDebugMode; + _debugMode = isDebugMode; } return self; } @@ -68,7 +63,7 @@ - (instancetype)initWithPageCache:(HippyPageCache *)pageCache { _driverType = pageCache.driverType; _renderType = pageCache.renderType; _debugURL = pageCache.debugURL; - _isDebugMode = pageCache.isDebugMode; + _debugMode = pageCache.isDebugMode; _hippyRootView = pageCache.rootView; _hippyBridge = pageCache.hippyBridge; _fromCache = YES; @@ -111,12 +106,12 @@ - (void)registerLogFunction { - (void)runHippyDemo { // Necessary configuration: NSString *moduleName = @"Demo"; - NSDictionary *launchOptions = @{ @"DebugMode": @(_isDebugMode) }; + NSDictionary *launchOptions = @{ @"DebugMode": @(_debugMode) }; NSDictionary *initialProperties = @{ @"isSimulator": @(TARGET_OS_SIMULATOR) }; HippyBridge *bridge = nil; HippyRootView *rootView = nil; - if (_isDebugMode) { + if (_debugMode) { bridge = [[HippyBridge alloc] initWithDelegate:self bundleURL:_debugURL moduleProvider:nil @@ -129,11 +124,11 @@ - (void)runHippyDemo { } else { NSURL *vendorBundleURL = [self vendorBundleURL]; NSURL *indexBundleURL = [self indexBundleURL]; - HippyBridge *bridge = [[HippyBridge alloc] initWithDelegate:self - bundleURL:vendorBundleURL - moduleProvider:nil - launchOptions:launchOptions - executorKey:nil]; + bridge = [[HippyBridge alloc] initWithDelegate:self + bundleURL:vendorBundleURL + moduleProvider:nil + launchOptions:launchOptions + executorKey:moduleName]; rootView = [[HippyRootView alloc] initWithBridge:bridge businessURL:indexBundleURL moduleName:moduleName @@ -191,7 +186,7 @@ - (HippyPageCache *)toPageCache { pageCache.driverType = _driverType; pageCache.renderType = _renderType; pageCache.debugURL = _debugURL; - pageCache.debugMode = _isDebugMode; + pageCache.debugMode = _debugMode; UIGraphicsBeginImageContextWithOptions(_hippyRootView.bounds.size, NO, [UIScreen mainScreen].scale); [_hippyRootView drawViewHierarchyInRect:_hippyRootView.bounds afterScreenUpdates:YES]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); diff --git a/framework/ios/base/bridge/HippyBridge.mm b/framework/ios/base/bridge/HippyBridge.mm index 022b9e72e8c..fe6246a9d34 100644 --- a/framework/ios/base/bridge/HippyBridge.mm +++ b/framework/ios/base/bridge/HippyBridge.mm @@ -1025,24 +1025,19 @@ - (void)setMethodInterceptor:(id)methodIntercept - (void)setupDomManager:(std::shared_ptr)domManager rootNode:(std::weak_ptr)rootNode { - __weak HippyBridge *weakSelf = self; - dispatch_block_t block = ^(void){ - HippyBridge *strongSelf = weakSelf; - HippyAssertParam(domManager); - if (!strongSelf || !domManager) { - return; - } - strongSelf.javaScriptExecutor.pScope->SetDomManager(domManager); - strongSelf.javaScriptExecutor.pScope->SetRootNode(rootNode); - #ifdef ENABLE_INSPECTOR - auto devtools_data_source = strongSelf->_javaScriptExecutor.pScope->GetDevtoolsDataSource(); - if (devtools_data_source) { - strongSelf->_javaScriptExecutor.pScope->GetDevtoolsDataSource()->Bind(domManager); - devtools_data_source->SetRootNode(rootNode); - } - #endif - }; - block(); + HippyAssertParam(domManager); + if (!domManager) { + return; + } + self.javaScriptExecutor.pScope->SetDomManager(domManager); + self.javaScriptExecutor.pScope->SetRootNode(rootNode); +#ifdef ENABLE_INSPECTOR + auto devtools_data_source = self.javaScriptExecutor.pScope->GetDevtoolsDataSource(); + if (devtools_data_source) { + self.javaScriptExecutor.pScope->GetDevtoolsDataSource()->Bind(domManager); + devtools_data_source->SetRootNode(rootNode); + } +#endif } - (BOOL)isValid { From 90fdf9550115267353ff323e75eae0ebd6afa59a Mon Sep 17 00:00:00 2001 From: maxli Date: Tue, 3 Sep 2024 14:45:55 +0800 Subject: [PATCH 21/47] fix(android): add try catch for vfs processor chain get --- modules/vfs/android/build.gradle | 1 + .../main/java/com/tencent/vfs/VfsManager.java | 23 +++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/modules/vfs/android/build.gradle b/modules/vfs/android/build.gradle index bf738c416eb..3cf55dd9bcc 100644 --- a/modules/vfs/android/build.gradle +++ b/modules/vfs/android/build.gradle @@ -39,5 +39,6 @@ android { dependencies { compileOnly project(path: ':pool') + compileOnly project(path: ':hippy-support') implementation deps.annotation } diff --git a/modules/vfs/android/src/main/java/com/tencent/vfs/VfsManager.java b/modules/vfs/android/src/main/java/com/tencent/vfs/VfsManager.java index f1665e86425..4f9d409d63f 100644 --- a/modules/vfs/android/src/main/java/com/tencent/vfs/VfsManager.java +++ b/modules/vfs/android/src/main/java/com/tencent/vfs/VfsManager.java @@ -19,6 +19,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.tencent.mtt.hippy.utils.LogUtils; import com.tencent.vfs.ResourceDataHolder.RequestFrom; import java.util.HashMap; import java.util.List; @@ -26,6 +27,8 @@ public class VfsManager { + private static final String TAG = "VfsManager"; + @NonNull private final CopyOnWriteArrayList mProcessorChain; private int mId; @@ -118,7 +121,15 @@ private void traverseForward(@NonNull final ResourceDataHolder holder, final boo int index = holder.index + 1; if (index < mProcessorChain.size()) { holder.index = index; - Processor processor = mProcessorChain.get(index); + Processor processor = null; + try { + processor = mProcessorChain.get(index); + } catch (IndexOutOfBoundsException e) { + LogUtils.e(TAG, "traverseForward get index " + index + " processor exception: " + e.getMessage()); + } + if (processor == null) { + return; + } if (isSync) { boolean goBack = processor.handleRequestSync(holder); if (goBack) { @@ -158,7 +169,15 @@ private void traverseGoBack(@NonNull final ResourceDataHolder holder, final bool int index = holder.index - 1; if (index >= 0 && index < mProcessorChain.size()) { holder.index = index; - Processor processor = mProcessorChain.get(index); + Processor processor = null; + try { + processor = mProcessorChain.get(index); + } catch (IndexOutOfBoundsException e) { + LogUtils.e(TAG, "traverseGoBack get index " + index + " processor exception: " + e.getMessage()); + } + if (processor == null) { + return; + } if (isSync) { processor.handleResponseSync(holder); traverseGoBack(holder, true); From 95ee14f7b69750ac86a204427cac6328cf224747 Mon Sep 17 00:00:00 2001 From: wwwcg Date: Wed, 4 Sep 2024 17:24:34 +0800 Subject: [PATCH 22/47] fix(ios): null pointer exception of bridge setup in rare scenarios --- framework/ios/base/bridge/HippyBridge.mm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/framework/ios/base/bridge/HippyBridge.mm b/framework/ios/base/bridge/HippyBridge.mm index fe6246a9d34..8a7d72e16d6 100644 --- a/framework/ios/base/bridge/HippyBridge.mm +++ b/framework/ios/base/bridge/HippyBridge.mm @@ -442,8 +442,9 @@ - (void)setUp { _javaScriptExecutor.contextCreatedBlock = ^(){ __strong __typeof(weakSelf)strongSelf = weakSelf; - if (strongSelf) { - dispatch_semaphore_wait(strongSelf.moduleSemaphore, DISPATCH_TIME_FOREVER); + dispatch_semaphore_t moduleSemaphore = strongSelf.moduleSemaphore; + if (strongSelf.isValid && moduleSemaphore) { + dispatch_semaphore_wait(moduleSemaphore, DISPATCH_TIME_FOREVER); NSDictionary *nativeModuleConfig = [strongSelf nativeModuleConfig]; [strongSelf.javaScriptExecutor injectObjectSync:nativeModuleConfig asGlobalObjectNamed:kHippyBatchedBridgeConfigKey callback:nil]; @@ -1085,7 +1086,6 @@ - (void)invalidate { _displayLink = nil; _moduleSetup = nil; _startTime = footstone::TimePoint::SystemNow(); - self.moduleSemaphore = nil; dispatch_group_notify(group, dispatch_get_main_queue(), ^{ [jsExecutor executeBlockOnJavaScriptQueue:^{ From 99de75323145b5d85bda96ab0b23b455b464a798 Mon Sep 17 00:00:00 2001 From: wwwcg Date: Wed, 4 Sep 2024 20:50:13 +0800 Subject: [PATCH 23/47] build(voltron): resolve voltron build error --- framework/voltron/core/src/bridge/bridge_ffi_impl.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/voltron/core/src/bridge/bridge_ffi_impl.cc b/framework/voltron/core/src/bridge/bridge_ffi_impl.cc index 4bd163850ad..31a3ddd2340 100644 --- a/framework/voltron/core/src/bridge/bridge_ffi_impl.cc +++ b/framework/voltron/core/src/bridge/bridge_ffi_impl.cc @@ -281,7 +281,6 @@ EXTERN_C void DoBindDomAndRender(uint32_t dom_manager_id, int32_t engine_id, uin } scope->SetDomManager(dom_manager); - scope->SetRenderManager(render_manager); dom_manager->SetRenderManager(render_manager); render_manager->SetDomManager(dom_manager); render_manager->BindBridgeId(engine_id); @@ -330,8 +329,9 @@ EXTERN_C void DoConnectRootViewAndRuntime(int32_t engine_id, uint32_t root_id) { } #endif + auto dom_manager = scope->GetDomManager().lock(); std::shared_ptr render_manager = - std::static_pointer_cast(scope->GetRenderManager().lock()); + std::static_pointer_cast(dom_manager->GetRenderManager().lock()); float density = render_manager->GetDensity(); auto layout_node = root_node->GetLayoutNode(); From bfbb6f9003a37988c69a3252472fc933183d6407 Mon Sep 17 00:00:00 2001 From: etkmao Date: Wed, 4 Sep 2024 21:45:29 +0800 Subject: [PATCH 24/47] fix(ios): fix object_data_map crash (#4017) when jsc_vm released before jsc_ctx --- driver/js/include/driver/napi/jsc/jsc_ctx.h | 2 ++ driver/js/include/driver/vm/jsc/jsc_vm.h | 1 - driver/js/src/napi/jsc/jsc_ctx.cc | 29 +++------------------ 3 files changed, 6 insertions(+), 26 deletions(-) diff --git a/driver/js/include/driver/napi/jsc/jsc_ctx.h b/driver/js/include/driver/napi/jsc/jsc_ctx.h index d8d6e12e74f..d33210c3066 100644 --- a/driver/js/include/driver/napi/jsc/jsc_ctx.h +++ b/driver/js/include/driver/napi/jsc/jsc_ctx.h @@ -212,6 +212,8 @@ class JSCCtx : public Ctx { bool is_exception_handled_; std::unordered_map> class_definition_map_; std::weak_ptr vm_; + + std::unordered_map> constructor_data_holder_; }; inline footstone::string_view ToStrView(JSStringRef str) { diff --git a/driver/js/include/driver/vm/jsc/jsc_vm.h b/driver/js/include/driver/vm/jsc/jsc_vm.h index d235163e76a..2d2f25896dd 100644 --- a/driver/js/include/driver/vm/jsc/jsc_vm.h +++ b/driver/js/include/driver/vm/jsc/jsc_vm.h @@ -46,7 +46,6 @@ class JSCVM : public VM, public std::enable_shared_from_this { JSContextGroupRelease(vm_); } - std::unordered_map>> constructor_data_holder_; JSContextGroupRef vm_; static void SaveConstructorDataPtr(void* ptr); diff --git a/driver/js/src/napi/jsc/jsc_ctx.cc b/driver/js/src/napi/jsc/jsc_ctx.cc index dd88e02b860..d01cb4e7590 100644 --- a/driver/js/src/napi/jsc/jsc_ctx.cc +++ b/driver/js/src/napi/jsc/jsc_ctx.cc @@ -65,11 +65,7 @@ JSCCtx::JSCCtx(JSContextGroupRef group, std::weak_ptr vm): vm_(vm) { JSCCtx::~JSCCtx() { JSGlobalContextRelease(context_); - auto vm = vm_.lock(); - FOOTSTONE_CHECK(vm); - auto jsc_vm = std::static_pointer_cast(vm); - auto& holder = jsc_vm->constructor_data_holder_[this]; - for (auto& [key, item] : holder) { + for (auto& [key, item] : constructor_data_holder_) { item->prototype = nullptr; JSCVM::ClearConstructorDataPtr(item.get()); } @@ -969,30 +965,13 @@ void* JSCCtx::GetPrivateData(const std::shared_ptr& object) { } void JSCCtx::SaveConstructorData(std::unique_ptr constructor_data) { - auto vm = vm_.lock(); - FOOTSTONE_CHECK(vm); - auto jsc_vm = std::static_pointer_cast(vm); - auto& holder = jsc_vm->constructor_data_holder_; - auto it = holder.find(this); - if (it == holder.end()) { - holder[this] = std::unordered_map>{}; - } JSCVM::SaveConstructorDataPtr(constructor_data.get()); - holder[this][constructor_data->class_ref] = std::move(constructor_data); + constructor_data_holder_[constructor_data->class_ref] = std::move(constructor_data); } std::shared_ptr JSCCtx::GetClassPrototype(JSClassRef ref) { - auto vm = vm_.lock(); - FOOTSTONE_CHECK(vm); - auto jsc_vm = std::static_pointer_cast(vm); - auto& holder = jsc_vm->constructor_data_holder_; - auto it = holder.find(this); - if (it == holder.end()) { - return nullptr; - } - auto& class_map = it->second; - auto iterator = class_map.find(ref); - if (iterator == class_map.end()) { + auto iterator = constructor_data_holder_.find(ref); + if (iterator == constructor_data_holder_.end()) { return nullptr; } return iterator->second->prototype; From 09072062d3537220cbc1432df1135e42e7089cf3 Mon Sep 17 00:00:00 2001 From: wwwcg Date: Thu, 5 Sep 2024 19:41:19 +0800 Subject: [PATCH 25/47] fix(ios): resolve engine reuse issue (#4019) refactor UIManager and HippyBridge, remove some redundant UIView's category --- dom/include/dom/dom_manager.h | 8 +- .../dom/layer_optimized_render_manager.h | 1 + dom/src/dom/dom_manager.cc | 10 +- .../ios/base/bridge/HippyBridge+Private.h | 1 + framework/ios/base/bridge/HippyBridge.mm | 69 +++--- .../ios/renderer/HippyUIManager+Private.h | 13 -- renderer/native/ios/renderer/HippyUIManager.h | 9 +- .../native/ios/renderer/HippyUIManager.mm | 69 +++--- .../native/ios/renderer/NativeRenderManager.h | 111 +++------- .../ios/renderer/NativeRenderManager.mm | 196 ++++++++++-------- renderer/native/ios/renderer/UIView+Render.h | 36 ---- renderer/native/ios/renderer/UIView+Render.mm | 71 ------- .../ios/renderer/UIView+RenderManager.h | 47 ----- .../listview/HippyNextBaseListView.mm | 9 +- .../listview/HippyNextBaseListViewManager.mm | 2 +- .../NativeRenderSmartViewPagerView.mm | 7 +- .../waterfalllist/HippyWaterfallView.h | 11 +- .../waterfalllist/HippyWaterfallView.mm | 8 +- 18 files changed, 233 insertions(+), 445 deletions(-) delete mode 100644 renderer/native/ios/renderer/UIView+Render.h delete mode 100644 renderer/native/ios/renderer/UIView+Render.mm delete mode 100644 renderer/native/ios/renderer/UIView+RenderManager.h diff --git a/dom/include/dom/dom_manager.h b/dom/include/dom/dom_manager.h index 9f34f51104c..da57955f68e 100644 --- a/dom/include/dom/dom_manager.h +++ b/dom/include/dom/dom_manager.h @@ -41,6 +41,8 @@ #include "footstone/base_timer.h" #include "footstone/worker.h" +#define HIPPY_EXPERIMENT_LAYER_OPTIMIZATION + namespace hippy { inline namespace dom { @@ -140,8 +142,12 @@ class DomManager : public std::enable_shared_from_this { friend class DomNode; uint32_t id_; +#ifdef HIPPY_EXPERIMENT_LAYER_OPTIMIZATION std::shared_ptr optimized_render_manager_; - std::weak_ptr render_manager_; + std::shared_ptr render_manager_; +#else + std::shared_ptr render_manager_; +#endif std::unordered_map> timer_map_; std::shared_ptr task_runner_; std::shared_ptr worker_; diff --git a/dom/include/dom/layer_optimized_render_manager.h b/dom/include/dom/layer_optimized_render_manager.h index 73c76d3d2ba..ce683c0cc47 100644 --- a/dom/include/dom/layer_optimized_render_manager.h +++ b/dom/include/dom/layer_optimized_render_manager.h @@ -28,6 +28,7 @@ inline namespace dom { class LayerOptimizedRenderManager : public RenderManager { public: LayerOptimizedRenderManager(std::shared_ptr render_manager); + inline std::shared_ptr GetInternalNativeRenderManager() { return render_manager_; } void CreateRenderNode(std::weak_ptr root_node, std::vector>&& nodes) override; void UpdateRenderNode(std::weak_ptr root_node, std::vector>&& nodes) override; diff --git a/dom/src/dom/dom_manager.cc b/dom/src/dom/dom_manager.cc index 138b06bfdd2..74d81826d92 100644 --- a/dom/src/dom/dom_manager.cc +++ b/dom/src/dom/dom_manager.cc @@ -18,8 +18,6 @@ * limitations under the License. */ -#define EXPERIMENT_LAYER_OPTIMIZATION - #include "dom/dom_manager.h" #include @@ -54,11 +52,11 @@ using Deserializer = footstone::value::Deserializer; using HippyValueArrayType = footstone::value::HippyValue::HippyValueArrayType; void DomManager::SetRenderManager(const std::weak_ptr& render_manager) { -#ifdef EXPERIMENT_LAYER_OPTIMIZATION +#ifdef HIPPY_EXPERIMENT_LAYER_OPTIMIZATION optimized_render_manager_ = std::make_shared(render_manager.lock()); render_manager_ = optimized_render_manager_; #else - render_manager_ = render_manager; + render_manager_ = render_manager.lock(); #endif } @@ -125,7 +123,7 @@ void DomManager::DeleteDomNodes(const std::weak_ptr& weak_root_node, } void DomManager::EndBatch(const std::weak_ptr& weak_root_node) { - auto render_manager = render_manager_.lock(); + auto render_manager = render_manager_; FOOTSTONE_DCHECK(render_manager); if (!render_manager) { return; @@ -187,7 +185,7 @@ void DomManager::DoLayout(const std::weak_ptr& weak_root_node) { if (!root_node) { return; } - auto render_manager = render_manager_.lock(); + auto render_manager = render_manager_; // check render_manager, measure text dependent render_manager FOOTSTONE_DCHECK(render_manager); if (!render_manager) { diff --git a/framework/ios/base/bridge/HippyBridge+Private.h b/framework/ios/base/bridge/HippyBridge+Private.h index 7f6ef573704..684f7f93b33 100644 --- a/framework/ios/base/bridge/HippyBridge+Private.h +++ b/framework/ios/base/bridge/HippyBridge+Private.h @@ -42,6 +42,7 @@ class RenderManager; @protocol HippyBridgeInternal /// The C++ version of RenderManager instance, bridge holds +/// One NativeRenderManager holds multiple Uimanager instance. @property (nonatomic, assign) std::shared_ptr renderManager; /// URI Loader diff --git a/framework/ios/base/bridge/HippyBridge.mm b/framework/ios/base/bridge/HippyBridge.mm index 8a7d72e16d6..fcf3d33117b 100644 --- a/framework/ios/base/bridge/HippyBridge.mm +++ b/framework/ios/base/bridge/HippyBridge.mm @@ -47,7 +47,6 @@ #import "HippyLog.h" #import "HippyOCToHippyValue.h" #import "HippyUtils.h" -#import "UIView+RenderManager.h" #import "TypeConverter.h" #import "VFSUriLoader.h" #import "HippyBase64DataHandler.h" @@ -55,11 +54,14 @@ #import "HippyRootView.h" #import "UIView+Hippy.h" #import "UIView+MountEvent.h" +#import "HippyUIManager.h" +#import "HippyUIManager+Private.h" #include "dom/animation/animation_manager.h" #include "dom/dom_manager.h" #include "dom/scene.h" #include "dom/render_manager.h" +#include "dom/layer_optimized_render_manager.h" #include "driver/scope.h" #include "footstone/worker_manager.h" #include "vfs/uri_loader.h" @@ -267,19 +269,6 @@ - (void)dealloc { } } -- (void)setUpNativeRenderManager { - auto engineResource = [[HippyJSEnginesMapper defaultInstance] JSEngineResourceForKey:self.engineKey]; - auto domManager = engineResource->GetDomManager(); - //Create NativeRenderManager - auto nativeRenderManager = std::make_shared(); - nativeRenderManager->Initialize(); - //set dom manager - nativeRenderManager->SetDomManager(domManager); - nativeRenderManager->SetVFSUriLoader([self createURILoaderIfNeeded]); - nativeRenderManager->SetHippyBridge(self); - _renderManager = nativeRenderManager; -} - - (std::shared_ptr)createURILoaderIfNeeded { if (!_uriLoader) { auto uriHandler = std::make_shared(); @@ -474,7 +463,6 @@ - (void)setUp { [self addImageProviderClass:[HippyDefaultImageProvider class]]; [self setVfsUriLoader:[self createURILoaderIfNeeded]]; - [self setUpNativeRenderManager]; // Load pending js bundles [self loadPendingVendorBundleURLIfNeeded]; @@ -684,12 +672,6 @@ - (void)innerLoadInstanceForRootView:(NSNumber *)rootTag withProperties:(NSDicti HippyLogInfo(@"[HP PERF] End loading instance for HippyBridge(%p)", self); } -- (void)sendRootSizeChangedEvent:(NSNumber *)tag params:(NSDictionary *)params { - NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary:params]; - [dic setObject:tag forKey:@"rootViewId"]; - [self sendEvent:@"onSizeChanged" params:dic]; -} - - (void)setVfsUriLoader:(std::weak_ptr)uriLoader { [_javaScriptExecutor setUriLoader:uriLoader]; #ifdef ENABLE_INSPECTOR @@ -1252,8 +1234,6 @@ - (void)setSnapShotData:(NSData *)data { #pragma mark - - -//FIXME: 调整优化 - (void)setRootView:(UIView *)rootView { auto engineResource = [[HippyJSEnginesMapper defaultInstance] JSEngineResourceForKey:self.engineKey]; auto domManager = engineResource->GetDomManager(); @@ -1269,21 +1249,38 @@ - (void)setRootView:(UIView *)rootView { _rootNode->SetRootSize(rootView.frame.size.width, rootView.frame.size.height); _rootNode->SetRootOrigin(rootView.frame.origin.x, rootView.frame.origin.y); - //set rendermanager for dommanager - if (domManager->GetRenderManager().lock() != _renderManager) { - domManager->SetRenderManager(_renderManager); + // Create NativeRenderManager if needed + auto renderManager = domManager->GetRenderManager().lock(); + std::shared_ptr nativeRenderManager; + if (!renderManager) { + // Register RenderManager to DomManager + nativeRenderManager = std::make_shared(self.moduleName.UTF8String); + domManager->SetRenderManager(nativeRenderManager); + } else { +#ifdef HIPPY_EXPERIMENT_LAYER_OPTIMIZATION + auto opRenderManager = std::static_pointer_cast(renderManager); + nativeRenderManager = std::static_pointer_cast(opRenderManager->GetInternalNativeRenderManager()); +#else + nativeRenderManager = std::static_pointer_cast(renderManager); +#endif /* HIPPY_EXPERIMENT_LAYER_OPTIMIZATION */ } + _renderManager = nativeRenderManager; + + // Create UIManager if needed and register it to NativeRenderManager + // Note that one NativeRenderManager may have multiple UIManager, + // and one UIManager may have multiple rootViews, + // But one HippyBridge can only have one UIManager. + HippyUIManager *uiManager = self.uiManager; + if (!uiManager) { + uiManager = [[HippyUIManager alloc] init]; + [uiManager setDomManager:domManager]; + [uiManager setBridge:self]; + self.uiManager = uiManager; + } + //bind rootview and root node - _renderManager->RegisterRootView(rootView, _rootNode); + _renderManager->RegisterRootView(rootView, _rootNode, uiManager); - __weak HippyBridge *weakBridge = self; - auto cb = [weakBridge](int32_t tag, NSDictionary *params){ - HippyBridge *strongBridge = weakBridge; - if (strongBridge) { - [strongBridge sendRootSizeChangedEvent:@(tag) params:params]; - } - }; - _renderManager->SetRootViewSizeChangedEvent(cb); //setup necessary params for bridge [self setupDomManager:domManager rootNode:_rootNode]; } @@ -1309,8 +1306,6 @@ - (void)resetRootSize:(CGSize)size { domManager->PostTask(hippy::dom::Scene(std::move(ops))); } - - @end void HippyBridgeFatal(NSError *error, HippyBridge *bridge) { diff --git a/renderer/native/ios/renderer/HippyUIManager+Private.h b/renderer/native/ios/renderer/HippyUIManager+Private.h index 83286ef3aff..a58630579da 100644 --- a/renderer/native/ios/renderer/HippyUIManager+Private.h +++ b/renderer/native/ios/renderer/HippyUIManager+Private.h @@ -28,10 +28,8 @@ #include #include -class VFSUriLoader; namespace hippy { inline namespace dom { -class RenderManager; class DomManager; class DomArgument; class RootNode; @@ -53,22 +51,11 @@ class HippyValue; /// DomManager instance @property (nonatomic, readonly) std::weak_ptr domManager; -/// VFSUriLoader instance -@property (nonatomic, assign) std::weak_ptr vfsUriLoader; - @end @interface HippyUIManager (Private) -/// Set hippy::RenderManager -/// - Parameter renderManager: hippy::RenderManager -- (void)registRenderManager:(std::weak_ptr)renderManager; - -/// Get hippy::RenderManager -- (std::weak_ptr)renderManager; - - - (void)registerRootView:(UIView *)rootView asRootNode:(std::weak_ptr)rootNode; - (void)unregisterRootViewFromTag:(NSNumber *)rootTag; diff --git a/renderer/native/ios/renderer/HippyUIManager.h b/renderer/native/ios/renderer/HippyUIManager.h index 5d9c3b22755..d10ce61ca39 100644 --- a/renderer/native/ios/renderer/HippyUIManager.h +++ b/renderer/native/ios/renderer/HippyUIManager.h @@ -66,8 +66,15 @@ HIPPY_EXTERN NSString *const HippyUIManagerDidEndBatchNotification; /// The HippyUIManager responsible for updating the view hierarchy. @interface HippyUIManager : NSObject +/// HippyBridge instance @property (nonatomic, weak) HippyBridge *bridge; + +/// View Registry of all nodes @property (nonatomic, readonly) HippyComponentMap *viewRegistry; + +/// Specify whether UI hierarchy will be created instantly. +/// When setting YES, UI hierarchy will not be created automatically, +/// default is NO. @property (nonatomic, assign) BOOL uiCreationLazilyEnabled; @@ -142,7 +149,7 @@ HIPPY_EXTERN NSString *const HippyUIManagerDidEndBatchNotification; @interface HippyBridge (HippyUIManager) /// The current HippyUIManager instance -@property (nonatomic, readonly) HippyUIManager *uiManager; +@property (nonatomic, strong) HippyUIManager *uiManager; /// A custom touch handler for gesture special processing /// You can use it when you need to modify Hippy's default gesture handling logic diff --git a/renderer/native/ios/renderer/HippyUIManager.mm b/renderer/native/ios/renderer/HippyUIManager.mm index a91f31beb13..8643e9f0568 100644 --- a/renderer/native/ios/renderer/HippyUIManager.mm +++ b/renderer/native/ios/renderer/HippyUIManager.mm @@ -41,8 +41,6 @@ #import "RenderVsyncManager.h" #import "UIView+DomEvent.h" #import "UIView+Hippy.h" -#import "UIView+Render.h" -#import "UIView+RenderManager.h" #import "HippyBridgeModule.h" #import "HippyModulesSetup.h" #import "NativeRenderManager.h" @@ -50,6 +48,7 @@ #import "HippyModuleData.h" #import "HippyModuleMethod.h" #import "HippyBridge+Private.h" +#import "HippyJSExecutor.h" #import "dom/root_node.h" #import "objc/runtime.h" #import @@ -185,15 +184,12 @@ @interface HippyUIManager() { // Listeners such as ScrollView/ListView etc. witch will listen to start layout event // The implementation here needs to be improved to provide a registration mechanism. NSHashTable> *_componentTransactionListeners; - - std::weak_ptr _renderManager; std::mutex _renderQueueLock; NSMutableDictionary *_viewManagers; NSArray *_extraComponents; NSMutableArray> *_imageProviders; - std::function _rootViewSizeChangedCb; } @@ -209,7 +205,6 @@ @interface HippyUIManager() { @implementation HippyUIManager @synthesize domManager = _domManager; -@synthesize vfsUriLoader = _vfsUriLoader; #pragma mark Life cycle @@ -251,14 +246,6 @@ - (void)dealloc { #pragma mark Setter & Getter -- (void)registRenderManager:(std::weak_ptr)renderManager { - _renderManager = renderManager; -} - -- (std::weak_ptr)renderManager { - return _renderManager; -} - - (void)setDomManager:(std::weak_ptr)domManager { _domManager = domManager; } @@ -335,7 +322,6 @@ - (void)registerRootView:(UIView *)rootView asRootNode:(std::weak_ptr) [rootView addObserver:self forKeyPath:@"frame" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:NULL]; - rootView.renderManager = [self renderManager]; CGRect frame = rootView.frame; // Register shadow view @@ -392,19 +378,22 @@ - (void)observeValueForKeyPath:(NSString *)keyPath @"width": @(CGRectGetWidth(curFrame)), @"height": @(CGRectGetHeight(curFrame)), @"rootViewId": rootTag }; + static const char *hippyOnSizeChangedKey = "onSizeChanged"; auto value = std::make_shared([params toHippyValue]); - auto event = std::make_shared("onSizeChanged", rootNode, NO, NO, value); + auto event = std::make_shared(hippyOnSizeChangedKey, rootNode, NO, NO, value); __weak HippyUIManager *weakSelf = self; std::function func = [weakSelf, rootNode, event, rootTag](){ rootNode->HandleEvent(event); HippyUIManager *strongSelf = weakSelf; if (strongSelf) { - [strongSelf domEventDidHandle:"onSizeChanged" forNode:[rootTag intValue] onRoot:[rootTag intValue]]; + [strongSelf domEventDidHandle:hippyOnSizeChangedKey forNode:[rootTag intValue] onRoot:[rootTag intValue]]; } }; domManager->PostTask(hippy::Scene({func})); - if (_rootViewSizeChangedCb) { - _rootViewSizeChangedCb([rootTag intValue], params); + + HippyBridge *bridge = self.bridge; + if (bridge) { + [bridge sendEvent:@(hippyOnSizeChangedKey) params:params]; } } } @@ -527,7 +516,6 @@ - (UIView *)createViewFromShadowView:(HippyShadowView *)shadowView { view.viewName = viewName; view.rootTag = rootTag; view.hippyShadowView = shadowView; - view.renderManager = [self renderManager]; [componentData setProps:props forView:view]; // Must be done before bgColor to prevent wrong default } } @@ -1169,24 +1157,26 @@ - (void)addEventName:(const std::string &)name }]; } else if (name == kVSyncKey) { std::string name_ = name; - auto weakDomManager = self.domManager; + __weak __typeof(self)weakSelf = self; [self domNodeForComponentTag:node_id onRootNode:rootNode resultNode:^(std::shared_ptr node) { if (node) { //for kVSyncKey event, node is rootnode - NSString *vsyncKey = [NSString stringWithFormat:@"%p-%d", self, node_id]; + __strong __typeof(weakSelf)strongSelf = weakSelf; + NSString *vsyncKey = [NSString stringWithFormat:@"%p-%d", strongSelf, node_id]; auto event = std::make_shared(name_, node); std::weak_ptr weakNode = node; [[RenderVsyncManager sharedInstance] registerVsyncObserver:^{ - auto domManager = weakDomManager.lock(); - if (domManager) { - std::function func = [weakNode, event](){ - auto strongNode = weakNode.lock(); - if (strongNode) { - strongNode->HandleEvent(event); - } - }; - domManager->PostTask(hippy::Scene({func})); + __strong __typeof(weakSelf)strongSelf = weakSelf; + HippyBridge *bridge = strongSelf.bridge; + if (!bridge) { + return; } + [bridge.javaScriptExecutor executeBlockOnJavaScriptQueue:^{ + auto strongNode = weakNode.lock(); + if (strongNode) { + strongNode->HandleEvent(event); + } + }]; } forKey:vsyncKey]; } }]; @@ -1488,12 +1478,8 @@ - (NSDictionary *)mergeProps:(NSDictionary *)newProps oldProps:(NSDictionary *)o return tmpProps; } -- (void)setRootViewSizeChangedEvent:(std::function)cb { - _rootViewSizeChangedCb = cb; -} - - (void)domEventDidHandle:(const std::string &)eventName forNode:(int32_t)tag onRoot:(int32_t)rootTag { - + // no op } #pragma mark Debug Methods @@ -1522,12 +1508,11 @@ - (void)domEventDidHandle:(const std::string &)eventName forNode:(int32_t)tag on @implementation HippyBridge (HippyUIManager) - (HippyUIManager *)uiManager { - auto renderManager = [self renderManager]; - if (renderManager) { - auto nativeRenderManager = std::static_pointer_cast(renderManager); - return nativeRenderManager->GetHippyUIManager(); - } - return nil; + return objc_getAssociatedObject(self, @selector(uiManager)); +} + +- (void)setUiManager:(HippyUIManager *)uiManager { + objc_setAssociatedObject(self, @selector(uiManager), uiManager, OBJC_ASSOCIATION_RETAIN); } - (id)customTouchHandler { diff --git a/renderer/native/ios/renderer/NativeRenderManager.h b/renderer/native/ios/renderer/NativeRenderManager.h index e1a1011905b..2551df1057c 100644 --- a/renderer/native/ios/renderer/NativeRenderManager.h +++ b/renderer/native/ios/renderer/NativeRenderManager.h @@ -20,37 +20,30 @@ * limitations under the License. */ -#ifndef NativeRenderManager_h -#define NativeRenderManager_h +#ifndef _HIPPY_NATIVERENDERMANAGER_H_ +#define _HIPPY_NATIVERENDERMANAGER_H_ #include #include - +#include #include "dom/render_manager.h" @class UIView, HippyUIManager; -class VFSUriLoader; namespace hippy { inline namespace dom { class RootNode; } } -@protocol HippyImageProviderProtocol; - /** * NativeRenderManager is used to manager view creation, update and delete for Native UI */ -class NativeRenderManager : public hippy::RenderManager ,public std::enable_shared_from_this { - +class NativeRenderManager : public hippy::RenderManager, public std::enable_shared_from_this { public: - NativeRenderManager(); - NativeRenderManager(HippyUIManager *uiManager): hippy::RenderManager("NativeRenderManager"), renderImpl_(uiManager){} - + + explicit NativeRenderManager(const std::string& name); ~NativeRenderManager(); - - void Initialize(); /** * create views from dom nodes @@ -58,21 +51,21 @@ class NativeRenderManager : public hippy::RenderManager ,public std::enable_shar */ void CreateRenderNode(std::weak_ptr root_node, std::vector>&& nodes) override; - + /** * update views' properties from dom nodes * @param nodes A set of nodes for updating views' properties */ void UpdateRenderNode(std::weak_ptr root_node, std::vector>&& nodes) override; - + /** * delete views from dom nodes * @param nodes A set of nodes for deleting views */ void DeleteRenderNode(std::weak_ptr root_node, std::vector>&& nodes) override; - + /** * update layout for view * @@ -80,7 +73,7 @@ class NativeRenderManager : public hippy::RenderManager ,public std::enable_shar */ void UpdateLayout(std::weak_ptr root_node, const std::vector>& nodes) override; - + /** * move views from container to another container * @@ -95,12 +88,12 @@ class NativeRenderManager : public hippy::RenderManager ,public std::enable_shar int32_t index) override; void MoveRenderNode(std::weak_ptr root_node, std::vector>&& nodes) override; - + /** * Invoked after batched operations completed */ void EndBatch(std::weak_ptr root_node) override; - + /** * Invoked before nodes do layout */ @@ -118,7 +111,7 @@ class NativeRenderManager : public hippy::RenderManager ,public std::enable_shar * @param name event name */ void AddEventListener(std::weak_ptr root_node, std::weak_ptr dom_node, const std::string& name) override; - + /** * unregister event for specific view * @@ -131,7 +124,7 @@ class NativeRenderManager : public hippy::RenderManager ,public std::enable_shar * unregister vsync event */ void RemoveVSyncEventListener(std::weak_ptr root_node); - + /** * invoke function of view * @@ -142,84 +135,30 @@ class NativeRenderManager : public hippy::RenderManager ,public std::enable_shar * @discussion Caller can get callback block from id by DomNode::GetCallback function */ void CallFunction(std::weak_ptr root_node, - std::weak_ptr dom_node, const std::string &name, + std::weak_ptr dom_node, + const std::string &name, const DomArgument& param, uint32_t cb) override; - - /** - * Register custom ui component - * - * @param extraComponents a map of custom ui components - */ - void RegisterExtraComponent(NSArray *extraComponents); - + /** - * Regitster a root view + * Regitster a root view and register UIManager instance to RenderManager * * @param view a specitified view as root view * @param root_node root node for root view + * @param uiManager HippyUIManager instance */ - void RegisterRootView(UIView *view, std::weak_ptr root_node); - + void RegisterRootView(UIView *view, std::weak_ptr root_node, HippyUIManager *uiManager); + /** * Unregister a root view * * @param id root view id */ void UnregisterRootView(uint32_t id); - - /** - * Get all registered root views - * - * @return a copy array of root views - */ - NSArray *rootViews(); - - /** - * set dom manager for render manager - * - * @param dom_manager weak pointer of dom manager - */ - void SetDomManager(std::weak_ptr dom_manager); - - /** - * Specify whether ui hierarchy should be created instantly - * - * @param enabled true means ui will not be created until it is required - * @discussion when true, ui hierarchy will not be created automatically, default is false - */ - void SetUICreationLazilyEnabled(bool enabled); - - /** - * Set vfs uri loader of CPP version - * - *@param loader vfs url loader instance - */ - void SetVFSUriLoader(std::shared_ptr loader); - - /** - * Set HippyBridge pointer to renderManager - * - *@param bridge HippyBridge instance - */ - void SetHippyBridge(HippyBridge *bridge); - - /** - * Set root view size changed event callback - * - *@param cb callback - */ - void SetRootViewSizeChangedEvent(std::function cb); - - /** - * Get HippyUIManager variable - * - * @return A HippyUIManager instance - */ - HippyUIManager *GetHippyUIManager(); - + private: - HippyUIManager *renderImpl_; + + std::unordered_map _uiManagerMap; }; -#endif /* NativeRenderManager_h */ +#endif /* _HIPPY_NATIVERENDERMANAGER_H_ */ diff --git a/renderer/native/ios/renderer/NativeRenderManager.mm b/renderer/native/ios/renderer/NativeRenderManager.mm index 17d3e5eb5c5..8465d2678ed 100644 --- a/renderer/native/ios/renderer/NativeRenderManager.mm +++ b/renderer/native/ios/renderer/NativeRenderManager.mm @@ -26,9 +26,9 @@ #import "HippyShadowText.h" #import "RenderVsyncManager.h" #import "HippyAssert.h" - #include "dom/dom_manager.h" #include "dom/layout_node.h" +#include "dom/root_node.h" using HippyValue = footstone::value::HippyValue; using RenderManager = hippy::RenderManager; @@ -39,42 +39,55 @@ using CallFunctionCallback = hippy::CallFunctionCallback; using RootNode = hippy::RootNode; -NativeRenderManager::NativeRenderManager(): hippy::RenderManager("NativeRenderManager") { -} -void NativeRenderManager::Initialize() { - renderImpl_ = [[HippyUIManager alloc] init]; - [renderImpl_ registRenderManager:weak_from_this()]; -} +NativeRenderManager::NativeRenderManager(const std::string& name): hippy::RenderManager(name) {} void NativeRenderManager::CreateRenderNode(std::weak_ptr root_node, std::vector> &&nodes) { @autoreleasepool { - HippyAssert(renderImpl_, @"renderImpl_ is null, did you forget to call Initialize()?"); - [renderImpl_ createRenderNodes:std::move(nodes) onRootNode:root_node]; + auto rootNode = root_node.lock(); + if (rootNode) { + HippyUIManager *uiManager = _uiManagerMap[rootNode->GetId()]; + HippyAssertParam(uiManager); + [uiManager createRenderNodes:std::move(nodes) onRootNode:root_node]; + } } } void NativeRenderManager::UpdateRenderNode(std::weak_ptr root_node, std::vector>&& nodes) { @autoreleasepool { - HippyAssert(renderImpl_, @"renderImpl_ is null, did you forget to call Initialize()?"); - [renderImpl_ updateRenderNodes:std::move(nodes) onRootNode:root_node]; + auto rootNode = root_node.lock(); + if (rootNode) { + HippyUIManager *uiManager = _uiManagerMap[rootNode->GetId()]; + HippyAssertParam(uiManager); + [uiManager updateRenderNodes:std::move(nodes) onRootNode:root_node]; + } + } } void NativeRenderManager::DeleteRenderNode(std::weak_ptr root_node, std::vector>&& nodes) { @autoreleasepool { - HippyAssert(renderImpl_, @"renderImpl_ is null, did you forget to call Initialize()?"); - [renderImpl_ deleteRenderNodesIds:std::move(nodes) onRootNode:root_node]; + auto rootNode = root_node.lock(); + if (rootNode) { + HippyUIManager *uiManager = _uiManagerMap[rootNode->GetId()]; + HippyAssertParam(uiManager); + [uiManager deleteRenderNodesIds:std::move(nodes) onRootNode:root_node]; + } } } void NativeRenderManager::UpdateLayout(std::weak_ptr root_node, const std::vector>& nodes) { @autoreleasepool { - HippyAssert(renderImpl_, @"renderImpl_ is null, did you forget to call Initialize()?"); + auto rootNode = root_node.lock(); + if (!rootNode) { + return; + } + HippyUIManager *uiManager = _uiManagerMap[rootNode->GetId()]; + HippyAssertParam(uiManager); using DomNodeUpdateInfoTuple = std::tuple; std::vector nodes_infos; nodes_infos.reserve(nodes.size()); @@ -84,7 +97,7 @@ DomNodeUpdateInfoTuple nodeUpdateInfo = std::make_tuple(tag, layoutResult); nodes_infos.push_back(nodeUpdateInfo); } - [renderImpl_ updateNodesLayout:nodes_infos onRootNode:root_node]; + [uiManager updateNodesLayout:nodes_infos onRootNode:root_node]; } } @@ -94,19 +107,29 @@ int32_t to_pid, int32_t index) { @autoreleasepool { - HippyAssert(renderImpl_, @"renderImpl_ is null, did you forget to call Initialize()?"); - [renderImpl_ renderMoveViews:std::move(moved_ids) - fromContainer:from_pid - toContainer:to_pid - index:index - onRootNode:root_node]; + auto rootNode = root_node.lock(); + if (!rootNode) { + return; + } + HippyUIManager *uiManager = _uiManagerMap[rootNode->GetId()]; + HippyAssertParam(uiManager); + [uiManager renderMoveViews:std::move(moved_ids) + fromContainer:from_pid + toContainer:to_pid + index:index + onRootNode:root_node]; } } void NativeRenderManager::MoveRenderNode(std::weak_ptr root_node, std::vector>&& nodes) { @autoreleasepool { - HippyAssert(renderImpl_, @"renderImpl_ is null, did you forget to call Initialize()?"); + auto rootNode = root_node.lock(); + if (!rootNode) { + return; + } + HippyUIManager *uiManager = _uiManagerMap[rootNode->GetId()]; + HippyAssertParam(uiManager); // Check whether all nodes have the same pid uint32_t firstPid = nodes[0]->GetPid(); bool allSamePid = std::all_of(nodes.begin(), nodes.end(), @@ -116,7 +139,7 @@ if (allSamePid) { // If all nodes have the same pid, call directly - [renderImpl_ renderMoveNodes:std::move(nodes) onRootNode:root_node]; + [uiManager renderMoveNodes:std::move(nodes) onRootNode:root_node]; } else { // If not, group them by pid and then call for each group std::map>> pidNodeMap; @@ -124,7 +147,7 @@ pidNodeMap[node->GetPid()].push_back(node); } for (auto& pair : pidNodeMap) { - [renderImpl_ renderMoveNodes:std::move(pair.second) onRootNode:root_node]; + [uiManager renderMoveNodes:std::move(pair.second) onRootNode:root_node]; } } } @@ -133,8 +156,13 @@ void NativeRenderManager::EndBatch(std::weak_ptr root_node) { @autoreleasepool { TDF_PERF_LOG("NativeRenderManager::EndBatch Begin"); - HippyAssert(renderImpl_, @"renderImpl_ is null, did you forget to call Initialize()?"); - [renderImpl_ batchOnRootNode:root_node]; + auto rootNode = root_node.lock(); + if (!rootNode) { + return; + } + HippyUIManager *uiManager = _uiManagerMap[rootNode->GetId()]; + HippyAssertParam(uiManager); + [uiManager batchOnRootNode:root_node]; TDF_PERF_LOG("NativeRenderManager::EndBatch End"); } @@ -150,11 +178,16 @@ std::weak_ptr dom_node, const std::string& name) { @autoreleasepool { - HippyAssert(renderImpl_, @"renderImpl_ is null, did you forget to call Initialize()?"); + auto rootNode = root_node.lock(); + if (!rootNode) { + return; + } + HippyUIManager *uiManager = _uiManagerMap[rootNode->GetId()]; + HippyAssertParam(uiManager); auto node = dom_node.lock(); if (node) { int32_t tag = node->GetId(); - [renderImpl_ addEventName:name forDomNodeId:tag onRootNode:root_node]; + [uiManager addEventName:name forDomNodeId:tag onRootNode:root_node]; } } }; @@ -163,19 +196,29 @@ std::weak_ptr dom_node, const std::string &name) { @autoreleasepool { - HippyAssert(renderImpl_, @"renderImpl_ is null, did you forget to call Initialize()?"); + auto rootNode = root_node.lock(); + if (!rootNode) { + return; + } + HippyUIManager *uiManager = _uiManagerMap[rootNode->GetId()]; + HippyAssertParam(uiManager); auto node = dom_node.lock(); if (node) { int32_t node_id = node->GetId(); - [renderImpl_ removeEventName:name forDomNodeId:node_id onRootNode:root_node]; + [uiManager removeEventName:name forDomNodeId:node_id onRootNode:root_node]; } } } void NativeRenderManager::RemoveVSyncEventListener(std::weak_ptr root_node) { @autoreleasepool { - HippyAssert(renderImpl_, @"renderImpl_ is null, did you forget to call Initialize()?"); - [renderImpl_ removeVSyncEventOnRootNode:root_node]; + auto rootNode = root_node.lock(); + if (!rootNode) { + return; + } + HippyUIManager *uiManager = _uiManagerMap[rootNode->GetId()]; + HippyAssertParam(uiManager); + [uiManager removeVSyncEventOnRootNode:root_node]; } } @@ -185,81 +228,54 @@ const DomArgument& param, uint32_t cb) { @autoreleasepool { - HippyAssert(renderImpl_, @"renderImpl_ is null, did you forget to call Initialize()?"); + auto rootNode = root_node.lock(); + if (!rootNode) { + return; + } + HippyUIManager *uiManager = _uiManagerMap[rootNode->GetId()]; + HippyAssertParam(uiManager); std::shared_ptr node = dom_node.lock(); if (node) { HippyValue hippy_value; param.ToObject(hippy_value); - [renderImpl_ dispatchFunction:name viewName:node->GetViewName() - viewTag:node->GetId() onRootNode:root_node params:hippy_value - callback:node->GetCallback(name, cb)]; + [uiManager dispatchFunction:name + viewName:node->GetViewName() + viewTag:node->GetId() + onRootNode:root_node + params:hippy_value + callback:node->GetCallback(name, cb)]; } EndBatch(root_node); } } -void NativeRenderManager::RegisterExtraComponent(NSArray *extraComponents) { - @autoreleasepool { - HippyAssert(renderImpl_, @"renderImpl_ is null, did you forget to call Initialize()?"); - [renderImpl_ registerExtraComponent:extraComponents]; - } -} - -void NativeRenderManager::RegisterRootView(UIView *view, std::weak_ptr root_node) { +void NativeRenderManager::RegisterRootView(UIView *view, + std::weak_ptr root_node, + HippyUIManager *uiManager) { @autoreleasepool { - HippyAssert(renderImpl_, @"renderImpl_ is null, did you forget to call Initialize()?"); - [renderImpl_ registerRootView:view asRootNode:root_node]; - } -} - -void NativeRenderManager::UnregisterRootView(uint32_t id) { - @autoreleasepool { - HippyAssert(renderImpl_, @"renderImpl_ is null, did you forget to call Initialize()?"); - [renderImpl_ unregisterRootViewFromTag:@(id)]; - } -} - -NSArray *NativeRenderManager::rootViews() { - @autoreleasepool { - HippyAssert(renderImpl_, @"renderImpl_ is null, did you forget to call Initialize()?"); - return [renderImpl_ rootViews]; - } -} - -void NativeRenderManager::SetDomManager(std::weak_ptr dom_manager) { - @autoreleasepool { - HippyAssert(renderImpl_, @"renderImpl_ is null, did you forget to call Initialize()?"); - [renderImpl_ setDomManager:dom_manager]; + auto rootNode = root_node.lock(); + if (!rootNode) { + return; + } + HippyAssertParam(uiManager); + _uiManagerMap[rootNode->GetId()] = uiManager; + [uiManager registerRootView:view asRootNode:root_node]; } } -void NativeRenderManager::SetUICreationLazilyEnabled(bool enabled) { - HippyAssert(renderImpl_, @"renderImpl_ is null, did you forget to call Initialize()?"); - renderImpl_.uiCreationLazilyEnabled = enabled; -} - -void NativeRenderManager::SetVFSUriLoader(std::shared_ptr loader) { +void NativeRenderManager::UnregisterRootView(uint32_t rootId) { @autoreleasepool { - HippyAssert(renderImpl_, @"renderImpl_ is null, did you forget to call Initialize()?"); - renderImpl_.vfsUriLoader = loader; + HippyUIManager *uiManager = _uiManagerMap[rootId]; + HippyAssertParam(uiManager); + [uiManager unregisterRootViewFromTag:@(rootId)]; + _uiManagerMap.erase(rootId); } } -void NativeRenderManager::SetHippyBridge(HippyBridge *bridge) { - HippyAssert(renderImpl_, @"renderImpl_ is null, did you forget to call Initialize()?"); - renderImpl_.bridge = bridge; -} - -void NativeRenderManager::SetRootViewSizeChangedEvent(std::function cb) { - [renderImpl_ setRootViewSizeChangedEvent:cb]; -} - -HippyUIManager *NativeRenderManager::GetHippyUIManager() { - return renderImpl_; -} - NativeRenderManager::~NativeRenderManager() { - [renderImpl_ invalidate]; - renderImpl_ = nil; + for (auto &pair : _uiManagerMap) { + [pair.second invalidate]; + } + _uiManagerMap.clear(); } diff --git a/renderer/native/ios/renderer/UIView+Render.h b/renderer/native/ios/renderer/UIView+Render.h deleted file mode 100644 index 3c8972b98ca..00000000000 --- a/renderer/native/ios/renderer/UIView+Render.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 - -NS_ASSUME_NONNULL_BEGIN - -@class HippyUIManager; - -@interface UIView (Render) - -/// Convenient method to get HippyUIManager instance -- (HippyUIManager *)uiManager; - -@end - -NS_ASSUME_NONNULL_END diff --git a/renderer/native/ios/renderer/UIView+Render.mm b/renderer/native/ios/renderer/UIView+Render.mm deleted file mode 100644 index bc1cfcf579d..00000000000 --- a/renderer/native/ios/renderer/UIView+Render.mm +++ /dev/null @@ -1,71 +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 "UIView+Render.h" -#import "HippyUIManager.h" -#import "UIView+RenderManager.h" -#import "NativeRenderManager.h" -#import "dom/render_manager.h" -#include - - -@implementation UIView (Render) - -- (HippyUIManager *)uiManager { - auto renderManager = [self renderManager].lock(); - if (renderManager) { - auto nativeRenderManager = std::static_pointer_cast(renderManager); - return nativeRenderManager->GetHippyUIManager(); - } - return nil; -} - -@end - - -#pragma mark - - -@interface RenderManagerWrapper : NSObject - -/// holds weak_ptr of hippy::RenderManager -@property (nonatomic, assign) std::weak_ptr renderManager; - -@end - -@implementation RenderManagerWrapper - -@end - -@implementation UIView (HippyRenderManager) - -- (void)setRenderManager:(std::weak_ptr)renderManager { - RenderManagerWrapper *wrapper = [[RenderManagerWrapper alloc] init]; - wrapper.renderManager = renderManager; - objc_setAssociatedObject(self, @selector(renderManager), wrapper, OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -- (std::weak_ptr)renderManager { - RenderManagerWrapper *wrapper = objc_getAssociatedObject(self, _cmd); - return wrapper.renderManager; -} - -@end diff --git a/renderer/native/ios/renderer/UIView+RenderManager.h b/renderer/native/ios/renderer/UIView+RenderManager.h deleted file mode 100644 index ed4cb516c6c..00000000000 --- a/renderer/native/ios/renderer/UIView+RenderManager.h +++ /dev/null @@ -1,47 +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. - */ - -#ifndef UIView_RenderManager_h -#define UIView_RenderManager_h - -#import -#include - -NS_ASSUME_NONNULL_BEGIN - -namespace hippy { -inline namespace dom { -class RenderManager; -}; -}; - - -@interface UIView (HippyRenderManager) - -/// Get the hippy::RenderManager instance -@property(nonatomic, assign) std::weak_ptr renderManager; - -@end - -NS_ASSUME_NONNULL_END - -#endif /* UIView_RenderManager_h */ diff --git a/renderer/native/ios/renderer/component/listview/HippyNextBaseListView.mm b/renderer/native/ios/renderer/component/listview/HippyNextBaseListView.mm index 40daabd1b53..21c2c78b867 100644 --- a/renderer/native/ios/renderer/component/listview/HippyNextBaseListView.mm +++ b/renderer/native/ios/renderer/component/listview/HippyNextBaseListView.mm @@ -31,7 +31,6 @@ #import "HippyShadowView.h" #import "UIView+DirectionalLayout.h" #import "UIView+Hippy.h" -#import "UIView+Render.h" #import "HippyShadowListView.h" static NSString *const kCellIdentifier = @"HippyListCellIdentifier"; @@ -49,8 +48,8 @@ @implementation HippyNextBaseListView #pragma mark - Life Cycle -- (instancetype)initWithFrame:(CGRect)frame { - if (self = [super initWithFrame:frame]) { +- (instancetype)initWithBridge:(HippyBridge *)bridge { + if (self = [super initWithBridge:bridge]) { _isInitialListReady = NO; self.preloadItemNumber = 1; } @@ -221,7 +220,7 @@ - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView forIndexPath:indexPath]; HippyShadowView *headerRenderObject = [self.dataSource headerForSection:section]; if (headerRenderObject && [headerRenderObject isKindOfClass:[HippyShadowView class]]) { - UIView *headerView = [self.uiManager createViewForShadowListItem:headerRenderObject]; + UIView *headerView = [self.bridge.uiManager createViewForShadowListItem:headerRenderObject]; CGRect frame = headerView.frame; frame.origin = CGPointZero; headerView.frame = frame; @@ -273,7 +272,7 @@ - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cell cellView = cachedVisibleCellView; HippyLogTrace(@"🟢 use cached visible cellView at %@ for %@", indexPath, shadowView.hippyTag); } else { - cellView = [self.uiManager createViewForShadowListItem:shadowView]; + cellView = [self.bridge.uiManager createViewForShadowListItem:shadowView]; [_cachedWeakCellViews setObject:cellView forKey:shadowView.hippyTag]; HippyLogTrace(@"🟡 create cellView at %@ for %@", indexPath, shadowView.hippyTag); } diff --git a/renderer/native/ios/renderer/component/listview/HippyNextBaseListViewManager.mm b/renderer/native/ios/renderer/component/listview/HippyNextBaseListViewManager.mm index 48d57088841..71ad81c91b2 100644 --- a/renderer/native/ios/renderer/component/listview/HippyNextBaseListViewManager.mm +++ b/renderer/native/ios/renderer/component/listview/HippyNextBaseListViewManager.mm @@ -48,7 +48,7 @@ @implementation HippyNextBaseListViewManager HIPPY_EXPORT_VIEW_PROPERTY(horizontal, BOOL) - (UIView *)view { - return [[HippyNextBaseListView alloc] init]; + return [[HippyNextBaseListView alloc] initWithBridge:self.bridge]; } - (HippyShadowView *)shadowView { diff --git a/renderer/native/ios/renderer/component/smartViewPager/NativeRenderSmartViewPagerView.mm b/renderer/native/ios/renderer/component/smartViewPager/NativeRenderSmartViewPagerView.mm index a10ca363f35..6c9fa2613d4 100644 --- a/renderer/native/ios/renderer/component/smartViewPager/NativeRenderSmartViewPagerView.mm +++ b/renderer/native/ios/renderer/component/smartViewPager/NativeRenderSmartViewPagerView.mm @@ -29,7 +29,6 @@ #import "NativeRenderSmartViewPagerView.h" #import "HippyScrollProtocol.h" #import "UIView+MountEvent.h" -#import "UIView+Render.h" #import "UIView+Hippy.h" #include @@ -59,8 +58,8 @@ - (void)setPreviousMargin:(CGFloat)previousMargin nextMargin:(CGFloat)nextMargin @implementation NativeRenderSmartViewPagerView #pragma mark Life Cycle -- (instancetype)initWithFrame:(CGRect)frame { - if (self = [super initWithFrame:frame]) { +- (instancetype)initWithBridge:(HippyBridge *)bridge { + if (self = [super initWithBridge:bridge]) { _isInitialListReady = NO; _dataSource = [[HippyNextBaseListViewDataSource alloc] initWithDataSource:nil itemViewName:[self compoentItemName] @@ -357,7 +356,7 @@ - (void)collectionView:(UICollectionView *)collectionView NSIndexPath *adjustIndexPath = [NSIndexPath indexPathForRow:cellIndex inSection:indexPath.section]; HippyWaterfallViewCell *hpCell = (HippyWaterfallViewCell *)cell; HippyShadowView *renderObject = [_dataSource cellForIndexPath:adjustIndexPath]; - UIView *cellView = [self.uiManager createViewForShadowListItem:renderObject]; + UIView *cellView = [self.bridge.uiManager createViewForShadowListItem:renderObject]; hpCell.cellView = cellView; cellView.parent = self; } diff --git a/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.h b/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.h index 7af72dc98d6..c25df712d16 100644 --- a/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.h +++ b/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.h @@ -21,7 +21,7 @@ */ #import - +#import "HippyBridge.h" #import "HippyCollectionViewWaterfallLayout.h" #import "HippyComponent.h" #import "HippyScrollableProtocol.h" @@ -56,6 +56,9 @@ typedef NS_ENUM(NSInteger, NativeRenderScrollState) { BOOL _allowNextScrollNoMatterWhat; } +/// Weak ref of HippyBridge +@property (nonatomic, weak, readonly) HippyBridge *bridge; + /** * Content inset for HippyWaterfallView */ @@ -116,6 +119,12 @@ typedef NS_ENUM(NSInteger, NativeRenderScrollState) { @property (nonatomic, copy) HippyDirectEventBlock onRefresh; @property (nonatomic, copy) HippyDirectEventBlock onExposureReport; +/// Init method +/// - Parameter bridge: HippyBridge instance +- (instancetype)initWithBridge:(HippyBridge *)bridge NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE; +- (instancetype)initWithCoder:(NSCoder *)coder NS_UNAVAILABLE; + /** * Initial collection view */ diff --git a/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.mm b/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.mm index 6545dff75a0..41e6e53a94e 100644 --- a/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.mm +++ b/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.mm @@ -29,7 +29,6 @@ #import "HippyWaterfallViewDataSource.h" #import "HippyShadowView.h" #import "HippyUIManager.h" -#import "UIView+Render.h" #import "HippyWaterfallViewCell.h" #import "HippyRootView.h" #import "HippyShadowListView.h" @@ -62,8 +61,9 @@ @implementation HippyWaterfallView { @synthesize contentSize; -- (instancetype)initWithFrame:(CGRect)frame { - if (self = [super initWithFrame:frame]) { +- (instancetype)initWithBridge:(id)bridge { + if (self = [super initWithFrame:CGRectZero]) { + _bridge = bridge; self.backgroundColor = [UIColor clearColor]; _scrollListeners = [NSHashTable weakObjectsHashTable]; _scrollEventThrottle = 100.f; @@ -266,7 +266,7 @@ - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cell if (cachedCellView) { cellView = cachedCellView; } else { - cellView = [self.uiManager createViewForShadowListItem:shadowView]; + cellView = [self.bridge.uiManager createViewForShadowListItem:shadowView]; [_cachedWeakCellViews setObject:cellView forKey:shadowView.hippyTag]; } From 592c010b24fa2b540ef1fb6800438aaa4d56c172 Mon Sep 17 00:00:00 2001 From: etkmao Date: Tue, 10 Sep 2024 15:54:04 +0800 Subject: [PATCH 26/47] refactor(ios): avoid mutex crash in special app environment (#4020) * fix(ios): check static invalid mutex crash * fix(ios): move static maps to heap for checking static overflow crash --- dom/include/dom/layout_node.h | 1 + dom/src/dom/root_node.cc | 1 + dom/src/dom/taitank_layout_node.cc | 145 +++++++++++--------- dom/src/dom/yoga_layout_node.cc | 1 + driver/js/include/driver/napi/jsc/jsc_ctx.h | 22 +++ driver/js/include/driver/vm/jsc/jsc_vm.h | 7 - driver/js/src/napi/jsc/jsc_ctx.cc | 12 +- driver/js/src/vm/jsc/jsc_vm.cc | 18 --- 8 files changed, 113 insertions(+), 94 deletions(-) diff --git a/dom/include/dom/layout_node.h b/dom/include/dom/layout_node.h index 8346c54540c..01a0ec3f684 100644 --- a/dom/include/dom/layout_node.h +++ b/dom/include/dom/layout_node.h @@ -124,6 +124,7 @@ class LayoutNode { const std::vector& style_delete) = 0; }; +void InitLayoutConsts(); std::shared_ptr CreateLayoutNode(); } // namespace dom diff --git a/dom/src/dom/root_node.cc b/dom/src/dom/root_node.cc index 6e737cd9f01..eb94863ea70 100644 --- a/dom/src/dom/root_node.cc +++ b/dom/src/dom/root_node.cc @@ -101,6 +101,7 @@ bool DomNodeStyleDiffer::Calculate(const std::shared_ptr& } RootNode::RootNode(uint32_t id) : DomNode(id, 0, 0, "", "", nullptr, nullptr, {}) { + InitLayoutConsts(); SetRenderInfo({id, 0, 0}); animation_manager_ = std::make_shared(); interceptors_.push_back(animation_manager_); diff --git a/dom/src/dom/taitank_layout_node.cc b/dom/src/dom/taitank_layout_node.cc index 0a3a9824809..cd9f1766fcd 100644 --- a/dom/src/dom/taitank_layout_node.cc +++ b/dom/src/dom/taitank_layout_node.cc @@ -30,75 +30,82 @@ namespace hippy { inline namespace dom { -const std::map kOverflowMap = {{"visible", OverflowType::OVERFLOW_VISIBLE}, - {"hidden", OverflowType::OVERFLOW_HIDDEN}, - {"scroll", OverflowType::OVERFLOW_SCROLL}}; - -const std::map kFlexDirectionMap = { - {"row", FlexDirection::FLEX_DIRECTION_ROW}, - {"row-reverse", FlexDirection::FLEX_DIRECTION_ROW_REVERSE}, - {"column", FlexDirection::FLEX_DIRECTION_COLUMN}, - {"column-reverse", FlexDirection::FLEX_DIRECTION_COLUNM_REVERSE}}; - -const std::map kWrapModeMap = {{"nowrap", FlexWrapMode::FLEX_NO_WRAP}, - {"wrap", FlexWrapMode::FLEX_WRAP}, - {"wrap-reverse", FlexWrapMode::FLEX_WRAP_REVERSE}}; - -const std::map kJustifyMap = {{"flex-start", FlexAlign::FLEX_ALIGN_START}, - {"center", FlexAlign::FLEX_ALIGN_CENTER}, - {"flex-end", FlexAlign::FLEX_ALIGN_END}, - {"space-between", FlexAlign::FLEX_ALIGN_SPACE_BETWEEN}, - {"space-around", FlexAlign::FLEX_ALIGN_SPACE_AROUND}, - {"space-evenly", FlexAlign::FLEX_ALIGN_SPACE_EVENLY}}; - -const std::map kAlignMap = {{"auto", FlexAlign::FLEX_ALIGN_AUTO}, - {"flex-start", FlexAlign::FLEX_ALIGN_START}, - {"center", FlexAlign::FLEX_ALIGN_CENTER}, - {"flex-end", FlexAlign::FLEX_ALIGN_END}, - {"stretch", FlexAlign::FLEX_ALIGN_STRETCH}, - {"baseline", FlexAlign::FLEX_ALIGN_BASE_LINE}, - {"space-between", FlexAlign::FLEX_ALIGN_SPACE_BETWEEN}, - {"space-around", FlexAlign::FLEX_ALIGN_SPACE_AROUND}}; - -const std::map kMarginMap = {{kMargin, CSSDirection::CSS_ALL}, - {kMarginVertical, CSSDirection::CSS_VERTICAL}, - {kMarginHorizontal, CSSDirection::CSS_HORIZONTAL}, - {kMarginLeft, CSSDirection::CSS_LEFT}, - {kMarginRight, CSSDirection::CSS_RIGHT}, - {kMarginTop, CSSDirection::CSS_TOP}, - {kMarginBottom, CSSDirection::CSS_BOTTOM}}; - -const std::map kPaddingMap = {{kPadding, CSSDirection::CSS_ALL}, - {kPaddingVertical, CSSDirection::CSS_VERTICAL}, - {kPaddingHorizontal, CSSDirection::CSS_HORIZONTAL}, - {kPaddingLeft, CSSDirection::CSS_LEFT}, - {kPaddingRight, CSSDirection::CSS_RIGHT}, - {kPaddingTop, CSSDirection::CSS_TOP}, - {kPaddingBottom, CSSDirection::CSS_BOTTOM}}; - -const std::map kPositionMap = {{kLeft, CSSDirection::CSS_LEFT}, - {kRight, CSSDirection::CSS_RIGHT}, - {kTop, CSSDirection::CSS_TOP}, - {kBottom, CSSDirection::CSS_BOTTOM}}; - -const std::map kBorderMap = {{kBorderWidth, CSSDirection::CSS_ALL}, - {kBorderLeftWidth, CSSDirection::CSS_LEFT}, - {kBorderTopWidth, CSSDirection::CSS_TOP}, - {kBorderRightWidth, CSSDirection::CSS_RIGHT}, - {kBorderBottomWidth, CSSDirection::CSS_BOTTOM}}; - -const std::map kPositionTypeMap = {{"relative", PositionType::POSITION_TYPE_RELATIVE}, - {"absolute", PositionType::POSITION_TYPE_ABSOLUTE}}; - -const std::map kDisplayTypeMap = {{"none", DisplayType::DISPLAY_TYPE_NONE}}; - -const std::map kDirectionMap = { - {"inherit", DIRECTION_INHERIT}, {"ltr", DIRECTION_LTR}, {"rtl", DIRECTION_RTL}}; +class TaitankLayoutConsts { +public: + const std::map kOverflowMap = {{"visible", OverflowType::OVERFLOW_VISIBLE}, + {"hidden", OverflowType::OVERFLOW_HIDDEN}, + {"scroll", OverflowType::OVERFLOW_SCROLL}}; + + const std::map kFlexDirectionMap = { + {"row", FlexDirection::FLEX_DIRECTION_ROW}, + {"row-reverse", FlexDirection::FLEX_DIRECTION_ROW_REVERSE}, + {"column", FlexDirection::FLEX_DIRECTION_COLUMN}, + {"column-reverse", FlexDirection::FLEX_DIRECTION_COLUNM_REVERSE}}; + + const std::map kWrapModeMap = {{"nowrap", FlexWrapMode::FLEX_NO_WRAP}, + {"wrap", FlexWrapMode::FLEX_WRAP}, + {"wrap-reverse", FlexWrapMode::FLEX_WRAP_REVERSE}}; + + const std::map kJustifyMap = {{"flex-start", FlexAlign::FLEX_ALIGN_START}, + {"center", FlexAlign::FLEX_ALIGN_CENTER}, + {"flex-end", FlexAlign::FLEX_ALIGN_END}, + {"space-between", FlexAlign::FLEX_ALIGN_SPACE_BETWEEN}, + {"space-around", FlexAlign::FLEX_ALIGN_SPACE_AROUND}, + {"space-evenly", FlexAlign::FLEX_ALIGN_SPACE_EVENLY}}; + + const std::map kAlignMap = {{"auto", FlexAlign::FLEX_ALIGN_AUTO}, + {"flex-start", FlexAlign::FLEX_ALIGN_START}, + {"center", FlexAlign::FLEX_ALIGN_CENTER}, + {"flex-end", FlexAlign::FLEX_ALIGN_END}, + {"stretch", FlexAlign::FLEX_ALIGN_STRETCH}, + {"baseline", FlexAlign::FLEX_ALIGN_BASE_LINE}, + {"space-between", FlexAlign::FLEX_ALIGN_SPACE_BETWEEN}, + {"space-around", FlexAlign::FLEX_ALIGN_SPACE_AROUND}}; + + const std::map kMarginMap = {{kMargin, CSSDirection::CSS_ALL}, + {kMarginVertical, CSSDirection::CSS_VERTICAL}, + {kMarginHorizontal, CSSDirection::CSS_HORIZONTAL}, + {kMarginLeft, CSSDirection::CSS_LEFT}, + {kMarginRight, CSSDirection::CSS_RIGHT}, + {kMarginTop, CSSDirection::CSS_TOP}, + {kMarginBottom, CSSDirection::CSS_BOTTOM}}; + + const std::map kPaddingMap = {{kPadding, CSSDirection::CSS_ALL}, + {kPaddingVertical, CSSDirection::CSS_VERTICAL}, + {kPaddingHorizontal, CSSDirection::CSS_HORIZONTAL}, + {kPaddingLeft, CSSDirection::CSS_LEFT}, + {kPaddingRight, CSSDirection::CSS_RIGHT}, + {kPaddingTop, CSSDirection::CSS_TOP}, + {kPaddingBottom, CSSDirection::CSS_BOTTOM}}; + + const std::map kPositionMap = {{kLeft, CSSDirection::CSS_LEFT}, + {kRight, CSSDirection::CSS_RIGHT}, + {kTop, CSSDirection::CSS_TOP}, + {kBottom, CSSDirection::CSS_BOTTOM}}; + + const std::map kBorderMap = {{kBorderWidth, CSSDirection::CSS_ALL}, + {kBorderLeftWidth, CSSDirection::CSS_LEFT}, + {kBorderTopWidth, CSSDirection::CSS_TOP}, + {kBorderRightWidth, CSSDirection::CSS_RIGHT}, + {kBorderBottomWidth, CSSDirection::CSS_BOTTOM}}; + + const std::map kPositionTypeMap = {{"relative", PositionType::POSITION_TYPE_RELATIVE}, + {"absolute", PositionType::POSITION_TYPE_ABSOLUTE}}; + + const std::map kDisplayTypeMap = {{"none", DisplayType::DISPLAY_TYPE_NONE}}; + + const std::map kDirectionMap = { + {"inherit", DIRECTION_INHERIT}, {"ltr", DIRECTION_LTR}, {"rtl", DIRECTION_RTL}}; +}; + +static std::shared_ptr global_layout_consts = nullptr; #define TAITANK_GET_STYLE_DECL(NAME, TYPE, DEFAULT) \ static TYPE GetStyle##NAME(const std::string& key) { \ - auto iter = k##NAME##Map.find(key); \ - if (iter != k##NAME##Map.end()) return iter->second; \ + if (global_layout_consts == nullptr) return DEFAULT; \ + auto &map = global_layout_consts->k##NAME##Map; \ + auto iter = map.find(key); \ + if (iter != map.end()) return iter->second; \ return DEFAULT; \ } @@ -814,6 +821,12 @@ void TaitankLayoutNode::Deallocate() { engine_node_ = nullptr; } +void InitLayoutConsts() { + if (global_layout_consts == nullptr) { + global_layout_consts = std::make_shared(); + } +} + std::shared_ptr CreateLayoutNode() { return std::make_shared(); } } // namespace dom diff --git a/dom/src/dom/yoga_layout_node.cc b/dom/src/dom/yoga_layout_node.cc index 303d721c702..7b681694fa5 100644 --- a/dom/src/dom/yoga_layout_node.cc +++ b/dom/src/dom/yoga_layout_node.cc @@ -762,6 +762,7 @@ void YogaLayoutNode::Deallocate() { YGConfigFree(yoga_config_); } +void InitLayoutConsts() {} std::shared_ptr CreateLayoutNode() { return std::make_shared(); } } // namespace dom diff --git a/driver/js/include/driver/napi/jsc/jsc_ctx.h b/driver/js/include/driver/napi/jsc/jsc_ctx.h index d33210c3066..075837285d5 100644 --- a/driver/js/include/driver/napi/jsc/jsc_ctx.h +++ b/driver/js/include/driver/napi/jsc/jsc_ctx.h @@ -28,6 +28,7 @@ #include #include +#include #include "footstone/logging.h" #include "footstone/string_view.h" @@ -63,6 +64,27 @@ struct ConstructorData { } }; +class ConstructorDataManager { +public: + void SaveConstructorDataPtr(void* ptr) { + std::lock_guard lock(mutex_); + constructor_data_ptr_set_.insert(ptr); + } + + void ClearConstructorDataPtr(void* ptr) { + std::lock_guard lock(mutex_); + constructor_data_ptr_set_.erase(ptr); + } + + bool IsValidConstructorDataPtr(void* ptr) { + std::lock_guard lock(mutex_); + return constructor_data_ptr_set_.find(ptr) != constructor_data_ptr_set_.end(); + } +private: + std::set constructor_data_ptr_set_; + std::mutex mutex_; +}; + class JSCCtx : public Ctx { public: using string_view = footstone::string_view; diff --git a/driver/js/include/driver/vm/jsc/jsc_vm.h b/driver/js/include/driver/vm/jsc/jsc_vm.h index 2d2f25896dd..3bd0b02ae7c 100644 --- a/driver/js/include/driver/vm/jsc/jsc_vm.h +++ b/driver/js/include/driver/vm/jsc/jsc_vm.h @@ -47,13 +47,6 @@ class JSCVM : public VM, public std::enable_shared_from_this { } JSContextGroupRef vm_; - - static void SaveConstructorDataPtr(void* ptr); - static void ClearConstructorDataPtr(void* ptr); - static bool IsValidConstructorDataPtr(void* ptr); - - static std::set constructor_data_ptr_set_; - static std::mutex mutex_; virtual std::shared_ptr ParseJson(const std::shared_ptr& ctx, const string_view& json) override; virtual std::shared_ptr CreateContext() override; diff --git a/driver/js/src/napi/jsc/jsc_ctx.cc b/driver/js/src/napi/jsc/jsc_ctx.cc index d01cb4e7590..51152479073 100644 --- a/driver/js/src/napi/jsc/jsc_ctx.cc +++ b/driver/js/src/napi/jsc/jsc_ctx.cc @@ -49,11 +49,13 @@ constexpr char16_t kSetStr[] = u"set"; static std::once_flag global_class_flag; static JSClassRef global_class; +static std::shared_ptr global_constructor_data_mgr = nullptr; JSCCtx::JSCCtx(JSContextGroupRef group, std::weak_ptr vm): vm_(vm) { std::call_once(global_class_flag, []() { JSClassDefinition global = kJSClassDefinitionEmpty; global_class = JSClassCreate(&global); + global_constructor_data_mgr = std::make_shared(); }); context_ = JSGlobalContextCreateInGroup(group, global_class); @@ -67,7 +69,9 @@ JSCCtx::~JSCCtx() { JSGlobalContextRelease(context_); for (auto& [key, item] : constructor_data_holder_) { item->prototype = nullptr; - JSCVM::ClearConstructorDataPtr(item.get()); + if (global_constructor_data_mgr) { + global_constructor_data_mgr->ClearConstructorDataPtr(item.get()); + } } } @@ -260,7 +264,7 @@ std::shared_ptr JSCCtx::DefineClass(const string_view& name, if (!private_data) { return; } - if (!JSCVM::IsValidConstructorDataPtr(private_data)) { + if (!global_constructor_data_mgr || !global_constructor_data_mgr->IsValidConstructorDataPtr(private_data)) { return; } auto constructor_data = reinterpret_cast(private_data); @@ -965,7 +969,9 @@ void* JSCCtx::GetPrivateData(const std::shared_ptr& object) { } void JSCCtx::SaveConstructorData(std::unique_ptr constructor_data) { - JSCVM::SaveConstructorDataPtr(constructor_data.get()); + if (global_constructor_data_mgr) { + global_constructor_data_mgr->SaveConstructorDataPtr(constructor_data.get()); + } constructor_data_holder_[constructor_data->class_ref] = std::move(constructor_data); } diff --git a/driver/js/src/vm/jsc/jsc_vm.cc b/driver/js/src/vm/jsc/jsc_vm.cc index eceeb8d1a97..6e92f5c3d40 100644 --- a/driver/js/src/vm/jsc/jsc_vm.cc +++ b/driver/js/src/vm/jsc/jsc_vm.cc @@ -37,9 +37,6 @@ namespace hippy { inline namespace driver { inline namespace vm { -std::set JSCVM::constructor_data_ptr_set_; -std::mutex JSCVM::mutex_; - std::shared_ptr JSCVM::ParseJson(const std::shared_ptr& ctx, const string_view& json) { if (footstone::StringViewUtils::IsEmpty(json)) { return nullptr; @@ -93,21 +90,6 @@ JSStringRef JSCVM::CreateJSCString(const string_view& str_view) { return ret; } -void JSCVM::SaveConstructorDataPtr(void* ptr) { - std::lock_guard lock(mutex_); - constructor_data_ptr_set_.insert(ptr); -} - -void JSCVM::ClearConstructorDataPtr(void* ptr) { - std::lock_guard lock(mutex_); - constructor_data_ptr_set_.erase(ptr); -} - -bool JSCVM::IsValidConstructorDataPtr(void* ptr) { - std::lock_guard lock(mutex_); - return constructor_data_ptr_set_.find(ptr) != constructor_data_ptr_set_.end(); -} - } } } From c9ddbc1e235173916f75dc958f1f148bbb5b4f54 Mon Sep 17 00:00:00 2001 From: wwwcg Date: Tue, 10 Sep 2024 16:44:05 +0800 Subject: [PATCH 27/47] fix(ios): resolve jsc_try_catch invalid issue (#4021) --- .../js/include/driver/napi/jsc/jsc_try_catch.h | 1 - driver/js/src/napi/jsc/jsc_try_catch.cc | 16 +++++++++------- framework/ios/base/bridge/HippyBridge.mm | 10 +++++++--- modules/ios/base/HippyAssert.m | 1 + 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/driver/js/include/driver/napi/jsc/jsc_try_catch.h b/driver/js/include/driver/napi/jsc/jsc_try_catch.h index b4ece21d608..77c270596c2 100644 --- a/driver/js/include/driver/napi/jsc/jsc_try_catch.h +++ b/driver/js/include/driver/napi/jsc/jsc_try_catch.h @@ -46,7 +46,6 @@ class JSCTryCatch : public TryCatch { virtual footstone::string_view GetExceptionMessage(); private: - std::shared_ptr exception_; bool is_verbose_; bool is_rethrow_; }; diff --git a/driver/js/src/napi/jsc/jsc_try_catch.cc b/driver/js/src/napi/jsc/jsc_try_catch.cc index f0b8465d1de..a85052b2dc8 100644 --- a/driver/js/src/napi/jsc/jsc_try_catch.cc +++ b/driver/js/src/napi/jsc/jsc_try_catch.cc @@ -21,7 +21,6 @@ */ #include "driver/napi/jsc/jsc_try_catch.h" - #include "driver/napi/jsc/jsc_ctx.h" #include "driver/napi/jsc/jsc_ctx_value.h" @@ -45,7 +44,6 @@ JSCTryCatch::~JSCTryCatch() { if (HasCaught()) { if (is_rethrow_ || is_verbose_) { std::shared_ptr ctx = std::static_pointer_cast(ctx_); - ctx->SetException(exception_); if (is_rethrow_) { ctx->SetExceptionHandled(false); } else { @@ -61,21 +59,24 @@ void JSCTryCatch::ReThrow() { bool JSCTryCatch::HasCaught() { if (enable_) { - return !!exception_; + std::shared_ptr ctx = std::static_pointer_cast(ctx_); + return !!ctx->GetException(); } return false; } bool JSCTryCatch::CanContinue() { if (enable_) { - return !exception_; + std::shared_ptr ctx = std::static_pointer_cast(ctx_); + return !ctx->GetException(); } return true; } bool JSCTryCatch::HasTerminated() { if (enable_) { - return !!exception_; + std::shared_ptr ctx = std::static_pointer_cast(ctx_); + return !!ctx->GetException(); } return false; } @@ -89,13 +90,14 @@ void JSCTryCatch::SetVerbose(bool is_verbose) { } std::shared_ptr JSCTryCatch::Exception() { - return exception_; + std::shared_ptr ctx = std::static_pointer_cast(ctx_); + return ctx->GetException(); } string_view JSCTryCatch::GetExceptionMessage() { if (enable_) { std::shared_ptr ctx = std::static_pointer_cast(ctx_); - return ctx->GetExceptionMessage(exception_); + return ctx->GetExceptionMessage(ctx->GetException()); } return ""; } diff --git a/framework/ios/base/bridge/HippyBridge.mm b/framework/ios/base/bridge/HippyBridge.mm index fcf3d33117b..a2d738277ba 100644 --- a/framework/ios/base/bridge/HippyBridge.mm +++ b/framework/ios/base/bridge/HippyBridge.mm @@ -710,15 +710,19 @@ - (void)executeJSCode:(NSData *)script return; } HippyAssert(self.javaScriptExecutor, @"js executor must not be null"); - __weak HippyBridge *weakSelf = self; + __weak __typeof(self)weakSelf = self; [self.javaScriptExecutor executeApplicationScript:script sourceURL:sourceURL onComplete:^(id result ,NSError *error) { - HippyBridge *strongSelf = weakSelf; + __strong __typeof(weakSelf)strongSelf = weakSelf; if (!strongSelf || ![strongSelf isValid]) { completion(result, error); return; } if (error) { - [strongSelf stopLoadingWithError:error scriptSourceURL:sourceURL]; + HippyLogError(@"ExecuteApplicationScript Error! %@", error.description); + HippyExecuteOnMainQueue(^{ + __strong __typeof(weakSelf)strongSelf = weakSelf; + [strongSelf stopLoadingWithError:error scriptSourceURL:sourceURL]; + }); } completion(result, error); }]; diff --git a/modules/ios/base/HippyAssert.m b/modules/ios/base/HippyAssert.m index b9dbc775df0..39b9139bcf5 100644 --- a/modules/ios/base/HippyAssert.m +++ b/modules/ios/base/HippyAssert.m @@ -96,6 +96,7 @@ void HippyFatal(NSError *error) { } [NSException raise:name format:@"%@", message]; } @catch (NSException *e) { + // no op } #endif //#ifdef DEBUG } From e5fcf2f82c3cf2ce9ea78f38cee74bbcf8e323e2 Mon Sep 17 00:00:00 2001 From: wwwcg Date: Tue, 10 Sep 2024 18:26:51 +0800 Subject: [PATCH 28/47] refactor(ios): add a uiManager getter for UIView (#4022) For compatibility, some third-party components want to get UIManager or HippyBridge directly through UIView, although there is a slight performance penalty doing this. --- renderer/native/ios/renderer/HippyUIManager.h | 3 ++ .../native/ios/renderer/HippyUIManager.mm | 19 ++++++++-- ....mm => HippyNextBaseListItemViewManager.m} | 0 .../listview/HippyNextBaseListView.mm | 9 +++-- ...e.mm => HippyNextBaseListViewDataSource.m} | 0 ...ager.mm => HippyNextBaseListViewManager.m} | 2 +- .../NativeRenderSmartViewPagerView.mm | 8 ++-- .../renderer/component/view/UIView+Render.h | 37 ++++++++++++++++++ .../renderer/component/view/UIView+Render.m | 38 +++++++++++++++++++ .../waterfalllist/HippyWaterfallView.h | 9 ----- .../waterfalllist/HippyWaterfallView.mm | 8 ++-- tests/ios/HippyUIViewCategoryTest.m | 22 ++++++++++- 12 files changed, 127 insertions(+), 28 deletions(-) rename renderer/native/ios/renderer/component/listview/{HippyNextBaseListItemViewManager.mm => HippyNextBaseListItemViewManager.m} (100%) rename renderer/native/ios/renderer/component/listview/{HippyNextBaseListViewDataSource.mm => HippyNextBaseListViewDataSource.m} (100%) rename renderer/native/ios/renderer/component/listview/{HippyNextBaseListViewManager.mm => HippyNextBaseListViewManager.m} (98%) create mode 100644 renderer/native/ios/renderer/component/view/UIView+Render.h create mode 100644 renderer/native/ios/renderer/component/view/UIView+Render.m diff --git a/renderer/native/ios/renderer/HippyUIManager.h b/renderer/native/ios/renderer/HippyUIManager.h index d10ce61ca39..63d88dd132e 100644 --- a/renderer/native/ios/renderer/HippyUIManager.h +++ b/renderer/native/ios/renderer/HippyUIManager.h @@ -33,6 +33,7 @@ @class HippyComponentMap; @protocol HippyImageProviderProtocol; +NS_ASSUME_NONNULL_BEGIN /** * Posted whenever a new root view is registered with HippyUIManager. The userInfo property @@ -156,3 +157,5 @@ HIPPY_EXTERN NSString *const HippyUIManagerDidEndBatchNotification; @property (nonatomic, strong, readonly) id customTouchHandler; @end + +NS_ASSUME_NONNULL_END diff --git a/renderer/native/ios/renderer/HippyUIManager.mm b/renderer/native/ios/renderer/HippyUIManager.mm index 8643e9f0568..2419d3928db 100644 --- a/renderer/native/ios/renderer/HippyUIManager.mm +++ b/renderer/native/ios/renderer/HippyUIManager.mm @@ -162,6 +162,18 @@ static void NativeRenderTraverseViewNodes(id view, void (^block) } } + +@interface UIView (HippyUIManagerPrivate) + +/// Bind UIView with HippyUIManager +/// This is a convenient method for UIView to get HippyUIManager instance. +/// - Parameter uiManager: HippyUIManager instance +- (void)setUiManager:(HippyUIManager *)uiManager; + +@end + +#pragma mark - + #define AssertMainQueue() NSAssert(HippyIsMainQueue(), @"This function must be called on the main thread") NSString *const HippyUIManagerDidRegisterRootViewNotification = @"HippyUIManagerDidRegisterRootViewNotification"; @@ -318,8 +330,8 @@ - (void)registerRootView:(UIView *)rootView asRootNode:(std::weak_ptr) // Register view [_viewRegistry addRootComponent:rootView rootNode:rootNode forTag:hippyTag]; - - [rootView addObserver:self forKeyPath:@"frame" + rootView.uiManager = self; + [rootView addObserver:self forKeyPath:@"frame" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:NULL]; CGRect frame = rootView.frame; @@ -516,6 +528,7 @@ - (UIView *)createViewFromShadowView:(HippyShadowView *)shadowView { view.viewName = viewName; view.rootTag = rootTag; view.hippyShadowView = shadowView; + view.uiManager = self; [componentData setProps:props forView:view]; // Must be done before bgColor to prevent wrong default } } @@ -1523,7 +1536,5 @@ - (void)setCustomTouchHandler:(id)customTouchHa objc_setAssociatedObject(self, @selector(customTouchHandler), customTouchHandler, OBJC_ASSOCIATION_RETAIN); } - @end - diff --git a/renderer/native/ios/renderer/component/listview/HippyNextBaseListItemViewManager.mm b/renderer/native/ios/renderer/component/listview/HippyNextBaseListItemViewManager.m similarity index 100% rename from renderer/native/ios/renderer/component/listview/HippyNextBaseListItemViewManager.mm rename to renderer/native/ios/renderer/component/listview/HippyNextBaseListItemViewManager.m diff --git a/renderer/native/ios/renderer/component/listview/HippyNextBaseListView.mm b/renderer/native/ios/renderer/component/listview/HippyNextBaseListView.mm index 21c2c78b867..40daabd1b53 100644 --- a/renderer/native/ios/renderer/component/listview/HippyNextBaseListView.mm +++ b/renderer/native/ios/renderer/component/listview/HippyNextBaseListView.mm @@ -31,6 +31,7 @@ #import "HippyShadowView.h" #import "UIView+DirectionalLayout.h" #import "UIView+Hippy.h" +#import "UIView+Render.h" #import "HippyShadowListView.h" static NSString *const kCellIdentifier = @"HippyListCellIdentifier"; @@ -48,8 +49,8 @@ @implementation HippyNextBaseListView #pragma mark - Life Cycle -- (instancetype)initWithBridge:(HippyBridge *)bridge { - if (self = [super initWithBridge:bridge]) { +- (instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { _isInitialListReady = NO; self.preloadItemNumber = 1; } @@ -220,7 +221,7 @@ - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView forIndexPath:indexPath]; HippyShadowView *headerRenderObject = [self.dataSource headerForSection:section]; if (headerRenderObject && [headerRenderObject isKindOfClass:[HippyShadowView class]]) { - UIView *headerView = [self.bridge.uiManager createViewForShadowListItem:headerRenderObject]; + UIView *headerView = [self.uiManager createViewForShadowListItem:headerRenderObject]; CGRect frame = headerView.frame; frame.origin = CGPointZero; headerView.frame = frame; @@ -272,7 +273,7 @@ - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cell cellView = cachedVisibleCellView; HippyLogTrace(@"🟢 use cached visible cellView at %@ for %@", indexPath, shadowView.hippyTag); } else { - cellView = [self.bridge.uiManager createViewForShadowListItem:shadowView]; + cellView = [self.uiManager createViewForShadowListItem:shadowView]; [_cachedWeakCellViews setObject:cellView forKey:shadowView.hippyTag]; HippyLogTrace(@"🟡 create cellView at %@ for %@", indexPath, shadowView.hippyTag); } diff --git a/renderer/native/ios/renderer/component/listview/HippyNextBaseListViewDataSource.mm b/renderer/native/ios/renderer/component/listview/HippyNextBaseListViewDataSource.m similarity index 100% rename from renderer/native/ios/renderer/component/listview/HippyNextBaseListViewDataSource.mm rename to renderer/native/ios/renderer/component/listview/HippyNextBaseListViewDataSource.m diff --git a/renderer/native/ios/renderer/component/listview/HippyNextBaseListViewManager.mm b/renderer/native/ios/renderer/component/listview/HippyNextBaseListViewManager.m similarity index 98% rename from renderer/native/ios/renderer/component/listview/HippyNextBaseListViewManager.mm rename to renderer/native/ios/renderer/component/listview/HippyNextBaseListViewManager.m index 71ad81c91b2..48d57088841 100644 --- a/renderer/native/ios/renderer/component/listview/HippyNextBaseListViewManager.mm +++ b/renderer/native/ios/renderer/component/listview/HippyNextBaseListViewManager.m @@ -48,7 +48,7 @@ @implementation HippyNextBaseListViewManager HIPPY_EXPORT_VIEW_PROPERTY(horizontal, BOOL) - (UIView *)view { - return [[HippyNextBaseListView alloc] initWithBridge:self.bridge]; + return [[HippyNextBaseListView alloc] init]; } - (HippyShadowView *)shadowView { diff --git a/renderer/native/ios/renderer/component/smartViewPager/NativeRenderSmartViewPagerView.mm b/renderer/native/ios/renderer/component/smartViewPager/NativeRenderSmartViewPagerView.mm index 6c9fa2613d4..b8c779dc11d 100644 --- a/renderer/native/ios/renderer/component/smartViewPager/NativeRenderSmartViewPagerView.mm +++ b/renderer/native/ios/renderer/component/smartViewPager/NativeRenderSmartViewPagerView.mm @@ -30,7 +30,7 @@ #import "HippyScrollProtocol.h" #import "UIView+MountEvent.h" #import "UIView+Hippy.h" - +#import "UIView+Render.h" #include static NSInteger kInfiniteLoopBegin = 2; @@ -58,8 +58,8 @@ - (void)setPreviousMargin:(CGFloat)previousMargin nextMargin:(CGFloat)nextMargin @implementation NativeRenderSmartViewPagerView #pragma mark Life Cycle -- (instancetype)initWithBridge:(HippyBridge *)bridge { - if (self = [super initWithBridge:bridge]) { +- (instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { _isInitialListReady = NO; _dataSource = [[HippyNextBaseListViewDataSource alloc] initWithDataSource:nil itemViewName:[self compoentItemName] @@ -356,7 +356,7 @@ - (void)collectionView:(UICollectionView *)collectionView NSIndexPath *adjustIndexPath = [NSIndexPath indexPathForRow:cellIndex inSection:indexPath.section]; HippyWaterfallViewCell *hpCell = (HippyWaterfallViewCell *)cell; HippyShadowView *renderObject = [_dataSource cellForIndexPath:adjustIndexPath]; - UIView *cellView = [self.bridge.uiManager createViewForShadowListItem:renderObject]; + UIView *cellView = [self.uiManager createViewForShadowListItem:renderObject]; hpCell.cellView = cellView; cellView.parent = self; } diff --git a/renderer/native/ios/renderer/component/view/UIView+Render.h b/renderer/native/ios/renderer/component/view/UIView+Render.h new file mode 100644 index 00000000000..d7d508ba879 --- /dev/null +++ b/renderer/native/ios/renderer/component/view/UIView+Render.h @@ -0,0 +1,37 @@ +/*! + * 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 + +NS_ASSUME_NONNULL_BEGIN + +@class HippyUIManager; +/// UIView's UIManager category +@interface UIView (HippyUIManager) + +/// Convenient method to get HippyUIManager instance, +/// UIView's uiManager property is set when created. +- (nullable HippyUIManager *)uiManager; + +@end + +NS_ASSUME_NONNULL_END diff --git a/renderer/native/ios/renderer/component/view/UIView+Render.m b/renderer/native/ios/renderer/component/view/UIView+Render.m new file mode 100644 index 00000000000..d751e6cd7f6 --- /dev/null +++ b/renderer/native/ios/renderer/component/view/UIView+Render.m @@ -0,0 +1,38 @@ +/*! + * 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 "UIView+Render.h" +#import + +@implementation UIView (HippyUIManager) + +- (HippyUIManager *)uiManager { + NSValue *weakValue = objc_getAssociatedObject(self, @selector(uiManager)); + return [weakValue nonretainedObjectValue]; +} + +- (void)setUiManager:(HippyUIManager *)uiManager { + NSValue *weakValue = [NSValue valueWithNonretainedObject:uiManager]; + objc_setAssociatedObject(self, @selector(uiManager), weakValue, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +@end diff --git a/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.h b/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.h index c25df712d16..35025b65395 100644 --- a/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.h +++ b/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.h @@ -56,9 +56,6 @@ typedef NS_ENUM(NSInteger, NativeRenderScrollState) { BOOL _allowNextScrollNoMatterWhat; } -/// Weak ref of HippyBridge -@property (nonatomic, weak, readonly) HippyBridge *bridge; - /** * Content inset for HippyWaterfallView */ @@ -119,12 +116,6 @@ typedef NS_ENUM(NSInteger, NativeRenderScrollState) { @property (nonatomic, copy) HippyDirectEventBlock onRefresh; @property (nonatomic, copy) HippyDirectEventBlock onExposureReport; -/// Init method -/// - Parameter bridge: HippyBridge instance -- (instancetype)initWithBridge:(HippyBridge *)bridge NS_DESIGNATED_INITIALIZER; -- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE; -- (instancetype)initWithCoder:(NSCoder *)coder NS_UNAVAILABLE; - /** * Initial collection view */ diff --git a/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.mm b/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.mm index 41e6e53a94e..7431c218e50 100644 --- a/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.mm +++ b/renderer/native/ios/renderer/component/waterfalllist/HippyWaterfallView.mm @@ -25,6 +25,7 @@ #import "HippyFooterRefresh.h" #import "HippyWaterfallItemView.h" #import "UIView+Hippy.h" +#import "UIView+Render.h" #import "HippyRefresh.h" #import "HippyWaterfallViewDataSource.h" #import "HippyShadowView.h" @@ -61,9 +62,8 @@ @implementation HippyWaterfallView { @synthesize contentSize; -- (instancetype)initWithBridge:(id)bridge { - if (self = [super initWithFrame:CGRectZero]) { - _bridge = bridge; +- (instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { self.backgroundColor = [UIColor clearColor]; _scrollListeners = [NSHashTable weakObjectsHashTable]; _scrollEventThrottle = 100.f; @@ -266,7 +266,7 @@ - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cell if (cachedCellView) { cellView = cachedCellView; } else { - cellView = [self.bridge.uiManager createViewForShadowListItem:shadowView]; + cellView = [self.uiManager createViewForShadowListItem:shadowView]; [_cachedWeakCellViews setObject:cellView forKey:shadowView.hippyTag]; } diff --git a/tests/ios/HippyUIViewCategoryTest.m b/tests/ios/HippyUIViewCategoryTest.m index 22705653f1c..d6fb521c9b7 100644 --- a/tests/ios/HippyUIViewCategoryTest.m +++ b/tests/ios/HippyUIViewCategoryTest.m @@ -21,7 +21,18 @@ */ #import -#import "UIView+Hippy.h" +#import +#import +#import + +@interface UIView (HippyUIManagerUnitTest) + +/// Bind UIView with HippyUIManager +/// This is a convenient method for UIView to get HippyUIManager instance. +/// - Parameter uiManager: HippyUIManager instance +- (void)setUiManager:(HippyUIManager *)uiManager; + +@end @interface HippyUIViewCategoryTest : XCTestCase @@ -47,8 +58,15 @@ - (void)testGetHippyRootView { XCTAssert([testView hippyRootView] == testSuperView); testView.hippyTag = @(11); XCTAssert([testView hippyRootView] == nil); +} + +- (void)testGetHippyUIManager { + UIView *testView = [UIView new]; + XCTAssertNil([testView uiManager]); - + HippyUIManager *uiManager = [[HippyUIManager alloc] init]; + XCTAssertNoThrow(testView.uiManager = uiManager); + XCTAssertTrue(testView.uiManager == uiManager); } From 700cfdf06eb44e0a62be05b5a4aa24265570d33c Mon Sep 17 00:00:00 2001 From: birdguo Date: Wed, 11 Sep 2024 15:22:08 +0800 Subject: [PATCH 29/47] fix(vue-next): fix vuejs ugrade issue (#4004) * fix(vue-next): fix vuejs ugrade issue 1. fix vuejs 3.4.32 patchProps API change issue 2. compatible vuejs compiler-core API change issue 3. upgrade vue-next demo package version * fix(vue-next): fix vue-next-ssr-demo issue 1. compatible vue upgrade issue 2. fix vue-next-ssr demo issue --- .../examples/hippy-vue-next-demo/package.json | 8 ++-- .../hippy-vue-next-ssr-demo/README.md | 2 +- .../hippy-vue-next-ssr-demo/package.json | 15 +++---- .../scripts/webpack-ssr-config/client.dev.js | 20 +++++++++ .../webpack-ssr-config/client.entry.js | 31 ++++++++++++-- .../scripts/webpack-ssr-config/server.dev.js | 27 ++++++++++-- .../webpack-ssr-config/server.entry.js | 24 ++++++++++- .../hippy-vue-next-ssr-demo/src/app.vue | 19 ++++++++- .../hippy-vue-next-ssr-demo/src/main.ts | 2 +- .../hippy-vue-next-compiler-ssr/package.json | 12 +++--- .../src/transforms/ssrInjectCssVars.ts | 3 +- .../transforms/ssrInjectFallthroughAttrs.ts | 7 ++-- .../src/transforms/ssrTransformComponent.ts | 41 +++++++++++-------- .../src/transforms/ssrTransformSuspense.ts | 32 ++++++++------- .../package.json | 13 +++--- .../hippy-vue-next-style-parser/package.json | 4 +- .../js/packages/hippy-vue-next/package.json | 8 ++-- .../packages/hippy-vue-next/src/patch-prop.ts | 3 -- 18 files changed, 190 insertions(+), 81 deletions(-) diff --git a/driver/js/examples/hippy-vue-next-demo/package.json b/driver/js/examples/hippy-vue-next-demo/package.json index 1b311547f29..49bf7deac60 100644 --- a/driver/js/examples/hippy-vue-next-demo/package.json +++ b/driver/js/examples/hippy-vue-next-demo/package.json @@ -19,9 +19,9 @@ "@hippy/vue-next": "v3.3-latest", "@hippy/vue-router-next-history": "0.0.1", "@hippy/web-renderer": "latest", - "@vue/runtime-core": "^3.2.46", - "@vue/shared": "^3.2.46", - "vue": "^3.2.46", + "@vue/runtime-core": "^3.4.32", + "@vue/shared": "^3.4.32", + "vue": "^3.4.32", "vue-router": "^4.0.12" }, "devDependencies": { @@ -43,7 +43,7 @@ "@hippy/vue-css-loader": "v3.3-latest", "@vitejs/plugin-vue": "^1.9.4", "@vue/cli-service": "^4.5.19", - "@vue/compiler-sfc": "^3.2.46", + "@vue/compiler-sfc": "^3.4.32", "babel-loader": "^8.1.0", "case-sensitive-paths-webpack-plugin": "^2.2.0", "clean-webpack-plugin": "^4.0.0", diff --git a/driver/js/examples/hippy-vue-next-ssr-demo/README.md b/driver/js/examples/hippy-vue-next-ssr-demo/README.md index 77dccfdfd48..6429d65e1ff 100644 --- a/driver/js/examples/hippy-vue-next-ssr-demo/README.md +++ b/driver/js/examples/hippy-vue-next-ssr-demo/README.md @@ -25,7 +25,7 @@ ensure you were at `examples/hippy-vue-next-ssr-demo`. #### Development -1. run `npm run ssr:dev-build` to build client entry & client bundle, then running hippy debug server +1. run `npm run ssr:dev-client` to build client entry & client bundle, then running hippy debug server 2. run `npm run ssr:dev-server` to build server bundle and start SSR web server to listen port **8080**. 3. debug your app with [reference](https://hippyjs.org/en-us/#/guide/debug) > You can change server listen port 8080 in `server.ts` by your self, but you also need change request port 8080 in diff --git a/driver/js/examples/hippy-vue-next-ssr-demo/package.json b/driver/js/examples/hippy-vue-next-ssr-demo/package.json index 367d4bffe81..90a2f4ee02e 100644 --- a/driver/js/examples/hippy-vue-next-ssr-demo/package.json +++ b/driver/js/examples/hippy-vue-next-ssr-demo/package.json @@ -24,12 +24,13 @@ "@hippy/vue-router-next-history": "latest", "@hippy/web-renderer": "latest", "@hippy/vue-next": "latest", - "@hippy/vue-next-server-renderer": "file:../../packages/hippy-vue-next-server-renderer", - "@hippy/vue-next-style-parser": "file:../../packages/hippy-vue-next-style-parser", - "@vue/runtime-core": "^3.2.46", - "@vue/shared": "^3.2.46", + "@hippy/vue-next-server-renderer": "latest", + "@hippy/hippy-vue-next-style-parser": "latest", + "@vue/runtime-core": "^3.4.32", + "@vue/server-renderer": "^3.4.32", + "@vue/shared": "^3.4.32", "core-js": "^3.20.2", - "vue": "^3.2.46", + "vue": "^3.4.32", "vue-router": "^4.0.12", "express": "^4.18.2", "pinia": "2.0.30" @@ -52,10 +53,10 @@ "@hippy/rejection-tracking-polyfill": "^1.0.0", "@hippy/vue-css-loader": "^2.0.1", "@vitejs/plugin-vue": "^1.9.4", - "@hippy/vue-next-compiler-ssr": "file:../../packages/hippy-vue-next-compiler-ssr", + "@hippy/vue-next-compiler-ssr": "latest", "@types/shelljs": "^0.8.5", "@vue/cli-service": "^4.5.19", - "@vue/compiler-sfc": "^3.2.46", + "@vue/compiler-sfc": "^3.4.32", "babel-loader": "^8.1.0", "case-sensitive-paths-webpack-plugin": "^2.2.0", "chokidar": "^3.5.3", diff --git a/driver/js/examples/hippy-vue-next-ssr-demo/scripts/webpack-ssr-config/client.dev.js b/driver/js/examples/hippy-vue-next-ssr-demo/scripts/webpack-ssr-config/client.dev.js index f465c4ff488..cab3754f326 100644 --- a/driver/js/examples/hippy-vue-next-ssr-demo/scripts/webpack-ssr-config/client.dev.js +++ b/driver/js/examples/hippy-vue-next-ssr-demo/scripts/webpack-ssr-config/client.dev.js @@ -189,6 +189,26 @@ module.exports = { console.warn('* Using the @hippy/vue-next defined in package.json'); } + // If @hippy/vue-next-style-parser was built exist in packages directory then make an alias + // Remove the section if you don't use it + const hippyVueNextStyleParserPath = path.resolve(__dirname, '../../../../packages/hippy-vue-next-style-parser/dist'); + if (fs.existsSync(path.resolve(hippyVueNextStyleParserPath, 'index.js'))) { + console.warn(`* Using the @hippy/vue-next-style-parser in ${hippyVueNextStyleParserPath} as @hippy/vue-next-style-parser alias`); + aliases['@hippy/vue-next-style-parser'] = hippyVueNextStyleParserPath; + } else { + console.warn('* Using the @hippy/vue-next-style-parser defined in package.json'); + } + + // If @hippy/vue-next-server-render was built exist in packages directory then make an alias + // Remove the section if you don't use it + const hippyVueNextSsrPath = path.resolve(__dirname, '../../../../packages/hippy-vue-next-server-renderer/dist'); + if (fs.existsSync(path.resolve(hippyVueNextSsrPath, 'index.js'))) { + console.warn(`* Using the @hippy/vue-next-server-renderer in ${hippyVueNextSsrPath} as @hippy/vue-next-server-renderer alias`); + aliases['@hippy/vue-next-server-renderer'] = hippyVueNextSsrPath; + } else { + console.warn('* Using the @hippy/vue-next-server-renderer defined in package.json'); + } + return aliases; })(), }, diff --git a/driver/js/examples/hippy-vue-next-ssr-demo/scripts/webpack-ssr-config/client.entry.js b/driver/js/examples/hippy-vue-next-ssr-demo/scripts/webpack-ssr-config/client.entry.js index f710f743a1b..660cc908186 100644 --- a/driver/js/examples/hippy-vue-next-ssr-demo/scripts/webpack-ssr-config/client.entry.js +++ b/driver/js/examples/hippy-vue-next-ssr-demo/scripts/webpack-ssr-config/client.entry.js @@ -2,6 +2,7 @@ const path = require('path'); const webpack = require('webpack'); const pkg = require('../../package.json'); +const fs = require('fs') module.exports = { mode: 'production', @@ -90,8 +91,32 @@ module.exports = { }, resolve: { extensions: ['.js', '.json', '.ts'], - alias: (() => ({ - src: path.resolve('./src'), - }))(), + alias: (() => { + const aliases = { + src: path.resolve('./src'), + }; + + // If @hippy/vue-next-style-parser was built exist in packages directory then make an alias + // Remove the section if you don't use it + const hippyVueNextStyleParserPath = path.resolve(__dirname, '../../../../packages/hippy-vue-next-style-parser/dist'); + if (fs.existsSync(path.resolve(hippyVueNextStyleParserPath, 'index.js'))) { + console.warn(`* Using the @hippy/vue-next-style-parser in ${hippyVueNextStyleParserPath} as @hippy/vue-next-style-parser alias`); + aliases['@hippy/vue-next-style-parser'] = hippyVueNextStyleParserPath; + } else { + console.warn('* Using the @hippy/vue-next-style-parser defined in package.json'); + } + + // If @hippy/vue-next-server-render was built exist in packages directory then make an alias + // Remove the section if you don't use it + const hippyVueNextSsrPath = path.resolve(__dirname, '../../../../packages/hippy-vue-next-server-renderer/dist'); + if (fs.existsSync(path.resolve(hippyVueNextSsrPath, 'index.js'))) { + console.warn(`* Using the @hippy/vue-next-server-renderer in ${hippyVueNextSsrPath} as @hippy/vue-next-server-renderer alias`); + aliases['@hippy/vue-next-server-renderer'] = hippyVueNextSsrPath; + } else { + console.warn('* Using the @hippy/vue-next-server-renderer defined in package.json'); + } + + return aliases; + })(), }, }; diff --git a/driver/js/examples/hippy-vue-next-ssr-demo/scripts/webpack-ssr-config/server.dev.js b/driver/js/examples/hippy-vue-next-ssr-demo/scripts/webpack-ssr-config/server.dev.js index e82008654ed..770a4d7b9f7 100644 --- a/driver/js/examples/hippy-vue-next-ssr-demo/scripts/webpack-ssr-config/server.dev.js +++ b/driver/js/examples/hippy-vue-next-ssr-demo/scripts/webpack-ssr-config/server.dev.js @@ -3,7 +3,7 @@ const fs = require('fs'); const webpack = require('webpack'); const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); -const compilerSSR = require('@hippy/vue-next-compiler-ssr'); + const { VueLoaderPlugin } = require('vue-loader'); const pkg = require('../../package.json'); @@ -24,9 +24,20 @@ if (fs.existsSync(hippyVueNextPath)) { } else { console.warn('* Using the @hippy/vue-next defined in package.json'); } -const { isNativeTag } = require(vueNext); + +let compilerSsrPkg = '@hippy/vue-next-compiler-ssr' +let compilerSsrPath = path.resolve(__dirname, '../../../../packages/hippy-vue-next-compiler-ssr/dist/index.js'); +if (fs.existsSync(compilerSsrPath)) { + console.warn(`* Using the @hippy/vue-next-compiler-ssr in ${compilerSsrPath}`); + compilerSsrPkg = compilerSsrPath +} else { + console.warn('* Using the @hippy/vue-next-compiler-ssr defined in package.json'); +} +const { isNativeTag } = require(vueNext); +const compilerSsr = require(compilerSsrPkg); + module.exports = { mode: 'development', bail: true, @@ -83,7 +94,7 @@ module.exports = { comments: false, }, // real used vue compiler - compiler: compilerSSR, + compiler: compilerSsr, }, }, ], @@ -177,6 +188,16 @@ module.exports = { console.warn('* Using the @hippy/vue-next defined in package.json'); } + // If @hippy/vue-next-server-render was built exist in packages directory then make an alias + // Remove the section if you don't use it + const hippyVueNextSsrPath = path.resolve(__dirname, '../../../../packages/hippy-vue-next-server-renderer/dist'); + if (fs.existsSync(path.resolve(hippyVueNextSsrPath, 'index.js'))) { + console.warn(`* Using the @hippy/vue-next-server-renderer in ${hippyVueNextSsrPath} as @hippy/vue-next-server-renderer alias`); + aliases['@hippy/vue-next-server-renderer'] = hippyVueNextSsrPath; + } else { + console.warn('* Using the @hippy/vue-next-server-renderer defined in package.json'); + } + return aliases; })(), }, diff --git a/driver/js/examples/hippy-vue-next-ssr-demo/scripts/webpack-ssr-config/server.entry.js b/driver/js/examples/hippy-vue-next-ssr-demo/scripts/webpack-ssr-config/server.entry.js index 3ecee4aea93..b67c138c5ce 100644 --- a/driver/js/examples/hippy-vue-next-ssr-demo/scripts/webpack-ssr-config/server.entry.js +++ b/driver/js/examples/hippy-vue-next-ssr-demo/scripts/webpack-ssr-config/server.entry.js @@ -3,7 +3,6 @@ const fs = require('fs'); const webpack = require('webpack'); const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); -const compilerSSR = require('@hippy/vue-next-compiler-ssr'); const { VueLoaderPlugin } = require('vue-loader'); const pkg = require('../../package.json'); @@ -24,7 +23,18 @@ if (fs.existsSync(hippyVueNextPath)) { } else { console.warn('* Using the @hippy/vue-next defined in package.json'); } + +let compilerSsrPkg = '@hippy/vue-next-compiler-ssr' +let compilerSsrPath = path.resolve(__dirname, '../../../../packages/hippy-vue-next-compiler-ssr/dist/index.js'); +if (fs.existsSync(compilerSsrPath)) { + console.warn(`* Using the @hippy/vue-next-compiler-ssr in ${compilerSsrPath}`); + compilerSsrPkg = compilerSsrPath +} else { + console.warn('* Using the @hippy/vue-next-compiler-ssr defined in package.json'); +} + const { isNativeTag } = require(vueNext); +const compilerSsr = require(compilerSsrPkg); module.exports = { mode: 'production', @@ -77,7 +87,7 @@ module.exports = { comments: false, }, // real used vue compiler - compiler: compilerSSR, + compiler: compilerSsr, }, }, ], @@ -171,6 +181,16 @@ module.exports = { console.warn('* Using the @hippy/vue-next defined in package.json'); } + // If @hippy/vue-next-server-render was built exist in packages directory then make an alias + // Remove the section if you don't use it + const hippyVueNextSsrPath = path.resolve(__dirname, '../../../../packages/hippy-vue-next-server-renderer/dist'); + if (fs.existsSync(path.resolve(hippyVueNextSsrPath, 'index.js'))) { + console.warn(`* Using the @hippy/vue-next-server-renderer in ${hippyVueNextSsrPath} as @hippy/vue-next-server-renderer alias`); + aliases['@hippy/vue-next-server-renderer'] = hippyVueNextSsrPath; + } else { + console.warn('* Using the @hippy/vue-next-server-renderer defined in package.json'); + } + return aliases; })(), }, diff --git a/driver/js/examples/hippy-vue-next-ssr-demo/src/app.vue b/driver/js/examples/hippy-vue-next-ssr-demo/src/app.vue index bb96e1b1097..65058aea3ef 100644 --- a/driver/js/examples/hippy-vue-next-ssr-demo/src/app.vue +++ b/driver/js/examples/hippy-vue-next-ssr-demo/src/app.vue @@ -11,7 +11,7 @@ + >Hippy Vue Next {{ ssrMsg }}