1 2#import "EXBuildConstants.h" 3#import "EXHomeAppManager.h" 4#import "EXKernel.h" 5#import "EXAppFetcher.h" 6#import "EXAppLoader.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 "EXVersionManager.h" 15#import "EXVersions.h" 16 17#import <EXConstants/EXConstantsService.h> 18#import <EXUpdates/EXUpdatesUpdate.h> 19 20#import <React/RCTUtils.h> 21#import <React/RCTBridge.h> 22 23#import <UMCore/UMModuleRegistryProvider.h> 24 25NSString * const kEXHomeLaunchUrlDefaultsKey = @"EXKernelLaunchUrlDefaultsKey"; 26NSString *kEXHomeBundleResourceName = @"kernel.ios"; 27NSString *kEXHomeManifestResourceName = @"kernel-manifest"; 28 29@implementation EXHomeAppManager 30 31- (NSDictionary *)extraParams 32{ 33 NSMutableDictionary *params = [@{ 34 @"browserModuleClass": [EXHomeModule class], 35 @"constants": @{ 36 @"expoRuntimeVersion": [EXBuildConstants sharedInstance].expoRuntimeVersion, 37 @"linkingUri": @"exp://", 38 @"experienceUrl": [@"exp://" stringByAppendingString:self.appRecord.appLoader.manifest.hostUri], 39 @"manifest": self.appRecord.appLoader.manifest.rawManifestJSON, 40 @"executionEnvironment": EXConstantsExecutionEnvironmentStoreClient, 41 @"appOwnership": @"expo", 42 @"supportedExpoSdks": [EXVersions sharedInstance].versions[@"sdkVersions"], 43 }, 44 @"exceptionsManagerDelegate": self.exceptionHandler, 45 @"isDeveloper": @([EXBuildConstants sharedInstance].isDevKernel), 46 @"isStandardDevMenuAllowed": @(YES), // kernel enables traditional RN dev menu 47 @"manifest": self.appRecord.appLoader.manifest.rawManifestJSON, 48 @"services": [EXKernel sharedInstance].serviceRegistry.allServices, 49 @"singletonModules": [UMModuleRegistryProvider singletonModules], 50 @"fileSystemDirectories": @{ 51 @"documentDirectory": [self scopedDocumentDirectory], 52 @"cachesDirectory": [self scopedCachesDirectory] 53 } 54 } mutableCopy]; 55 56 NSURL *initialHomeUrl = [self _initialHomeUrl]; 57 if (initialHomeUrl) { 58 params[@"initialUri"] = initialHomeUrl; 59 } 60 return params; 61} 62 63#pragma mark - interfacing with home JS 64 65- (void)addHistoryItemWithUrl:(NSURL *)manifestUrl manifest:(EXUpdatesRawManifest *)manifest 66{ 67 if (!manifest || !manifestUrl || [manifest.rawID isEqualToString:@"@exponent/home"]) { 68 return; 69 } 70 NSDictionary *params = @{ 71 @"manifestUrl": manifestUrl.absoluteString, 72 @"manifest": manifest.rawManifestJSON, 73 }; 74 [self _dispatchHomeJSEvent:@"addHistoryItem" body:params onSuccess:nil onFailure:nil]; 75} 76 77- (void)getHistoryUrlForExperienceId:(NSString *)experienceId completion:(void (^)(NSString *))completion 78{ 79 [self _dispatchHomeJSEvent:@"getHistoryUrlForExperienceId" 80 body:@{ @"experienceId": experienceId } 81 onSuccess:^(NSDictionary *result) { 82 NSString *url = result[@"url"]; 83 completion(url); 84 } onFailure:^(NSString *errorMessage) { 85 completion(nil); 86 }]; 87} 88 89- (void)showQRReader 90{ 91 [self _dispatchHomeJSEvent:@"showQRReader" body:@{} onSuccess:nil onFailure:nil]; 92} 93 94#pragma mark - EXReactAppManager 95 96- (NSArray *)extraModulesForBridge:(RCTBridge *)bridge 97{ 98 NSMutableArray *modules = [NSMutableArray array]; 99 100 [modules addObjectsFromArray:[self.versionManager extraModulesForBridge:bridge]]; 101 102 return modules; 103} 104 105- (void)computeVersionSymbolPrefix 106{ 107 self.validatedVersion = nil; 108 self.versionSymbolPrefix = [[EXVersions sharedInstance] symbolPrefixForSdkVersion:self.validatedVersion isKernel:YES]; 109} 110 111- (RCTLogFunction)logFunction 112{ 113 return EXGetKernelRCTLogFunction(); 114} 115 116- (RCTLogLevel)logLevel 117{ 118 return RCTLogLevelWarning; 119} 120 121- (NSDictionary *)launchOptionsForBridge 122{ 123 if (!self.hasBridgeEverLoaded) { 124 return [ExpoKit sharedInstance].launchOptions; 125 } else { 126 // don't want to re-consume launch options when the bridge reloads. 127 return nil; 128 } 129} 130 131- (NSString *)bundleResourceNameForAppFetcher:(__unused EXAppFetcher *)appFetcher withManifest:(nonnull __unused EXUpdatesRawManifest *)manifest 132{ 133 return kEXHomeBundleResourceName; 134} 135 136#pragma mark - util 137 138- (void)_dispatchHomeJSEvent:(NSString *)eventName body:(NSDictionary *)eventBody onSuccess:(void (^_Nullable)(NSDictionary * _Nullable))success onFailure:(void (^_Nullable)(NSString * _Nullable))failure 139{ 140 EXHomeModule *homeModule = [[EXKernel sharedInstance] nativeModuleForAppManager:self named:@"ExponentKernel"]; 141 if (homeModule) { 142 [homeModule dispatchJSEvent:eventName body:eventBody onSuccess:success onFailure:failure]; 143 } else { 144 if (failure) { 145 failure(nil); 146 } 147 } 148} 149 150- (NSURL *)_initialHomeUrl 151{ 152 // used by appetize - override the kernel initial url if there's something in NSUserDefaults 153 NSURL *initialHomeUrl; 154 NSString *kernelInitialUrlDefaultsValue = [[NSUserDefaults standardUserDefaults] stringForKey:kEXHomeLaunchUrlDefaultsKey]; 155 if (kernelInitialUrlDefaultsValue) { 156 initialHomeUrl = [NSURL URLWithString:kernelInitialUrlDefaultsValue]; 157 [[NSUserDefaults standardUserDefaults] removeObjectForKey:kEXHomeLaunchUrlDefaultsKey]; 158 [[NSUserDefaults standardUserDefaults] synchronize]; 159 } else { 160 initialHomeUrl = [EXKernelLinkingManager initialUrlFromLaunchOptions:[self launchOptionsForBridge]]; 161 } 162 return initialHomeUrl; 163} 164 165+ (EXUpdatesRawManifest * _Nullable)bundledHomeManifest 166{ 167 NSString *manifestJson = nil; 168 BOOL usesNSBundleManifest = NO; 169 170 // if developing, use development manifest from EXBuildConstants 171 if ([EXBuildConstants sharedInstance].isDevKernel) { 172 manifestJson = [EXBuildConstants sharedInstance].kernelManifestJsonString; 173 } 174 175 // otherwise use published manifest 176 if (!manifestJson) { 177 NSString *manifestPath = [[NSBundle mainBundle] pathForResource:kEXHomeManifestResourceName ofType:@"json"]; 178 if (manifestPath) { 179 NSError *error; 180 usesNSBundleManifest = YES; 181 manifestJson = [NSString stringWithContentsOfFile:manifestPath encoding:NSUTF8StringEncoding error:&error]; 182 if (error) { 183 manifestJson = nil; 184 } 185 } 186 } 187 188 if (manifestJson) { 189 id manifest = RCTJSONParse(manifestJson, nil); 190 if ([manifest isKindOfClass:[NSDictionary class]]) { 191 if (usesNSBundleManifest && ![manifest[@"id"] isEqualToString:@"@exponent/home"]) { 192 DDLogError(@"Bundled kernel manifest was published with an id other than @exponent/home"); 193 } 194 return [EXUpdatesUpdate rawManifestForJSON:manifest]; 195 } 196 } 197 return nil; 198} 199 200- (BOOL)requiresValidManifests 201{ 202 // running home 203 return NO; 204} 205 206@end 207