1082815dcSEvan Baconimport { ExpoConfig } from '@expo/config-types'; 2082815dcSEvan Baconimport { XcodeProject } from 'xcode'; 3082815dcSEvan Bacon 4082815dcSEvan Baconimport { InfoPlist } from './IosConfig.types'; 5082815dcSEvan Baconimport { findFirstNativeTarget } from './Target'; 6082815dcSEvan Baconimport { 7082815dcSEvan Bacon ConfigurationSectionEntry, 8082815dcSEvan Bacon getBuildConfigurationsForListId, 9082815dcSEvan Bacon sanitizedName, 10082815dcSEvan Bacon} from './utils/Xcodeproj'; 11*8a424bebSJames Ideimport { ConfigPlugin } from '../Plugin.types'; 12*8a424bebSJames Ideimport { createInfoPlistPluginWithPropertyGuard, withXcodeProject } from '../plugins/ios-plugins'; 13082815dcSEvan Bacon 14082815dcSEvan Baconexport const withDisplayName = createInfoPlistPluginWithPropertyGuard( 15082815dcSEvan Bacon setDisplayName, 16082815dcSEvan Bacon { 17082815dcSEvan Bacon infoPlistProperty: 'CFBundleDisplayName', 18082815dcSEvan Bacon expoConfigProperty: 'name', 19082815dcSEvan Bacon }, 20082815dcSEvan Bacon 'withDisplayName' 21082815dcSEvan Bacon); 22082815dcSEvan Bacon 23082815dcSEvan Baconexport const withName = createInfoPlistPluginWithPropertyGuard( 24082815dcSEvan Bacon setName, 25082815dcSEvan Bacon { 26082815dcSEvan Bacon infoPlistProperty: 'CFBundleName', 27082815dcSEvan Bacon expoConfigProperty: 'name', 28082815dcSEvan Bacon }, 29082815dcSEvan Bacon 'withName' 30082815dcSEvan Bacon); 31082815dcSEvan Bacon 32082815dcSEvan Bacon/** Set the PRODUCT_NAME variable in the xcproj file based on the app.json name property. */ 33082815dcSEvan Baconexport const withProductName: ConfigPlugin = (config) => { 34082815dcSEvan Bacon return withXcodeProject(config, (config) => { 35082815dcSEvan Bacon config.modResults = setProductName(config, config.modResults); 36082815dcSEvan Bacon return config; 37082815dcSEvan Bacon }); 38082815dcSEvan Bacon}; 39082815dcSEvan Bacon 40082815dcSEvan Baconexport function getName(config: Pick<ExpoConfig, 'name'>) { 41082815dcSEvan Bacon return typeof config.name === 'string' ? config.name : null; 42082815dcSEvan Bacon} 43082815dcSEvan Bacon 44082815dcSEvan Bacon/** 45082815dcSEvan Bacon * CFBundleDisplayName is used for most things: the name on the home screen, in 46082815dcSEvan Bacon * notifications, and others. 47082815dcSEvan Bacon */ 48082815dcSEvan Baconexport function setDisplayName( 49082815dcSEvan Bacon configOrName: Pick<ExpoConfig, 'name'> | string, 50082815dcSEvan Bacon { CFBundleDisplayName, ...infoPlist }: InfoPlist 51082815dcSEvan Bacon): InfoPlist { 52082815dcSEvan Bacon let name: string | null = null; 53082815dcSEvan Bacon if (typeof configOrName === 'string') { 54082815dcSEvan Bacon name = configOrName; 55082815dcSEvan Bacon } else { 56082815dcSEvan Bacon name = getName(configOrName); 57082815dcSEvan Bacon } 58082815dcSEvan Bacon 59082815dcSEvan Bacon if (!name) { 60082815dcSEvan Bacon return infoPlist; 61082815dcSEvan Bacon } 62082815dcSEvan Bacon 63082815dcSEvan Bacon return { 64082815dcSEvan Bacon ...infoPlist, 65082815dcSEvan Bacon CFBundleDisplayName: name, 66082815dcSEvan Bacon }; 67082815dcSEvan Bacon} 68082815dcSEvan Bacon 69082815dcSEvan Bacon/** 70082815dcSEvan Bacon * CFBundleName is recommended to be 16 chars or less and is used in lists, eg: 71082815dcSEvan Bacon * sometimes on the App Store 72082815dcSEvan Bacon */ 73082815dcSEvan Baconexport function setName( 74082815dcSEvan Bacon config: Pick<ExpoConfig, 'name'>, 75082815dcSEvan Bacon { CFBundleName, ...infoPlist }: InfoPlist 76082815dcSEvan Bacon): InfoPlist { 77082815dcSEvan Bacon const name = getName(config); 78082815dcSEvan Bacon 79082815dcSEvan Bacon if (!name) { 80082815dcSEvan Bacon return infoPlist; 81082815dcSEvan Bacon } 82082815dcSEvan Bacon 83082815dcSEvan Bacon return { 84082815dcSEvan Bacon ...infoPlist, 85082815dcSEvan Bacon CFBundleName: name, 86082815dcSEvan Bacon }; 87082815dcSEvan Bacon} 88082815dcSEvan Bacon 89082815dcSEvan Baconexport function setProductName( 90082815dcSEvan Bacon config: Pick<ExpoConfig, 'name'>, 91082815dcSEvan Bacon project: XcodeProject 92082815dcSEvan Bacon): XcodeProject { 93082815dcSEvan Bacon const name = sanitizedName(getName(config) ?? ''); 94082815dcSEvan Bacon 95082815dcSEvan Bacon if (!name) { 96082815dcSEvan Bacon return project; 97082815dcSEvan Bacon } 98082815dcSEvan Bacon const quotedName = ensureQuotes(name); 99082815dcSEvan Bacon 100082815dcSEvan Bacon const [, nativeTarget] = findFirstNativeTarget(project); 101082815dcSEvan Bacon 102082815dcSEvan Bacon getBuildConfigurationsForListId(project, nativeTarget.buildConfigurationList).forEach( 103082815dcSEvan Bacon ([, item]: ConfigurationSectionEntry) => { 104082815dcSEvan Bacon item.buildSettings.PRODUCT_NAME = quotedName; 105082815dcSEvan Bacon } 106082815dcSEvan Bacon ); 107082815dcSEvan Bacon 108082815dcSEvan Bacon return project; 109082815dcSEvan Bacon} 110082815dcSEvan Bacon 111082815dcSEvan Baconconst ensureQuotes = (value: string) => { 112082815dcSEvan Bacon if (!value.match(/^['"]/)) { 113082815dcSEvan Bacon return `"${value}"`; 114082815dcSEvan Bacon } 115082815dcSEvan Bacon return value; 116082815dcSEvan Bacon}; 117