1// Copyright 2015-present 650 Industries. All rights reserved. 2 3#import "EXAbstractLoader+Updates.h" 4#import "EXKernel.h" 5#import "EXKernelAppRecord.h" 6#import "EXReactAppManager.h" 7#import "EXUpdatesDatabaseManager.h" 8#import "EXUpdatesManager.h" 9 10#import <EXUpdates/EXUpdatesFileDownloader.h> 11#import <EXUpdates/EXUpdatesRemoteAppLoader.h> 12 13#import <React/RCTBridge.h> 14 15@import EXManifests; 16 17NSString * const EXUpdatesEventName = @"Expo.nativeUpdatesEvent"; 18NSString * const EXUpdatesErrorEventType = @"error"; 19NSString * const EXUpdatesUpdateAvailableEventType = @"updateAvailable"; 20NSString * const EXUpdatesNotAvailableEventType = @"noUpdateAvailable"; 21 22@implementation EXUpdatesManager 23 24- (void)notifyApp:(EXKernelAppRecord *)appRecord 25ofDownloadWithManifest:(EXManifestsManifest * _Nullable)manifest 26 isNew:(BOOL)isBundleNew 27 error:(NSError * _Nullable)error; 28{ 29 NSDictionary *body; 30 if (error) { 31 body = @{ 32 @"type": EXUpdatesErrorEventType, 33 @"message": error.localizedDescription 34 }; 35 } else if (isBundleNew) { 36 // prevent a crash, but this shouldn't ever happen 37 NSDictionary *rawManifestJSON = manifest ? manifest.rawManifestJSON : @{}; 38 body = @{ 39 @"type": EXUpdatesUpdateAvailableEventType, 40 @"manifest": rawManifestJSON 41 }; 42 } else { 43 body = @{ 44 @"type": EXUpdatesNotAvailableEventType 45 }; 46 } 47 RCTBridge *bridge = appRecord.appManager.reactBridge; 48 if (appRecord.status == kEXKernelAppRecordStatusRunning) { 49 [bridge enqueueJSCall:@"RCTDeviceEventEmitter.emit" args:@[EXUpdatesEventName, body]]; 50 } 51} 52 53# pragma mark - internal 54 55- (EXAbstractLoader *)_appLoaderWithScopeKey:(NSString *)scopeKey 56{ 57 EXKernelAppRecord *appRecord = [[EXKernel sharedInstance].appRegistry newestRecordWithScopeKey:scopeKey]; 58 return appRecord.appLoader; 59} 60 61# pragma mark - EXUpdatesBindingDelegate 62 63- (EXUpdatesConfig *)configForScopeKey:(NSString *)scopeKey 64{ 65 return [self _appLoaderWithScopeKey:scopeKey].config; 66} 67 68- (EXUpdatesSelectionPolicy *)selectionPolicyForScopeKey:(NSString *)scopeKey 69{ 70 return [self _appLoaderWithScopeKey:scopeKey].selectionPolicy; 71} 72 73- (nullable EXUpdatesUpdate *)launchedUpdateForScopeKey:(NSString *)scopeKey 74{ 75 return [self _appLoaderWithScopeKey:scopeKey].appLauncher.launchedUpdate; 76} 77 78- (nullable NSDictionary *)assetFilesMapForScopeKey:(NSString *)scopeKey 79{ 80 return [self _appLoaderWithScopeKey:scopeKey].appLauncher.assetFilesMap; 81} 82 83- (BOOL)isUsingEmbeddedAssetsForScopeKey:(NSString *)scopeKey 84{ 85 return NO; 86} 87 88- (BOOL)isStartedForScopeKey:(NSString *)scopeKey 89{ 90 return [self _appLoaderWithScopeKey:scopeKey].appLauncher != nil; 91} 92 93- (BOOL)isEmergencyLaunchForScopeKey:(NSString *)scopeKey 94{ 95 return [self _appLoaderWithScopeKey:scopeKey].isEmergencyLaunch; 96} 97 98- (void)requestRelaunchForScopeKey:(NSString *)scopeKey withCompletion:(EXUpdatesAppRelaunchCompletionBlock)completion 99{ 100 [[EXKernel sharedInstance] reloadAppFromCacheWithScopeKey:scopeKey]; 101 completion(YES); 102} 103 104@end 105