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