Skip to content

Commit

Permalink
Revert "refactor(ios): rewrite bundle loading process (Tencent#4028)"
Browse files Browse the repository at this point in the history
This reverts commit b91f3e9.
  • Loading branch information
wwwcg committed Oct 24, 2024
1 parent 5a3a73e commit 892b5fd
Show file tree
Hide file tree
Showing 7 changed files with 763 additions and 118 deletions.
224 changes: 106 additions & 118 deletions framework/ios/base/bridge/HippyBridge.mm
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@

#import "HippyBridge.h"
#import "HippyBridge+Private.h"
#import "HippyBundleLoadOperation.h"
#import "HippyBundleExecutionOperation.h"
#import "HippyBundleOperationQueue.h"
#import "HippyContextWrapper.h"
#import "HippyDeviceBaseInfo.h"
#import "HippyDisplayLink.h"
Expand All @@ -48,7 +51,6 @@
#import "UIView+RenderManager.h"
#import "TypeConverter.h"
#import "VFSUriLoader.h"
#import "HippyBridge+VFSLoader.h"
#import "HippyBase64DataHandler.h"
#import "NativeRenderManager.h"
#import "HippyRootView.h"
Expand Down Expand Up @@ -102,10 +104,6 @@
static NSString *const HippyNativeGlobalKeyNightMode = @"NightMode";


#define HIPPY_BUNDLE_FETCH_TIMEOUT_SEC 30 // Bundle fetch operation timeout value, 30s
static NSString *const kHippyBundleFetchQueueName = @"com.hippy.bundleQueue.fetch";
static NSString *const kHippyBundleExecuteQueueName = @"com.hippy.bundleQueue.execute";

typedef NS_ENUM(NSUInteger, HippyBridgeFields) {
HippyBridgeFieldRequestModuleIDs = 0,
HippyBridgeFieldMethodIDs,
Expand Down Expand Up @@ -145,10 +143,12 @@ static inline void registerLogDelegateToHippyCore() {
@interface HippyBridge() {
__weak id<HippyMethodInterceptorProtocol> _methodInterceptor;
HippyModulesSetup *_moduleSetup;
__weak NSOperation *_lastOperation;
BOOL _wasBatchActive;
HippyDisplayLink *_displayLink;
HippyBridgeModuleProviderBlock _moduleProvider;
BOOL _valid;
HippyBundleOperationQueue *_bundlesQueue;
NSMutableArray<NSURL *> *_bundleURLs;
NSURL *_sandboxDirectory;

Expand All @@ -165,19 +165,14 @@ @interface HippyBridge() {
/// 在共享情况下,只有全部bridge实例均释放,JS引擎资源才会销毁。
/// 默认情况下对每个bridge使用独立JS引擎
@property (nonatomic, strong) NSString *engineKey;
/// Module setup semaphore
@property (readwrite, strong) dispatch_semaphore_t moduleSemaphore;

/// Pending load bundle's URL
/// 等待加载(Load)的 Vendor bundleURL
@property (nonatomic, strong) NSURL *pendingLoadingVendorBundleURL;
/// Bundle loading count, used to indicate whether is in loading state.
@property (nonatomic, assign) NSInteger loadingCount;
/// Bundle fetch operation queue (concurrent)
@property (nonatomic, strong) NSOperationQueue *bundleQueue;
/// Record the last execute operation for adding execution dependency.
@property (atomic, strong, nullable) NSOperation *lastExecuteOperation;

/// Cached Dimensions info,will be passed to JS Side.

@property(readwrite, strong) dispatch_semaphore_t moduleSemaphore;
@property(readwrite, assign) NSInteger loadingCount;


/// 缓存的Dimensions信息,用于传递给JS Side
@property (atomic, strong) NSDictionary *cachedDimensionsInfo;

@end
Expand All @@ -191,6 +186,17 @@ @implementation HippyBridge

dispatch_queue_t HippyJSThread;

dispatch_queue_t HippyBridgeQueue() {
static dispatch_once_t onceToken;
static dispatch_queue_t queue;
dispatch_once(&onceToken, ^{
dispatch_queue_attr_t attr =
dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INITIATED, 0);
queue = dispatch_queue_create("com.hippy.bridge", attr);
});
return queue;
}

+ (void)initialize {
[super initialize];
static dispatch_once_t onceToken;
Expand Down Expand Up @@ -227,6 +233,7 @@ - (instancetype)initWithDelegate:(id<HippyBridgeDelegate>)delegate
_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);
registerLogDelegateToHippyCore();
Expand All @@ -236,12 +243,6 @@ - (instancetype)initWithDelegate:(id<HippyBridgeDelegate>)delegate
self.cachedDimensionsInfo = hippyExportedDimensions(self);
}, YES);

// Create bundle operation queue
_bundleQueue = [[NSOperationQueue alloc] init];
_bundleQueue.qualityOfService = NSQualityOfServiceUserInitiated;
_bundleQueue.name = kHippyBundleFetchQueueName;
_bundleQueue.maxConcurrentOperationCount = NSOperationQueueDefaultMaxConcurrentOperationCount;

[self setUp];

[self addImageProviderClass:[HippyDefaultImageProvider class]];
Expand Down Expand Up @@ -439,7 +440,6 @@ - (void)setUp {

} @catch (NSException *exception) {
HippyBridgeHandleException(exception, self);
dispatch_semaphore_signal(self.moduleSemaphore);
}
}

Expand All @@ -459,21 +459,20 @@ - (void)loadPendingVendorBundleURLIfNeeded {
}
}

#define BUNDLE_LOAD_NOTI_SUCCESS_USER_INFO(whichSelf) \
@{ kHippyNotiBridgeKey: whichSelf, \
#define BUNDLE_LOAD_NOTI_SUCCESS_USER_INFO \
@{ kHippyNotiBridgeKey: strongSelf, \
kHippyNotiBundleUrlKey: bundleURL, \
kHippyNotiBundleTypeKey : @(bundleType) }

#define BUNDLE_LOAD_NOTI_ERROR_USER_INFO(whichSelf) \
@{ kHippyNotiBridgeKey: whichSelf, \
#define BUNDLE_LOAD_NOTI_ERROR_USER_INFO \
@{ kHippyNotiBridgeKey: strongSelf, \
kHippyNotiBundleUrlKey: bundleURL, \
kHippyNotiBundleTypeKey : @(bundleType), \
kHippyNotiErrorKey : error }

- (void)loadBundleURL:(NSURL *)bundleURL
bundleType:(HippyBridgeBundleType)bundleType
completion:(nonnull HippyBridgeBundleLoadCompletionBlock)completion {
HippyAssertParam(bundleURL);
if (!bundleURL) {
if (completion) {
static NSString *bundleError = @"bundle url is nil";
Expand All @@ -498,108 +497,117 @@ - (void)loadBundleURL:(NSURL *)bundleURL
HP_CSTR_NOT_NULL(bundleURL.absoluteString.UTF8String));
[_bundleURLs addObject:bundleURL];

NSDictionary *userInfo = BUNDLE_LOAD_NOTI_SUCCESS_USER_INFO(self);
[[NSNotificationCenter defaultCenter] postNotificationName:HippyJavaScriptWillStartLoadingNotification
object:self
userInfo:userInfo];
[self beginLoadingBundle:bundleURL bundleType:bundleType completion:completion];
__weak __typeof(self)weakSelf = self;
dispatch_async(HippyBridgeQueue(), ^{
__strong __typeof(weakSelf)strongSelf = weakSelf;
if (!strongSelf) {
return;
}
NSDictionary *userInfo = BUNDLE_LOAD_NOTI_SUCCESS_USER_INFO;
[[NSNotificationCenter defaultCenter] postNotificationName:HippyJavaScriptWillStartLoadingNotification
object:strongSelf
userInfo:userInfo];
[strongSelf beginLoadingBundle:bundleURL bundleType:bundleType completion:completion];
});
}

- (void)beginLoadingBundle:(NSURL *)bundleURL
bundleType:(HippyBridgeBundleType)bundleType
completion:(HippyBridgeBundleLoadCompletionBlock)completion {
HippyAssertMainQueue();
HippyAssertParam(bundleURL);
HippyAssertParam(completion);

__weak __typeof(self)weakSelf = self;
dispatch_group_t group = dispatch_group_create();
__weak HippyBridge *weakSelf = self;
__block NSData *script = nil;
self.loadingCount++;

// Fetch operation
NSBlockOperation *fetchOperation = [NSBlockOperation blockOperationWithBlock:^{
__strong __typeof(weakSelf) strongSelf = weakSelf;
dispatch_group_enter(group);
NSOperationQueue *bundleQueue = [[NSOperationQueue alloc] init];
bundleQueue.maxConcurrentOperationCount = 1;
bundleQueue.name = @"com.hippy.bundleQueue";
HippyBundleLoadOperation *fetchOp = [[HippyBundleLoadOperation alloc] initWithBridge:self
bundleURL:bundleURL
queue:bundleQueue];
fetchOp.onLoad = ^(NSData *source, NSError *error) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
if (!strongSelf) {
dispatch_group_leave(group);
return;
}
HippyLogInfo(@"Start fetching bundle(%s)",
HP_CSTR_NOT_NULL(bundleURL.absoluteString.lastPathComponent.UTF8String));
// create semaphore
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[strongSelf fetchBundleWithURL:bundleURL completion:^(NSData *source, NSError *error) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
NSDictionary *userInfo;
if (error) {
HippyBridgeFatal(error, strongSelf);
userInfo = BUNDLE_LOAD_NOTI_ERROR_USER_INFO(strongSelf);
} else {
script = source;
userInfo = BUNDLE_LOAD_NOTI_SUCCESS_USER_INFO(strongSelf);
}
[[NSNotificationCenter defaultCenter] postNotificationName:HippyJavaScripDidLoadSourceCodeNotification
object:strongSelf
userInfo:userInfo];
HippyLogInfo(@"End fetching bundle(%s) error?:%@",
HP_CSTR_NOT_NULL(bundleURL.absoluteString.lastPathComponent.UTF8String), error);
dispatch_semaphore_signal(semaphore); // release semaphore
}];
// wait semaphore
dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, HIPPY_BUNDLE_FETCH_TIMEOUT_SEC * NSEC_PER_SEC);
intptr_t result = dispatch_semaphore_wait(semaphore, timeout);
if (result != 0) {
HippyLogError(@"Fetch operation timed out!!! (30s)");
NSDictionary *userInfo;
if (error) {
HippyBridgeFatal(error, weakSelf);
userInfo = BUNDLE_LOAD_NOTI_ERROR_USER_INFO;
} else {
script = source;
userInfo = BUNDLE_LOAD_NOTI_SUCCESS_USER_INFO;
}
}];
[[NSNotificationCenter defaultCenter] postNotificationName:HippyJavaScripDidLoadSourceCodeNotification
object:strongSelf
userInfo:userInfo];
dispatch_group_leave(group);
};

// Execution operation
NSBlockOperation *executeOperation = [NSBlockOperation blockOperationWithBlock:^{
HippyLogInfo(@"Start executing bundle(%s)",
HP_CSTR_NOT_NULL(bundleURL.absoluteString.lastPathComponent.UTF8String));
__strong __typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf || !strongSelf.valid || !script) {
NSString *errMsg = [NSString stringWithFormat:@"Bundle Execution Operation Fail! valid:%d, script:%@",
strongSelf.valid, script];
completion(nil, HippyErrorWithMessage(errMsg));
strongSelf.lastExecuteOperation = nil;
dispatch_group_enter(group);
HippyBundleExecutionOperation *executeOp = [[HippyBundleExecutionOperation alloc] initWithBlock:^{
__strong __typeof(weakSelf)strongSelf = weakSelf;
if (!strongSelf || !strongSelf.valid) {
dispatch_group_leave(group);
return;
}
__weak __typeof(strongSelf)weakSelf = strongSelf;
[strongSelf executeJSCode:script sourceURL:bundleURL onCompletion:^(id result, NSError *error) {
HippyLogInfo(@"End executing bundle(%s)",
HP_CSTR_NOT_NULL(bundleURL.absoluteString.lastPathComponent.UTF8String));
strongSelf.lastExecuteOperation = nil;
__strong __typeof(weakSelf)strongSelf = weakSelf;
HippyLogInfo(@"End loading bundle(%s) at %s",
HP_CSTR_NOT_NULL(bundleURL.absoluteString.lastPathComponent.UTF8String),
HP_CSTR_NOT_NULL(bundleURL.absoluteString.UTF8String));

if (completion) {
completion(bundleURL, error);
}
if (!strongSelf || !strongSelf.valid) {
dispatch_group_leave(group);
return;
}
if (error) {
HippyBridgeFatal(error, strongSelf);
}

__weak __typeof(self)weakSelf = strongSelf;
dispatch_async(dispatch_get_main_queue(), ^{
__strong __typeof(weakSelf)strongSelf = weakSelf;
if (!strongSelf) {
return;
}
strongSelf.loadingCount--;
NSNotificationName notiName = error ? HippyJavaScriptDidFailToLoadNotification : HippyJavaScriptDidLoadNotification;
NSDictionary *userInfo = error ? BUNDLE_LOAD_NOTI_ERROR_USER_INFO(strongSelf) : BUNDLE_LOAD_NOTI_SUCCESS_USER_INFO(strongSelf);
[[NSNotificationCenter defaultCenter] postNotificationName:notiName object:strongSelf userInfo:userInfo];
NSNotificationName notiName;
NSDictionary *userInfo;
if (error) {
notiName = HippyJavaScriptDidFailToLoadNotification;
userInfo = BUNDLE_LOAD_NOTI_ERROR_USER_INFO;
} else {
notiName = HippyJavaScriptDidLoadNotification;
userInfo = BUNDLE_LOAD_NOTI_SUCCESS_USER_INFO;
}
[[NSNotificationCenter defaultCenter] postNotificationName:notiName
object:strongSelf
userInfo:userInfo];
});
dispatch_group_leave(group);
}];
}];
} queue:bundleQueue];

// Add dependency, make sure that doing fetch before execute,
// and all execution operations must be queued.
[executeOperation addDependency:fetchOperation];
if (self.lastExecuteOperation) {
[executeOperation addDependency:self.lastExecuteOperation];
//set dependency
[executeOp addDependency:fetchOp];
if (_lastOperation) {
[executeOp addDependency:_lastOperation];
_lastOperation = executeOp;
} else {
_lastOperation = executeOp;
}

// Enqueue operation
[_bundleQueue addOperations:@[fetchOperation, executeOperation] waitUntilFinished:NO];
self.lastExecuteOperation = executeOperation;
[_bundlesQueue addOperations:@[fetchOp, executeOp]];
dispatch_block_t completionBlock = ^(void){
HippyBridge *strongSelf = weakSelf;
if (strongSelf && strongSelf.isValid) {
strongSelf.loadingCount--;
}
};
dispatch_group_notify(group, HippyBridgeQueue(), completionBlock);
}

- (void)unloadInstanceForRootView:(NSNumber *)rootTag {
Expand Down Expand Up @@ -667,26 +675,6 @@ - (void)setInspectable:(BOOL)isInspectable {

#pragma mark - Private

/// Fetch JS Bundle
- (void)fetchBundleWithURL:(NSURL *)bundleURL completion:(void (^)(NSData *source, NSError *error))completion {
HippyAssertParam(bundleURL);
HippyAssertParam(completion);
// Fetch the bundle
// Call the completion handler with the fetched data or error
[self loadContentsAsynchronouslyFromUrl:bundleURL.absoluteString
method:@"get"
params:nil
body:nil
queue:nil
progress:nil
completionHandler:^(NSData * _Nullable data,
NSDictionary * _Nullable userInfo,
NSURLResponse * _Nullable response,
NSError * _Nullable error) {
completion(data, error);
}];
}

/// Execute JS Bundle
- (void)executeJSCode:(NSData *)script
sourceURL:(NSURL *)sourceURL
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*!
* 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 <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface HippyBundleExecutionOperation : NSOperation

- (instancetype)initWithBlock:(dispatch_block_t)block queue:(NSOperationQueue *)queue;

@end

NS_ASSUME_NONNULL_END
Loading

0 comments on commit 892b5fd

Please sign in to comment.