1import { ExpoConfig } from '@expo/config-types'; 2import { XcodeProject } from 'xcode'; 3 4import { ConfigPlugin } from '../Plugin.types'; 5import { withXcodeProject } from '../plugins/ios-plugins'; 6import { addWarningIOS } from '../utils/warnings'; 7import { isNotComment } from './utils/Xcodeproj'; 8 9type Bitcode = NonNullable<ExpoConfig['ios']>['bitcode']; 10 11/** 12 * Plugin to set a bitcode preference for the Xcode project 13 * based on the project's Expo config `ios.bitcode` value. 14 */ 15export const withBitcode: ConfigPlugin = (config) => { 16 return withXcodeProject(config, async (config) => { 17 config.modResults = await setBitcodeWithConfig(config, { 18 project: config.modResults, 19 }); 20 return config; 21 }); 22}; 23 24/** 25 * Plugin to set a custom bitcode preference for the Xcode project. 26 * Does not read from the Expo config `ios.bitcode`. 27 * 28 * @param bitcode custom bitcode setting. 29 */ 30export const withCustomBitcode: ConfigPlugin<Bitcode> = (config, bitcode) => { 31 return withXcodeProject(config, async (config) => { 32 config.modResults = await setBitcode(bitcode, { 33 project: config.modResults, 34 }); 35 return config; 36 }); 37}; 38 39/** 40 * Get the bitcode preference from the Expo config. 41 */ 42export function getBitcode(config: Pick<ExpoConfig, 'ios'>): Bitcode { 43 return config.ios?.bitcode; 44} 45 46/** 47 * Enable or disable the `ENABLE_BITCODE` property of the project configurations. 48 */ 49export function setBitcodeWithConfig( 50 config: Pick<ExpoConfig, 'ios'>, 51 { project }: { project: XcodeProject } 52): XcodeProject { 53 const bitcode = getBitcode(config); 54 return setBitcode(bitcode, { project }); 55} 56 57/** 58 * Enable or disable the `ENABLE_BITCODE` property. 59 */ 60export function setBitcode(bitcode: Bitcode, { project }: { project: XcodeProject }): XcodeProject { 61 const isDefaultBehavior = bitcode == null; 62 // If the value is undefined, then do nothing. 63 if (isDefaultBehavior) { 64 return project; 65 } 66 67 const targetName = typeof bitcode === 'string' ? bitcode : undefined; 68 const isBitcodeEnabled = !!bitcode; 69 if (targetName) { 70 // Assert if missing 71 const configs = Object.entries(project.pbxXCBuildConfigurationSection()).filter(isNotComment); 72 const hasConfiguration = configs.find(([, configuration]) => configuration.name === targetName); 73 if (hasConfiguration) { 74 // If targetName is defined then disable bitcode everywhere. 75 project.addBuildProperty('ENABLE_BITCODE', 'NO'); 76 } else { 77 const names = [ 78 // Remove duplicates, wrap in double quotes, and sort alphabetically. 79 ...new Set(configs.map(([, configuration]) => `"${configuration.name}"`)), 80 ].sort(); 81 addWarningIOS( 82 'ios.bitcode', 83 `No configuration named "${targetName}". Expected one of: ${names.join(', ')}.` 84 ); 85 } 86 } 87 88 project.addBuildProperty('ENABLE_BITCODE', isBitcodeEnabled ? 'YES' : 'NO', targetName); 89 90 return project; 91} 92