This repository has been archived on 2022-03-12. You can view files and clone it, but cannot push or open issues or pull requests.
reValuate/node_modules/expo-updates/ios/EXUpdates/AppLoader/EXUpdatesEmbeddedAppLoader.m
2021-04-02 02:24:13 +03:00

125 lines
6.0 KiB
Objective-C

// Copyright © 2019 650 Industries. All rights reserved.
#import <EXUpdates/EXUpdatesFileDownloader.h>
#import <EXUpdates/EXUpdatesEmbeddedAppLoader.h>
NS_ASSUME_NONNULL_BEGIN
NSString * const EXUpdatesEmbeddedManifestName = @"app";
NSString * const EXUpdatesEmbeddedManifestType = @"manifest";
NSString * const EXUpdatesEmbeddedBundleFilename = @"app";
NSString * const EXUpdatesEmbeddedBundleFileType = @"bundle";
NSString * const EXUpdatesBareEmbeddedBundleFilename = @"main";
NSString * const EXUpdatesBareEmbeddedBundleFileType = @"jsbundle";
static NSString * const EXUpdatesEmbeddedAppLoaderErrorDomain = @"EXUpdatesEmbeddedAppLoader";
@implementation EXUpdatesEmbeddedAppLoader
+ (nullable EXUpdatesUpdate *)embeddedManifestWithConfig:(EXUpdatesConfig *)config
database:(nullable EXUpdatesDatabase *)database
{
static EXUpdatesUpdate *embeddedManifest;
static dispatch_once_t once;
dispatch_once(&once, ^{
if (!config.hasEmbeddedUpdate) {
embeddedManifest = nil;
} else if (!embeddedManifest) {
NSString *path = [[NSBundle mainBundle] pathForResource:EXUpdatesEmbeddedManifestName ofType:EXUpdatesEmbeddedManifestType];
NSData *manifestData = [NSData dataWithContentsOfFile:path];
if (!manifestData) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException
reason:@"The embedded manifest is invalid or could not be read. Make sure you have configured expo-updates correctly in your Xcode Build Phases."
userInfo:@{}];
}
NSError *err;
id manifest = [NSJSONSerialization JSONObjectWithData:manifestData options:kNilOptions error:&err];
if (!manifest) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException
reason:@"The embedded manifest is invalid or could not be read. Make sure you have configured expo-updates correctly in your Xcode Build Phases."
userInfo:@{}];
} else {
NSAssert([manifest isKindOfClass:[NSDictionary class]], @"embedded manifest should be a valid JSON file");
NSMutableDictionary *mutableManifest = [manifest mutableCopy];
// automatically verify embedded manifest since it was already codesigned
mutableManifest[@"isVerified"] = @(YES);
embeddedManifest = [EXUpdatesUpdate updateWithEmbeddedManifest:[mutableManifest copy]
config:config
database:database];
if (!embeddedManifest.updateId) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException
reason:@"The embedded manifest is invalid. Make sure you have configured expo-updates correctly in your Xcode Build Phases."
userInfo:@{}];
}
}
}
});
return embeddedManifest;
}
- (void)loadUpdateFromEmbeddedManifestWithCallback:(EXUpdatesAppLoaderManifestBlock)manifestBlock
success:(EXUpdatesAppLoaderSuccessBlock)success
error:(EXUpdatesAppLoaderErrorBlock)error
{
EXUpdatesUpdate *embeddedManifest = [[self class] embeddedManifestWithConfig:self.config
database:self.database];
if (embeddedManifest) {
self.manifestBlock = manifestBlock;
self.successBlock = success;
self.errorBlock = error;
[self startLoadingFromManifest:embeddedManifest];
} else {
error([NSError errorWithDomain:EXUpdatesEmbeddedAppLoaderErrorDomain
code:1008
userInfo:@{NSLocalizedDescriptionKey: @"Failed to load embedded manifest. Make sure you have configured expo-updates correctly."}]);
}
}
- (void)downloadAsset:(EXUpdatesAsset *)asset
{
NSURL *destinationUrl = [self.directory URLByAppendingPathComponent:asset.filename];
dispatch_async([EXUpdatesFileDownloader assetFilesQueue], ^{
if ([[NSFileManager defaultManager] fileExistsAtPath:[destinationUrl path]]) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self handleAssetDownloadAlreadyExists:asset];
});
} else {
NSAssert(asset.mainBundleFilename, @"embedded asset mainBundleFilename must be nonnull");
NSString *bundlePath = asset.mainBundleDir
? [[NSBundle mainBundle] pathForResource:asset.mainBundleFilename ofType:asset.type inDirectory:asset.mainBundleDir]
: [[NSBundle mainBundle] pathForResource:asset.mainBundleFilename ofType:asset.type];
NSAssert(bundlePath, @"NSBundle must contain the expected assets");
if (!bundlePath) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException
reason:[NSString stringWithFormat:@"Could not find the expected embedded asset %@.%@. Check that expo-updates is installed correctly.", asset.mainBundleFilename, asset.type]
userInfo:nil];
}
NSError *err;
if ([[NSFileManager defaultManager] copyItemAtPath:bundlePath toPath:[destinationUrl path] error:&err]) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self handleAssetDownloadWithData:[NSData dataWithContentsOfFile:bundlePath] response:nil asset:asset];
});
} else {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self handleAssetDownloadWithError:err asset:asset];
});
}
}
});
}
- (void)loadUpdateFromUrl:(NSURL *)url
success:(EXUpdatesAppLoaderSuccessBlock)success
error:(EXUpdatesAppLoaderErrorBlock)error
{
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Should not call EXUpdatesEmbeddedAppLoader#loadUpdateFromUrl" userInfo:nil];
}
@end
NS_ASSUME_NONNULL_END