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#ifdef INCLUDES_VERSIONED_CODE 60 NSDictionary *detachedVersions = _versions[@"detachedNativeVersions"]; 61 if (detachedVersions) { 62 if (!isKernel && detachedVersions[@"shell"]) { 63 // we are in a detached shell scenario, so we always want to leave the shell unprefixed 64 return @""; 65 } 66 if (isKernel && detachedVersions[@"shell"] && detachedVersions[@"kernel"]) { 67 if ([detachedVersions[@"shell"] isEqualToString:detachedVersions[@"kernel"]]) { 68 // kernel version matches shell version, so run them both unprefixed 69 return @""; 70 } else { 71 // kernel needs to run on prefixed code for the given kernel version, continue 72 version = detachedVersions[@"kernel"]; 73 } 74 } 75 } 76 if (version && version.length && ![version isEqualToString:@"UNVERSIONED"]) { 77 return [[@"ABI" stringByAppendingString:version] stringByReplacingOccurrencesOfString:@"." withString:@"_"]; 78 } 79#endif 80 return @""; 81} 82 83- (NSString *)availableSdkVersionForManifest:(EXUpdatesRawManifest * _Nullable)manifest 84{ 85 return [self _versionForManifest:manifest]; 86} 87 88#pragma mark - Internal 89 90- (NSString *)_versionForManifest:(EXUpdatesRawManifest * _Nullable)manifest 91{ 92 if (manifest && manifest.sdkVersion) { 93 NSString *sdkVersion = manifest.sdkVersion; 94 NSArray *sdkVersions = _versions[@"sdkVersions"]; 95 if (sdkVersion && sdkVersions) { 96 for (NSString *availableVersion in sdkVersions) { 97 if ([sdkVersion isEqualToString:availableVersion]) { 98 if (_temporarySdkVersion) { 99 NSArray <NSNumber *>* versionComponents = [availableVersion versionComponents]; 100 BOOL isTemporary = (versionComponents.count > 1 && versionComponents[1].integerValue != 0); 101 if (isTemporary && [availableVersion isEqualToString:_temporarySdkVersion]) { 102 // no prefix if we're just using the current version 103 break; 104 } 105 } 106 return availableVersion; 107 } 108 } 109 } 110 } 111 return @""; 112} 113 114- (void)_loadVersions 115{ 116 NSString *versionsPath = [[NSBundle mainBundle] pathForResource:@"EXSDKVersions" ofType:@"plist"]; 117 NSMutableDictionary *mutableVersions = (versionsPath) ? [NSMutableDictionary dictionaryWithContentsOfFile:versionsPath] : [NSMutableDictionary dictionary]; 118 if (mutableVersions[@"detachedNativeVersions"]) { 119 NSDictionary *detachedNativeVersions = mutableVersions[@"detachedNativeVersions"]; 120 _temporarySdkVersion = detachedNativeVersions[@"shell"]; 121 } else { 122 _temporarySdkVersion = [EXBuildConstants sharedInstance].temporarySdkVersion; 123 } 124 if (!_temporarySdkVersion) { 125 // no temporary sdk version specified in any way, fall back to using the highest version 126 NSArray *sdkVersions = mutableVersions[@"sdkVersions"]; 127 NSUInteger highestVersion = 0; 128 if (sdkVersions) { 129 for (NSString *availableVersion in sdkVersions) { 130 NSArray <NSNumber *>* versionComponents = [availableVersion versionComponents]; 131 if (versionComponents.count > 1 && versionComponents[0].integerValue > highestVersion) { 132 highestVersion = versionComponents[0].integerValue; 133 _temporarySdkVersion = availableVersion; 134 } 135 } 136 } 137 } 138 139 NSAssert((mutableVersions[@"sdkVersions"] != nil), @"No SDK versions are specified for the Expo kernel. Is the project missing EXSDKVersions.plist?"); 140 141 _versions = mutableVersions; 142} 143 144- (BOOL)supportsVersion:(NSString *)sdkVersion { 145#ifdef INCLUDES_VERSIONED_CODE 146 return [_versions[@"sdkVersions"] containsObject:(NSString *) sdkVersion]; 147#else 148 return YES; 149#endif 150} 151 152@end 153