xref: /expo/ios/Client/EXHomeAppManager.m (revision 19a0af8d)
1
2#import "EXBuildConstants.h"
3#import "EXHomeAppManager.h"
4#import "EXKernel.h"
5#import "EXAppFetcher.h"
6#import "EXAbstractLoader.h"
7#import "EXKernelLinkingManager.h"
8#import "EXHomeModule.h"
9#import "EXKernelUtil.h"
10#import "EXLog.h"
11#import "ExpoKit.h"
12#import "EXReactAppExceptionHandler.h"
13#import "EXReactAppManager+Private.h"
14#import "EXVersionManagerObjC.h"
15#import "EXVersions.h"
16#import "EXEmbeddedHomeLoader.h"
17
18#import <EXConstants/EXConstantsService.h>
19
20#import <React/RCTUtils.h>
21#import <React/RCTBridge.h>
22
23#if defined(EX_DETACHED)
24#import "ExpoKit-Swift.h"
25#else
26#import "Expo_Go-Swift.h"
27#endif // defined(EX_DETACHED)
28
29#import <ExpoModulesCore/EXModuleRegistryProvider.h>
30
31@import EXManifests;
32@import EXUpdates;
33
34NSString * const kEXHomeLaunchUrlDefaultsKey = @"EXKernelLaunchUrlDefaultsKey";
35
36@implementation EXHomeAppManager
37
38- (NSDictionary *)extraParams
39{
40  NSMutableDictionary *params = [@{
41    @"browserModuleClass": [EXHomeModule class],
42    @"constants": @{
43        @"expoRuntimeVersion": [EXBuildConstants sharedInstance].expoRuntimeVersion,
44        @"linkingUri": @"exp://",
45        @"experienceUrl": [@"exp://" stringByAppendingString:(self.appRecord.appLoader.manifest.hostUri ?: @"")],
46        @"manifest": self.appRecord.appLoader.manifest.rawManifestJSON,
47        @"executionEnvironment": EXConstantsExecutionEnvironmentStoreClient,
48        @"appOwnership": @"expo",
49        @"supportedExpoSdks": [EXVersions sharedInstance].versions[@"sdkVersions"],
50    },
51    @"exceptionsManagerDelegate": self.exceptionHandler,
52    @"isDeveloper": @([EXBuildConstants sharedInstance].isDevKernel),
53    @"isStandardDevMenuAllowed": @(YES), // kernel enables traditional RN dev menu
54    @"manifest": self.appRecord.appLoader.manifest.rawManifestJSON,
55    @"services": [EXKernel sharedInstance].serviceRegistry.allServices,
56    @"singletonModules": [EXModuleRegistryProvider singletonModules],
57    @"fileSystemDirectories": @{
58        @"documentDirectory": [self scopedDocumentDirectory],
59        @"cachesDirectory": [self scopedCachesDirectory]
60    }
61  } mutableCopy];
62
63  NSURL *initialHomeUrl = [self _initialHomeUrl];
64  if (initialHomeUrl) {
65    params[@"initialUri"] = initialHomeUrl;
66  }
67  return params;
68}
69
70#pragma mark - interfacing with home JS
71
72- (void)addHistoryItemWithUrl:(NSURL *)manifestUrl manifest:(EXManifestsManifest *)manifest
73{
74  if (!manifest || !manifestUrl || [manifest.legacyId isEqualToString:@"@exponent/home"]) {
75    return;
76  }
77  NSDictionary *params = @{
78    @"manifestUrl": manifestUrl.absoluteString,
79    @"manifest": manifest.rawManifestJSON,
80  };
81  [self _dispatchHomeJSEvent:@"addHistoryItem" body:params onSuccess:nil onFailure:nil];
82}
83
84- (void)getHistoryUrlForScopeKey:(NSString *)scopeKey completion:(void (^)(NSString *))completion
85{
86  [self _dispatchHomeJSEvent:@"getHistoryUrlForExperienceId"
87                        body:@{ @"experienceId": scopeKey }
88                   onSuccess:^(NSDictionary *result) {
89                     NSString *url = result[@"url"];
90                     completion(url);
91                   } onFailure:^(NSString *errorMessage) {
92                     completion(nil);
93                   }];
94}
95
96- (void)showQRReader
97{
98  [self _dispatchHomeJSEvent:@"showQRReader" body:@{} onSuccess:nil onFailure:nil];
99}
100
101#pragma mark - EXReactAppManager
102
103- (NSArray *)extraModulesForBridge:(RCTBridge *)bridge
104{
105  NSMutableArray *modules = [NSMutableArray array];
106
107  [modules addObjectsFromArray:[self.versionManager extraModulesForBridge:bridge]];
108
109  return modules;
110}
111
112- (void)computeVersionSymbolPrefix
113{
114  self.validatedVersion = nil;
115  self.versionSymbolPrefix = [[EXVersions sharedInstance] symbolPrefixForSdkVersion:self.validatedVersion isKernel:YES];
116}
117
118- (RCTLogFunction)logFunction
119{
120  return EXGetKernelRCTLogFunction();
121}
122
123- (RCTLogLevel)logLevel
124{
125  return RCTLogLevelWarning;
126}
127
128- (NSDictionary *)launchOptionsForBridge
129{
130  if (!self.hasBridgeEverLoaded) {
131    return [ExpoKit sharedInstance].launchOptions;
132  } else {
133    // don't want to re-consume launch options when the bridge reloads.
134    return nil;
135  }
136}
137
138- (NSString *)bundleResourceNameForAppFetcher:(__unused EXAppFetcher *)appFetcher withManifest:(nonnull __unused EXManifestsManifest *)manifest
139{
140  return kEXHomeBundleResourceName;
141}
142
143#pragma mark - util
144
145- (void)_dispatchHomeJSEvent:(NSString *)eventName body:(NSDictionary *)eventBody onSuccess:(void (^_Nullable)(NSDictionary * _Nullable))success onFailure:(void (^_Nullable)(NSString * _Nullable))failure
146{
147  EXHomeModule *homeModule = [[EXKernel sharedInstance] nativeModuleForAppManager:self named:@"ExponentKernel"];
148  if (homeModule) {
149    [homeModule dispatchJSEvent:eventName body:eventBody onSuccess:success onFailure:failure];
150  } else {
151    if (failure) {
152      failure(nil);
153    }
154  }
155}
156
157- (NSURL *)_initialHomeUrl
158{
159  // used by appetize - override the kernel initial url if there's something in NSUserDefaults
160  NSURL *initialHomeUrl;
161  NSString *kernelInitialUrlDefaultsValue = [[NSUserDefaults standardUserDefaults] stringForKey:kEXHomeLaunchUrlDefaultsKey];
162  if (kernelInitialUrlDefaultsValue) {
163    initialHomeUrl = [NSURL URLWithString:kernelInitialUrlDefaultsValue];
164    [[NSUserDefaults standardUserDefaults] removeObjectForKey:kEXHomeLaunchUrlDefaultsKey];
165    [[NSUserDefaults standardUserDefaults] synchronize];
166  } else {
167    initialHomeUrl = [EXKernelLinkingManager initialUrlFromLaunchOptions:[self launchOptionsForBridge]];
168  }
169  return initialHomeUrl;
170}
171
172- (BOOL)requiresValidManifests
173{
174  // running home
175  return NO;
176}
177
178@end
179