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