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