1*082815dcSEvan Baconimport { ExpoConfig } from '@expo/config-types'; 2*082815dcSEvan Baconimport path from 'path'; 3*082815dcSEvan Bacon 4*082815dcSEvan Baconimport { ConfigPlugin } from '../Plugin.types'; 5*082815dcSEvan Baconimport { withAppBuildGradle, withProjectBuildGradle } from '../plugins/android-plugins'; 6*082815dcSEvan Baconimport { withDangerousMod } from '../plugins/withDangerousMod'; 7*082815dcSEvan Baconimport { copyFilePathToPathAsync } from '../utils/fs'; 8*082815dcSEvan Baconimport { addWarningAndroid } from '../utils/warnings'; 9*082815dcSEvan Bacon 10*082815dcSEvan Baconconst DEFAULT_TARGET_PATH = './android/app/google-services.json'; 11*082815dcSEvan Bacon 12*082815dcSEvan Baconconst googleServicesClassPath = 'com.google.gms:google-services'; 13*082815dcSEvan Baconconst googleServicesPlugin = 'com.google.gms.google-services'; 14*082815dcSEvan Bacon 15*082815dcSEvan Bacon// NOTE(brentvatne): This may be annoying to keep up to date... 16*082815dcSEvan Baconconst googleServicesVersion = '4.3.3'; 17*082815dcSEvan Bacon 18*082815dcSEvan Baconexport const withClassPath: ConfigPlugin = (config) => { 19*082815dcSEvan Bacon return withProjectBuildGradle(config, (config) => { 20*082815dcSEvan Bacon if (config.modResults.language === 'groovy') { 21*082815dcSEvan Bacon config.modResults.contents = setClassPath(config, config.modResults.contents); 22*082815dcSEvan Bacon } else { 23*082815dcSEvan Bacon addWarningAndroid( 24*082815dcSEvan Bacon 'android.googleServicesFile', 25*082815dcSEvan Bacon `Cannot automatically configure project build.gradle if it's not groovy` 26*082815dcSEvan Bacon ); 27*082815dcSEvan Bacon } 28*082815dcSEvan Bacon return config; 29*082815dcSEvan Bacon }); 30*082815dcSEvan Bacon}; 31*082815dcSEvan Bacon 32*082815dcSEvan Baconexport const withApplyPlugin: ConfigPlugin = (config) => { 33*082815dcSEvan Bacon return withAppBuildGradle(config, (config) => { 34*082815dcSEvan Bacon if (config.modResults.language === 'groovy') { 35*082815dcSEvan Bacon config.modResults.contents = applyPlugin(config, config.modResults.contents); 36*082815dcSEvan Bacon } else { 37*082815dcSEvan Bacon addWarningAndroid( 38*082815dcSEvan Bacon 'android.googleServicesFile', 39*082815dcSEvan Bacon `Cannot automatically configure app build.gradle if it's not groovy` 40*082815dcSEvan Bacon ); 41*082815dcSEvan Bacon } 42*082815dcSEvan Bacon return config; 43*082815dcSEvan Bacon }); 44*082815dcSEvan Bacon}; 45*082815dcSEvan Bacon 46*082815dcSEvan Bacon/** 47*082815dcSEvan Bacon * Add `google-services.json` to project 48*082815dcSEvan Bacon */ 49*082815dcSEvan Baconexport const withGoogleServicesFile: ConfigPlugin = (config) => { 50*082815dcSEvan Bacon return withDangerousMod(config, [ 51*082815dcSEvan Bacon 'android', 52*082815dcSEvan Bacon async (config) => { 53*082815dcSEvan Bacon await setGoogleServicesFile(config, config.modRequest.projectRoot); 54*082815dcSEvan Bacon return config; 55*082815dcSEvan Bacon }, 56*082815dcSEvan Bacon ]); 57*082815dcSEvan Bacon}; 58*082815dcSEvan Bacon 59*082815dcSEvan Baconexport function getGoogleServicesFilePath(config: Pick<ExpoConfig, 'android'>) { 60*082815dcSEvan Bacon return config.android?.googleServicesFile ?? null; 61*082815dcSEvan Bacon} 62*082815dcSEvan Bacon 63*082815dcSEvan Baconexport async function setGoogleServicesFile( 64*082815dcSEvan Bacon config: Pick<ExpoConfig, 'android'>, 65*082815dcSEvan Bacon projectRoot: string, 66*082815dcSEvan Bacon targetPath: string = DEFAULT_TARGET_PATH 67*082815dcSEvan Bacon) { 68*082815dcSEvan Bacon const partialSourcePath = getGoogleServicesFilePath(config); 69*082815dcSEvan Bacon if (!partialSourcePath) { 70*082815dcSEvan Bacon return false; 71*082815dcSEvan Bacon } 72*082815dcSEvan Bacon 73*082815dcSEvan Bacon const completeSourcePath = path.resolve(projectRoot, partialSourcePath); 74*082815dcSEvan Bacon const destinationPath = path.resolve(projectRoot, targetPath); 75*082815dcSEvan Bacon 76*082815dcSEvan Bacon try { 77*082815dcSEvan Bacon await copyFilePathToPathAsync(completeSourcePath, destinationPath); 78*082815dcSEvan Bacon } catch (e) { 79*082815dcSEvan Bacon console.log(e); 80*082815dcSEvan Bacon throw new Error( 81*082815dcSEvan Bacon `Cannot copy google-services.json from ${completeSourcePath} to ${destinationPath}. Please make sure the source and destination paths exist.` 82*082815dcSEvan Bacon ); 83*082815dcSEvan Bacon } 84*082815dcSEvan Bacon return true; 85*082815dcSEvan Bacon} 86*082815dcSEvan Bacon 87*082815dcSEvan Bacon/** 88*082815dcSEvan Bacon * Adding the Google Services plugin 89*082815dcSEvan Bacon * NOTE(brentvatne): string replacement is a fragile approach! we need a 90*082815dcSEvan Bacon * better solution than this. 91*082815dcSEvan Bacon */ 92*082815dcSEvan Baconexport function setClassPath(config: Pick<ExpoConfig, 'android'>, buildGradle: string) { 93*082815dcSEvan Bacon const googleServicesFile = getGoogleServicesFilePath(config); 94*082815dcSEvan Bacon if (!googleServicesFile) { 95*082815dcSEvan Bacon return buildGradle; 96*082815dcSEvan Bacon } 97*082815dcSEvan Bacon 98*082815dcSEvan Bacon if (buildGradle.includes(googleServicesClassPath)) { 99*082815dcSEvan Bacon return buildGradle; 100*082815dcSEvan Bacon } 101*082815dcSEvan Bacon 102*082815dcSEvan Bacon // 103*082815dcSEvan Bacon return buildGradle.replace( 104*082815dcSEvan Bacon /dependencies\s?{/, 105*082815dcSEvan Bacon `dependencies { 106*082815dcSEvan Bacon classpath '${googleServicesClassPath}:${googleServicesVersion}'` 107*082815dcSEvan Bacon ); 108*082815dcSEvan Bacon} 109*082815dcSEvan Bacon 110*082815dcSEvan Baconexport function applyPlugin(config: Pick<ExpoConfig, 'android'>, appBuildGradle: string) { 111*082815dcSEvan Bacon const googleServicesFile = getGoogleServicesFilePath(config); 112*082815dcSEvan Bacon if (!googleServicesFile) { 113*082815dcSEvan Bacon return appBuildGradle; 114*082815dcSEvan Bacon } 115*082815dcSEvan Bacon 116*082815dcSEvan Bacon // Make sure the project does not have the plugin already 117*082815dcSEvan Bacon const pattern = new RegExp(`apply\\s+plugin:\\s+['"]${googleServicesPlugin}['"]`); 118*082815dcSEvan Bacon if (appBuildGradle.match(pattern)) { 119*082815dcSEvan Bacon return appBuildGradle; 120*082815dcSEvan Bacon } 121*082815dcSEvan Bacon 122*082815dcSEvan Bacon // Add it to the end of the file 123*082815dcSEvan Bacon return appBuildGradle + `\napply plugin: '${googleServicesPlugin}'`; 124*082815dcSEvan Bacon} 125