diff --git a/React/Base/RCTBatchedBridge.mm b/React/Base/RCTBatchedBridge.mm index 66ce3e649..5c90acca5 100644 --- a/React/Base/RCTBatchedBridge.mm +++ b/React/Base/RCTBatchedBridge.mm @@ -115,7 +115,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR dispatch_group_enter(initModulesAndLoadSource); __weak RCTBatchedBridge *weakSelf = self; __block NSData *sourceCode; - [self loadSource:^(NSError *error, NSData *source, __unused int64_t sourceLength) { + [self loadSource:^(NSError *error, RCTSource *source) { if (error) { RCTLogWarn(@"Failed to load source: %@", error); dispatch_async(dispatch_get_main_queue(), ^{ @@ -123,7 +123,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR }); } - sourceCode = source; + sourceCode = source.data; dispatch_group_leave(initModulesAndLoadSource); } onProgress:^(RCTLoadingProgress *progressData) { #if RCT_DEV && __has_include("RCTDevLoadingView.h") @@ -192,10 +192,10 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR [_performanceLogger markStartForTag:RCTPLScriptDownload]; RCTPerformanceLogger *performanceLogger = _performanceLogger; - RCTSourceLoadBlock onSourceLoad = ^(NSError *error, NSData *source, int64_t sourceLength) { + RCTSourceLoadBlock onSourceLoad = ^(NSError *error, RCTSource *source) { [performanceLogger markStopForTag:RCTPLScriptDownload]; - [performanceLogger setValue:sourceLength forTag:RCTPLBundleSize]; - _onSourceLoad(error, source, sourceLength); + [performanceLogger setValue:source.length forTag:RCTPLBundleSize]; + _onSourceLoad(error, source); }; if ([self.delegate respondsToSelector:@selector(loadSourceForBridge:onProgress:onComplete:)]) { @@ -205,9 +205,9 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR } else if (!self.bundleURL) { NSError *error = RCTErrorWithMessage(@"No bundle URL present.\n\nMake sure you're running a packager " \ "server or have included a .jsbundle file in your application bundle."); - onSourceLoad(error, nil, 0); + onSourceLoad(error, nil); } else { - [RCTJavaScriptLoader loadBundleAtURL:self.bundleURL onProgress:onProgress onComplete:^(NSError *error, NSData *source, int64_t sourceLength) { + [RCTJavaScriptLoader loadBundleAtURL:self.bundleURL onProgress:onProgress onComplete:^(NSError *error, RCTSource *source) { if (error && [self.delegate respondsToSelector:@selector(fallbackSourceURLForBridge:)]) { NSURL *fallbackURL = [self.delegate fallbackSourceURLForBridge:self->_parentBridge]; if (fallbackURL && ![fallbackURL isEqual:self.bundleURL]) { @@ -217,7 +217,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR return; } } - onSourceLoad(error, source, sourceLength); + onSourceLoad(error, source); }]; } } diff --git a/React/Base/RCTJavaScriptLoader.h b/React/Base/RCTJavaScriptLoader.h index c1d30ce20..08cf7e420 100755 --- a/React/Base/RCTJavaScriptLoader.h +++ b/React/Base/RCTJavaScriptLoader.h @@ -33,8 +33,32 @@ NS_ENUM(NSInteger) { @end +@interface RCTSource : NSObject + +/** + * URL of the source object. + */ +@property (strong, nonatomic, readonly) NSURL *url; + +/** + * JS source (or simply the binary header in the case of a RAM bundle). + */ +@property (strong, nonatomic, readonly) NSData *data; + +/** + * Length of the entire JS bundle. Note that self.length != self.data.length in the case of certain bundle formats. For + * instance, when using RAM bundles: + * + * - self.data will point to the bundle header + * - self.data.length is the length of the bundle header, i.e. sizeof(facebook::react::BundleHeader) + * - self.length is the length of the entire bundle file (header + contents) + */ +@property (nonatomic, readonly) NSUInteger length; + +@end + typedef void (^RCTSourceLoadProgressBlock)(RCTLoadingProgress *progressData); -typedef void (^RCTSourceLoadBlock)(NSError *error, NSData *source, int64_t sourceLength); +typedef void (^RCTSourceLoadBlock)(NSError *error, RCTSource *source); @interface RCTJavaScriptLoader : NSObject diff --git a/React/Base/RCTJavaScriptLoader.mm b/React/Base/RCTJavaScriptLoader.mm index 4330e4e78..2e531b58b 100755 --- a/React/Base/RCTJavaScriptLoader.mm +++ b/React/Base/RCTJavaScriptLoader.mm @@ -22,6 +22,29 @@ NSString *const RCTJavaScriptLoaderErrorDomain = @"RCTJavaScriptLoaderErrorDomain"; +@interface RCTSource() +{ +@public + NSURL *_url; + NSData *_data; + NSUInteger _length; +} + +@end + +@implementation RCTSource + +static RCTSource *RCTSourceCreate(NSURL *url, NSData *data, int64_t length) NS_RETURNS_RETAINED +{ + RCTSource *source = [RCTSource new]; + source->_url = url; + source->_data = data; + source->_length = length; + return source; +} + +@end + @implementation RCTLoadingProgress - (NSString *)description @@ -51,7 +74,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) sourceLength:&sourceLength error:&error]; if (data) { - onComplete(nil, data, sourceLength); + onComplete(nil, RCTSourceCreate(scriptURL, data, sourceLength)); return; } @@ -62,7 +85,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init) if (isCannotLoadSyncError) { attemptAsynchronousLoadOfBundleAtURL(scriptURL, onProgress, onComplete); } else { - onComplete(error, nil, 0); + onComplete(error, nil); } } @@ -193,7 +216,7 @@ static void attemptAsynchronousLoadOfBundleAtURL(NSURL *scriptURL, RCTSourceLoad NSData *source = [NSData dataWithContentsOfFile:scriptURL.path options:NSDataReadingMappedIfSafe error:&error]; - onComplete(error, source, source.length); + onComplete(error, RCTSourceCreate(scriptURL, source, source.length)); }); return; } @@ -224,7 +247,7 @@ static void attemptAsynchronousLoadOfBundleAtURL(NSURL *scriptURL, RCTSourceLoad NSUnderlyingErrorKey: error, }]; } - onComplete(error, nil, 0); + onComplete(error, nil); return; } @@ -239,7 +262,7 @@ static void attemptAsynchronousLoadOfBundleAtURL(NSURL *scriptURL, RCTSourceLoad error = [NSError errorWithDomain:@"JSServer" code:statusCode userInfo:userInfoForRawResponse([[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding])]; - onComplete(error, nil, 0); + onComplete(error, nil); return; } @@ -255,11 +278,11 @@ static void attemptAsynchronousLoadOfBundleAtURL(NSURL *scriptURL, RCTSourceLoad @"headers": headers, @"data": data }]; - onComplete(error, nil, 0); + onComplete(error, nil); return; } - onComplete(nil, data, data.length); + onComplete(nil, RCTSourceCreate(scriptURL, data, data.length)); } progressHandler:^(NSDictionary *headers, NSNumber *loaded, NSNumber *total) { // Only care about download progress events for the javascript bundle part. if ([headers[@"Content-Type"] isEqualToString:@"application/javascript"]) { diff --git a/React/CxxBridge/RCTCxxBridge.mm b/React/CxxBridge/RCTCxxBridge.mm index fd0346a74..cdb698f62 100644 --- a/React/CxxBridge/RCTCxxBridge.mm +++ b/React/CxxBridge/RCTCxxBridge.mm @@ -350,12 +350,12 @@ struct RCTInstanceCallback : public InstanceCallback { // Load the source asynchronously, then store it for later execution. dispatch_group_enter(prepareBridge); __block NSData *sourceCode; - [self loadSource:^(NSError *error, NSData *source, int64_t sourceLength) { + [self loadSource:^(NSError *error, RCTSource *source) { if (error) { [weakSelf handleError:error]; } - sourceCode = source; + sourceCode = source.data; dispatch_group_leave(prepareBridge); } onProgress:^(RCTLoadingProgress *progressData) { #if RCT_DEV && __has_include("RCTDevLoadingView.h") @@ -386,13 +386,13 @@ struct RCTInstanceCallback : public InstanceCallback { (void)cookie; RCTPerformanceLogger *performanceLogger = _performanceLogger; - RCTSourceLoadBlock onSourceLoad = ^(NSError *error, NSData *source, int64_t sourceLength) { + RCTSourceLoadBlock onSourceLoad = ^(NSError *error, RCTSource *source) { RCTProfileEndAsyncEvent(0, @"native", cookie, @"JavaScript download", @"JS async"); [performanceLogger markStopForTag:RCTPLScriptDownload]; - [performanceLogger setValue:sourceLength forTag:RCTPLBundleSize]; + [performanceLogger setValue:source.length forTag:RCTPLBundleSize]; [center postNotificationName:RCTBridgeDidDownloadScriptNotification object:self->_parentBridge]; - _onSourceLoad(error, source, sourceLength); + _onSourceLoad(error, source); }; if ([self.delegate respondsToSelector:@selector(loadSourceForBridge:onProgress:onComplete:)]) { @@ -402,9 +402,9 @@ struct RCTInstanceCallback : public InstanceCallback { } else if (!self.bundleURL) { NSError *error = RCTErrorWithMessage(@"No bundle URL present.\n\nMake sure you're running a packager " \ "server or have included a .jsbundle file in your application bundle."); - onSourceLoad(error, nil, 0); + onSourceLoad(error, nil); } else { - [RCTJavaScriptLoader loadBundleAtURL:self.bundleURL onProgress:onProgress onComplete:^(NSError *error, NSData *source, int64_t sourceLength) { + [RCTJavaScriptLoader loadBundleAtURL:self.bundleURL onProgress:onProgress onComplete:^(NSError *error, RCTSource *source) { if (error && [self.delegate respondsToSelector:@selector(fallbackSourceURLForBridge:)]) { NSURL *fallbackURL = [self.delegate fallbackSourceURLForBridge:self->_parentBridge]; if (fallbackURL && ![fallbackURL isEqual:self.bundleURL]) { @@ -414,7 +414,7 @@ struct RCTInstanceCallback : public InstanceCallback { return; } } - onSourceLoad(error, source, sourceLength); + onSourceLoad(error, source); }]; } }