1import { ExpoConfig } from '@expo/config-types'; 2import plist from '@expo/plist'; 3import assert from 'assert'; 4import fs from 'fs'; 5import path from 'path'; 6import { XcodeProject } from 'xcode'; 7 8import { InfoPlist } from './IosConfig.types'; 9import { getSourceRoot } from './Paths'; 10import { appendScheme } from './Scheme'; 11import { addResourceFileToGroup, getProjectName } from './utils/Xcodeproj'; 12import { ConfigPlugin, ModProps } from '../Plugin.types'; 13import { withInfoPlist, withXcodeProject } from '../plugins/ios-plugins'; 14 15export const withGoogle: ConfigPlugin = (config) => { 16 return withInfoPlist(config, (config) => { 17 config.modResults = setGoogleConfig(config, config.modResults, config.modRequest); 18 return config; 19 }); 20}; 21 22export const withGoogleServicesFile: ConfigPlugin = (config) => { 23 return withXcodeProject(config, (config) => { 24 config.modResults = setGoogleServicesFile(config, { 25 projectRoot: config.modRequest.projectRoot, 26 project: config.modResults, 27 }); 28 return config; 29 }); 30}; 31 32function readGoogleServicesInfoPlist( 33 relativePath: string, 34 { projectRoot }: { projectRoot: string } 35) { 36 const googleServiceFilePath = path.resolve(projectRoot, relativePath); 37 const contents = fs.readFileSync(googleServiceFilePath, 'utf8'); 38 assert(contents, 'GoogleService-Info.plist is empty'); 39 return plist.parse(contents); 40} 41 42export function getGoogleSignInReversedClientId( 43 config: Pick<ExpoConfig, 'ios'>, 44 modRequest: Pick<ModProps<InfoPlist>, 'projectRoot'> 45): string | null { 46 const googleServicesFileRelativePath = getGoogleServicesFile(config); 47 if (googleServicesFileRelativePath === null) { 48 return null; 49 } 50 51 const infoPlist = readGoogleServicesInfoPlist(googleServicesFileRelativePath, modRequest); 52 53 return infoPlist.REVERSED_CLIENT_ID ?? null; 54} 55 56export function getGoogleServicesFile(config: Pick<ExpoConfig, 'ios'>) { 57 return config.ios?.googleServicesFile ?? null; 58} 59 60export function setGoogleSignInReversedClientId( 61 config: Pick<ExpoConfig, 'ios'>, 62 infoPlist: InfoPlist, 63 modRequest: Pick<ModProps<InfoPlist>, 'projectRoot'> 64): InfoPlist { 65 const reversedClientId = getGoogleSignInReversedClientId(config, modRequest); 66 67 if (reversedClientId === null) { 68 return infoPlist; 69 } 70 71 return appendScheme(reversedClientId, infoPlist); 72} 73 74export function setGoogleConfig( 75 config: Pick<ExpoConfig, 'ios'>, 76 infoPlist: InfoPlist, 77 modRequest: ModProps<InfoPlist> 78): InfoPlist { 79 infoPlist = setGoogleSignInReversedClientId(config, infoPlist, modRequest); 80 return infoPlist; 81} 82 83export function setGoogleServicesFile( 84 config: Pick<ExpoConfig, 'ios'>, 85 { projectRoot, project }: { project: XcodeProject; projectRoot: string } 86): XcodeProject { 87 const googleServicesFileRelativePath = getGoogleServicesFile(config); 88 if (googleServicesFileRelativePath === null) { 89 return project; 90 } 91 92 const googleServiceFilePath = path.resolve(projectRoot, googleServicesFileRelativePath); 93 fs.copyFileSync( 94 googleServiceFilePath, 95 path.join(getSourceRoot(projectRoot), 'GoogleService-Info.plist') 96 ); 97 98 const projectName = getProjectName(projectRoot); 99 const plistFilePath = `${projectName}/GoogleService-Info.plist`; 100 if (!project.hasFile(plistFilePath)) { 101 project = addResourceFileToGroup({ 102 filepath: plistFilePath, 103 groupName: projectName, 104 project, 105 isBuildFile: true, 106 verbose: true, 107 }); 108 } 109 return project; 110} 111