1// Copyright 2015-present 650 Industries. All rights reserved. 2 3#import "EXBuildConstants.h" 4#import "EXVersions.h" 5#import "EXKernelUtil.h" 6 7@import EXManifests; 8 9@interface EXVersions () 10 11- (void)_loadVersions; 12 13@end 14 15@implementation NSString (EXVersions) 16 17- (NSArray <NSNumber *>*)versionComponents 18{ 19 NSArray *stringComponents = [self componentsSeparatedByString:@"."]; 20 NSMutableArray <NSNumber *>* components = [NSMutableArray arrayWithCapacity:stringComponents.count]; 21 for (NSString *component in stringComponents) { 22 [components addObject:@([component integerValue])]; 23 } 24 return components; 25} 26 27@end 28 29@implementation EXVersions 30 31+ (nonnull instancetype)sharedInstance 32{ 33 static EXVersions *theVersions; 34 static dispatch_once_t once; 35 dispatch_once(&once, ^{ 36 if (!theVersions) { 37 theVersions = [[EXVersions alloc] init]; 38 } 39 }); 40 return theVersions; 41} 42 43- (instancetype)init 44{ 45 if (self = [super init]) { 46 [self _loadVersions]; 47 } 48 return self; 49} 50 51+ (NSString *)versionedString:(NSString *)string withPrefix:(NSString *)symbolPrefix 52{ 53 if (!string || !symbolPrefix) { 54 return nil; 55 } 56 return [NSString stringWithFormat:@"%@%@", symbolPrefix, string]; 57} 58 59- (NSString *)symbolPrefixForSdkVersion:(NSString *)version isKernel:(BOOL)isKernel 60{ 61#ifdef INCLUDES_VERSIONED_CODE 62 NSDictionary *detachedVersions = _versions[@"detachedNativeVersions"]; 63 if (detachedVersions) { 64 if (!isKernel && detachedVersions[@"shell"]) { 65 // we are in a detached shell scenario, so we always want to leave the shell unprefixed 66 return @""; 67 } 68 if (isKernel && detachedVersions[@"shell"] && detachedVersions[@"kernel"]) { 69 if ([detachedVersions[@"shell"] isEqualToString:detachedVersions[@"kernel"]]) { 70 // kernel version matches shell version, so run them both unprefixed 71 return @""; 72 } else { 73 // kernel needs to run on prefixed code for the given kernel version, continue 74 version = detachedVersions[@"kernel"]; 75 } 76 } 77 } 78 if (version && version.length && ![version isEqualToString:@"UNVERSIONED"]) { 79 return [[@"ABI" stringByAppendingString:version] stringByReplacingOccurrencesOfString:@"." withString:@"_"]; 80 } 81#endif 82 return @""; 83} 84 85- (NSString *)availableSdkVersionForManifest:(EXManifestsManifest * _Nullable)manifest 86{ 87 return [self _versionForManifest:manifest]; 88} 89 90#pragma mark - Internal 91 92- (NSString *)_versionForManifest:(EXManifestsManifest * _Nullable)manifest 93{ 94 if (manifest && manifest.expoGoSDKVersion) { 95 NSString *sdkVersion = manifest.expoGoSDKVersion; 96 NSArray *sdkVersions = _versions[@"sdkVersions"]; 97 if (sdkVersion && sdkVersions) { 98 for (NSString *availableVersion in sdkVersions) { 99 if ([sdkVersion isEqualToString:availableVersion]) { 100 if (_temporarySdkVersion) { 101 NSArray <NSNumber *>* versionComponents = [availableVersion versionComponents]; 102 BOOL isTemporary = (versionComponents.count > 1 && versionComponents[1].integerValue != 0); 103 if (isTemporary && [availableVersion isEqualToString:_temporarySdkVersion]) { 104 // no prefix if we're just using the current version 105 break; 106 } 107 } 108 return availableVersion; 109 } 110 } 111 } 112 } 113 return @""; 114} 115 116- (void)_loadVersions 117{ 118 NSString *versionsPath = [[NSBundle mainBundle] pathForResource:@"EXSDKVersions" ofType:@"plist"]; 119 NSMutableDictionary *mutableVersions = (versionsPath) ? [NSMutableDictionary dictionaryWithContentsOfFile:versionsPath] : [NSMutableDictionary dictionary]; 120 if (mutableVersions[@"detachedNativeVersions"]) { 121 NSDictionary *detachedNativeVersions = mutableVersions[@"detachedNativeVersions"]; 122 _temporarySdkVersion = detachedNativeVersions[@"shell"]; 123 } else { 124 _temporarySdkVersion = [EXBuildConstants sharedInstance].temporarySdkVersion; 125 } 126 if (!_temporarySdkVersion) { 127 // no temporary sdk version specified in any way, fall back to using the highest version 128 NSArray *sdkVersions = mutableVersions[@"sdkVersions"]; 129 NSUInteger highestVersion = 0; 130 if (sdkVersions) { 131 for (NSString *availableVersion in sdkVersions) { 132 NSArray <NSNumber *>* versionComponents = [availableVersion versionComponents]; 133 if (versionComponents.count > 1 && versionComponents[0].integerValue > highestVersion) { 134 highestVersion = versionComponents[0].integerValue; 135 _temporarySdkVersion = availableVersion; 136 } 137 } 138 } 139 } 140 141 NSAssert((mutableVersions[@"sdkVersions"] != nil), @"No SDK versions are specified for the Expo kernel. Is the project missing EXSDKVersions.plist?"); 142 143 _versions = mutableVersions; 144} 145 146- (BOOL)supportsVersion:(NSString *)sdkVersion { 147#ifdef INCLUDES_VERSIONED_CODE 148 return [_versions[@"sdkVersions"] containsObject:(NSString *) sdkVersion]; 149#else 150 return YES; 151#endif 152} 153 154@end 155