1082815dcSEvan Baconimport { ExpoConfig } from '@expo/config-types'; 2082815dcSEvan Baconimport { JSONObject } from '@expo/json-file'; 3082815dcSEvan Baconimport fs from 'fs'; 4082815dcSEvan Baconimport path from 'path'; 5082815dcSEvan Baconimport slash from 'slash'; 6082815dcSEvan Baconimport { XCBuildConfiguration } from 'xcode'; 7082815dcSEvan Bacon 8082815dcSEvan Baconimport { findFirstNativeTarget, getXCBuildConfigurationFromPbxproj } from './Target'; 9082815dcSEvan Baconimport { 10082815dcSEvan Bacon getBuildConfigurationsForListId, 11082815dcSEvan Bacon getPbxproj, 12082815dcSEvan Bacon getProductName, 13082815dcSEvan Bacon getProjectName, 14082815dcSEvan Bacon} from './utils/Xcodeproj'; 15082815dcSEvan Baconimport { trimQuotes } from './utils/string'; 16*8a424bebSJames Ideimport { createEntitlementsPlugin } from '../plugins/ios-plugins'; 17082815dcSEvan Bacon 18082815dcSEvan Baconexport const withAssociatedDomains = createEntitlementsPlugin( 19082815dcSEvan Bacon setAssociatedDomains, 20082815dcSEvan Bacon 'withAssociatedDomains' 21082815dcSEvan Bacon); 22082815dcSEvan Bacon 23082815dcSEvan Baconexport function setAssociatedDomains( 24082815dcSEvan Bacon config: ExpoConfig, 25082815dcSEvan Bacon { 'com.apple.developer.associated-domains': _, ...entitlementsPlist }: JSONObject 26082815dcSEvan Bacon): JSONObject { 27082815dcSEvan Bacon if (config.ios?.associatedDomains) { 28082815dcSEvan Bacon return { 29082815dcSEvan Bacon ...entitlementsPlist, 30082815dcSEvan Bacon 'com.apple.developer.associated-domains': config.ios.associatedDomains, 31082815dcSEvan Bacon }; 32082815dcSEvan Bacon } 33082815dcSEvan Bacon 34082815dcSEvan Bacon return entitlementsPlist; 35082815dcSEvan Bacon} 36082815dcSEvan Bacon 37082815dcSEvan Baconexport function getEntitlementsPath( 38082815dcSEvan Bacon projectRoot: string, 39082815dcSEvan Bacon { 40082815dcSEvan Bacon targetName, 41082815dcSEvan Bacon buildConfiguration = 'Release', 42082815dcSEvan Bacon }: { targetName?: string; buildConfiguration?: string } = {} 43082815dcSEvan Bacon): string | null { 44082815dcSEvan Bacon const project = getPbxproj(projectRoot); 45082815dcSEvan Bacon const xcBuildConfiguration = getXCBuildConfigurationFromPbxproj(project, { 46082815dcSEvan Bacon targetName, 47082815dcSEvan Bacon buildConfiguration, 48082815dcSEvan Bacon }); 49082815dcSEvan Bacon if (!xcBuildConfiguration) { 50082815dcSEvan Bacon return null; 51082815dcSEvan Bacon } 52082815dcSEvan Bacon const entitlementsPath = getEntitlementsPathFromBuildConfiguration( 53082815dcSEvan Bacon projectRoot, 54082815dcSEvan Bacon xcBuildConfiguration 55082815dcSEvan Bacon ); 56082815dcSEvan Bacon return entitlementsPath && fs.existsSync(entitlementsPath) ? entitlementsPath : null; 57082815dcSEvan Bacon} 58082815dcSEvan Bacon 59082815dcSEvan Baconfunction getEntitlementsPathFromBuildConfiguration( 60082815dcSEvan Bacon projectRoot: string, 61082815dcSEvan Bacon xcBuildConfiguration: XCBuildConfiguration 62082815dcSEvan Bacon): string | null { 63082815dcSEvan Bacon const entitlementsPathRaw = xcBuildConfiguration?.buildSettings?.CODE_SIGN_ENTITLEMENTS as 64082815dcSEvan Bacon | string 65082815dcSEvan Bacon | undefined; 66082815dcSEvan Bacon if (entitlementsPathRaw) { 67082815dcSEvan Bacon return path.normalize(path.join(projectRoot, 'ios', trimQuotes(entitlementsPathRaw))); 68082815dcSEvan Bacon } else { 69082815dcSEvan Bacon return null; 70082815dcSEvan Bacon } 71082815dcSEvan Bacon} 72082815dcSEvan Bacon 73082815dcSEvan Baconexport function ensureApplicationTargetEntitlementsFileConfigured(projectRoot: string): void { 74082815dcSEvan Bacon const project = getPbxproj(projectRoot); 75082815dcSEvan Bacon const projectName = getProjectName(projectRoot); 76082815dcSEvan Bacon const productName = getProductName(project); 77082815dcSEvan Bacon 78082815dcSEvan Bacon const [, applicationTarget] = findFirstNativeTarget(project); 79082815dcSEvan Bacon const buildConfigurations = getBuildConfigurationsForListId( 80082815dcSEvan Bacon project, 81082815dcSEvan Bacon applicationTarget.buildConfigurationList 82082815dcSEvan Bacon ); 83082815dcSEvan Bacon let hasChangesToWrite = false; 84082815dcSEvan Bacon for (const [, xcBuildConfiguration] of buildConfigurations) { 85082815dcSEvan Bacon const oldEntitlementPath = getEntitlementsPathFromBuildConfiguration( 86082815dcSEvan Bacon projectRoot, 87082815dcSEvan Bacon xcBuildConfiguration 88082815dcSEvan Bacon ); 89082815dcSEvan Bacon if (oldEntitlementPath && fs.existsSync(oldEntitlementPath)) { 90082815dcSEvan Bacon return; 91082815dcSEvan Bacon } 92082815dcSEvan Bacon hasChangesToWrite = true; 93082815dcSEvan Bacon // Use posix formatted path, even on Windows 94082815dcSEvan Bacon const entitlementsRelativePath = slash(path.join(projectName, `${productName}.entitlements`)); 95082815dcSEvan Bacon const entitlementsPath = path.normalize( 96082815dcSEvan Bacon path.join(projectRoot, 'ios', entitlementsRelativePath) 97082815dcSEvan Bacon ); 98082815dcSEvan Bacon fs.mkdirSync(path.dirname(entitlementsPath), { recursive: true }); 99082815dcSEvan Bacon if (!fs.existsSync(entitlementsPath)) { 100082815dcSEvan Bacon fs.writeFileSync(entitlementsPath, ENTITLEMENTS_TEMPLATE); 101082815dcSEvan Bacon } 102082815dcSEvan Bacon xcBuildConfiguration.buildSettings.CODE_SIGN_ENTITLEMENTS = entitlementsRelativePath; 103082815dcSEvan Bacon } 104082815dcSEvan Bacon if (hasChangesToWrite) { 105082815dcSEvan Bacon fs.writeFileSync(project.filepath, project.writeSync()); 106082815dcSEvan Bacon } 107082815dcSEvan Bacon} 108082815dcSEvan Bacon 109082815dcSEvan Baconconst ENTITLEMENTS_TEMPLATE = ` 110082815dcSEvan Bacon<?xml version="1.0" encoding="UTF-8"?> 111082815dcSEvan Bacon<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 112082815dcSEvan Bacon<plist version="1.0"> 113082815dcSEvan Bacon<dict> 114082815dcSEvan Bacon</dict> 115082815dcSEvan Bacon</plist> 116082815dcSEvan Bacon`; 117