mirror of
https://github.com/react/react-native.git
synced 2026-09-28 13:23:09 +08:00
refactor(iOS): persist bundle as local file on par with Android (#57751)
Summary: On Android, in development, the JS bundle is downloaded and saved as a file - this is done to avoid passing it through JNI, but iOS could use similar approach for uniform behavior. This allows libraries to be able to obtain the bundle from the file without re-downloading it from Metro. It would impact iOS boot slightly, but only in development, so it should be negligible. ## Changelog: [IOS] [CHANGED] - make iOS preserve dev bundle as a temp file on par with Android implementation Pull Request resolved: https://github.com/react/react-native/pull/57751 Test Plan: rn-tester iOS dev works with this change Reviewed By: cortinico, christophpurrer Differential Revision: D114346244 Pulled By: coado fbshipit-source-id: ebb4264fe8949cd766e71ca0363aa209a61370f7
This commit is contained in:
committed by
meta-codesync[bot]
parent
fff4994af8
commit
e2a4c68449
@@ -72,5 +72,13 @@ typedef NSMutableArray<NSURLQueryItem *> *_Nullable (^RCTPackagerOptionsUpdater)
|
||||
andDefaultGetter:(nullable RCTBridgelessBundleURLGetter)defaultGetter;
|
||||
- (void)resetBundleURL;
|
||||
@property (nonatomic, nullable) NSURL *bundleURL;
|
||||
|
||||
/**
|
||||
* File URL of the most recently downloaded bundle persisted to disk. Only set
|
||||
* when the bundle was fetched from a remote URL (e.g. the packager); nil when
|
||||
* the bundle was loaded from a local file, in which case its location on disk
|
||||
* is the bundleURL itself.
|
||||
*/
|
||||
@property (nonatomic, nullable) NSURL *downloadedBundleFileURL;
|
||||
@property (nonatomic, nonnull) RCTBundleConfiguration *bundleConfig;
|
||||
@end
|
||||
|
||||
@@ -68,6 +68,14 @@ NS_ENUM(NSInteger){
|
||||
*/
|
||||
@property (nonatomic, readonly) NSInteger filesChangedCount;
|
||||
|
||||
/**
|
||||
* File URL of the downloaded bundle persisted to disk, from which self.data is
|
||||
* memory-mapped. Only set when the bundle was fetched from a remote URL (e.g. the
|
||||
* packager); nil when the bundle was loaded from a local file, in which case the
|
||||
* bundle's location on disk is self.url.
|
||||
*/
|
||||
@property (strong, nonatomic, readonly) NSURL *downloadedBundleFileURL;
|
||||
|
||||
@end
|
||||
|
||||
typedef void (^RCTSourceLoadProgressBlock)(RCTLoadingProgress *progressData);
|
||||
|
||||
@@ -25,6 +25,7 @@ NSString *const RCTJavaScriptLoaderErrorDomain = @"RCTJavaScriptLoaderErrorDomai
|
||||
NSData *_data;
|
||||
NSUInteger _length;
|
||||
NSInteger _filesChangedCount;
|
||||
NSURL *_downloadedBundleFileURL;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -210,6 +211,15 @@ static void parseHeaders(NSDictionary *headers, RCTSource *source)
|
||||
source->_filesChangedCount = [headers[@"X-Metro-Files-Changed-Count"] integerValue];
|
||||
}
|
||||
|
||||
static NSURL *persistDownloadedBundle(NSData *data, NSError **error)
|
||||
{
|
||||
NSString *bundlePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"ReactNativeDevBundle.js"];
|
||||
if (![data writeToFile:bundlePath options:NSDataWritingAtomic error:error]) {
|
||||
return nil;
|
||||
}
|
||||
return [NSURL fileURLWithPath:bundlePath];
|
||||
}
|
||||
|
||||
static void attemptAsynchronousLoadOfBundleAtURL(
|
||||
NSURL *scriptURL,
|
||||
RCTSourceLoadProgressBlock onProgress,
|
||||
@@ -314,7 +324,24 @@ static void attemptAsynchronousLoadOfBundleAtURL(
|
||||
}
|
||||
}
|
||||
|
||||
RCTSource *source = RCTSourceCreate(sourceURL, data, data.length);
|
||||
NSError *persistError;
|
||||
NSURL *downloadedBundleFileURL = persistDownloadedBundle(data, &persistError);
|
||||
if (downloadedBundleFileURL == nil) {
|
||||
onComplete(persistError, nil);
|
||||
return;
|
||||
}
|
||||
|
||||
NSError *mappingError;
|
||||
NSData *bundleData = [NSData dataWithContentsOfURL:downloadedBundleFileURL
|
||||
options:NSDataReadingMappedIfSafe
|
||||
error:&mappingError];
|
||||
if (bundleData == nil) {
|
||||
onComplete(mappingError, nil);
|
||||
return;
|
||||
}
|
||||
|
||||
RCTSource *source = RCTSourceCreate(sourceURL, bundleData, static_cast<int64_t>(bundleData.length));
|
||||
source->_downloadedBundleFileURL = downloadedBundleFileURL;
|
||||
parseHeaders(headers, source);
|
||||
onComplete(nil, source);
|
||||
}
|
||||
|
||||
+10
-2
@@ -537,10 +537,18 @@ class RCTHostHostTargetDelegate : public facebook::react::jsinspector_modern::Ho
|
||||
onProgress:(RCTSourceLoadProgressBlock)onProgress
|
||||
onComplete:(RCTSourceLoadBlock)loadCallback
|
||||
{
|
||||
__weak RCTHost *weakSelf = self;
|
||||
RCTSourceLoadBlock onComplete = ^(NSError *error, RCTSource *source) {
|
||||
RCTHost *strongSelf = weakSelf;
|
||||
if (strongSelf != nil && source != nil) {
|
||||
strongSelf->_bundleManager.downloadedBundleFileURL = source.downloadedBundleFileURL;
|
||||
}
|
||||
loadCallback(error, source);
|
||||
};
|
||||
if ([_hostDelegate respondsToSelector:@selector(loadBundleAtURL:onProgress:onComplete:)]) {
|
||||
[_hostDelegate loadBundleAtURL:sourceURL onProgress:onProgress onComplete:loadCallback];
|
||||
[_hostDelegate loadBundleAtURL:sourceURL onProgress:onProgress onComplete:onComplete];
|
||||
} else {
|
||||
[RCTJavaScriptLoader loadBundleAtURL:sourceURL onProgress:onProgress onComplete:loadCallback];
|
||||
[RCTJavaScriptLoader loadBundleAtURL:sourceURL onProgress:onProgress onComplete:onComplete];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -749,6 +749,7 @@ interface RCTBundleConfiguration : public NSObject {
|
||||
|
||||
interface RCTBundleManager : public NSObject {
|
||||
public @property (assign) NSURL* bundleURL;
|
||||
public @property (assign) NSURL* downloadedBundleFileURL;
|
||||
public @property (assign) RCTBundleConfiguration* bundleConfig;
|
||||
public virtual _Nullable instancetype initWithBundleConfig:(_Nullable RCTBundleConfiguration* bundleConfig);
|
||||
public virtual void resetBundleURL();
|
||||
@@ -1818,6 +1819,7 @@ interface RCTSource : public NSObject {
|
||||
public @property (assign, readonly) NSInteger filesChangedCount;
|
||||
public @property (assign, readonly) NSUInteger length;
|
||||
public @property (strong, readonly) NSData* data;
|
||||
public @property (strong, readonly) NSURL* downloadedBundleFileURL;
|
||||
public @property (strong, readonly) NSURL* url;
|
||||
}
|
||||
|
||||
|
||||
@@ -747,6 +747,7 @@ interface RCTBundleConfiguration : public NSObject {
|
||||
|
||||
interface RCTBundleManager : public NSObject {
|
||||
public @property (assign) NSURL* bundleURL;
|
||||
public @property (assign) NSURL* downloadedBundleFileURL;
|
||||
public @property (assign) RCTBundleConfiguration* bundleConfig;
|
||||
public virtual _Nullable instancetype initWithBundleConfig:(_Nullable RCTBundleConfiguration* bundleConfig);
|
||||
public virtual void resetBundleURL();
|
||||
@@ -1813,6 +1814,7 @@ interface RCTSource : public NSObject {
|
||||
public @property (assign, readonly) NSInteger filesChangedCount;
|
||||
public @property (assign, readonly) NSUInteger length;
|
||||
public @property (strong, readonly) NSData* data;
|
||||
public @property (strong, readonly) NSURL* downloadedBundleFileURL;
|
||||
public @property (strong, readonly) NSURL* url;
|
||||
}
|
||||
|
||||
|
||||
@@ -749,6 +749,7 @@ interface RCTBundleConfiguration : public NSObject {
|
||||
|
||||
interface RCTBundleManager : public NSObject {
|
||||
public @property (assign) NSURL* bundleURL;
|
||||
public @property (assign) NSURL* downloadedBundleFileURL;
|
||||
public @property (assign) RCTBundleConfiguration* bundleConfig;
|
||||
public virtual _Nullable instancetype initWithBundleConfig:(_Nullable RCTBundleConfiguration* bundleConfig);
|
||||
public virtual void resetBundleURL();
|
||||
@@ -1818,6 +1819,7 @@ interface RCTSource : public NSObject {
|
||||
public @property (assign, readonly) NSInteger filesChangedCount;
|
||||
public @property (assign, readonly) NSUInteger length;
|
||||
public @property (strong, readonly) NSData* data;
|
||||
public @property (strong, readonly) NSURL* downloadedBundleFileURL;
|
||||
public @property (strong, readonly) NSURL* url;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user