1import { getExpoHomeDirectory } from '@expo/config/build/getUserState'; 2import path from 'path'; 3import ProgressBar from 'progress'; 4 5import { getVersionsAsync, SDKVersion } from '../api/getVersions'; 6import { downloadAppAsync } from './downloadAppAsync'; 7import { CommandError } from './errors'; 8import { ora } from './ora'; 9import { profile } from './profile'; 10import { createProgressBar } from './progress'; 11 12const debug = require('debug')('expo:utils:downloadExpoGo') as typeof console.log; 13 14const platformSettings: Record< 15 string, 16 { 17 shouldExtractResults: boolean; 18 versionsKey: keyof SDKVersion; 19 getFilePath: (filename: string) => string; 20 } 21> = { 22 ios: { 23 versionsKey: 'iosClientUrl', 24 getFilePath: (filename) => 25 path.join(getExpoHomeDirectory(), 'ios-simulator-app-cache', `${filename}.app`), 26 shouldExtractResults: true, 27 }, 28 android: { 29 versionsKey: 'androidClientUrl', 30 getFilePath: (filename) => 31 path.join(getExpoHomeDirectory(), 'android-apk-cache', `${filename}.apk`), 32 shouldExtractResults: false, 33 }, 34}; 35 36/** Download the Expo Go app from the Expo servers (if only it was this easy for every app). */ 37export async function downloadExpoGoAsync( 38 platform: keyof typeof platformSettings, 39 { 40 url, 41 sdkVersion, 42 }: { 43 url?: string; 44 sdkVersion?: string; 45 } 46): Promise<string> { 47 const { getFilePath, versionsKey, shouldExtractResults } = platformSettings[platform]; 48 49 const spinner = ora({ text: 'Fetching Expo Go', color: 'white' }).start(); 50 51 let bar: ProgressBar | null = null; 52 53 if (!url) { 54 if (!sdkVersion) { 55 throw new CommandError( 56 `Unable to determine which Expo Go version to install (platform: ${platform})` 57 ); 58 } 59 const { sdkVersions: versions } = await getVersionsAsync(); 60 61 const version = versions[sdkVersion]; 62 if (!version) { 63 throw new CommandError( 64 `Unable to find a version of Expo Go for SDK ${sdkVersion} (platform: ${platform})` 65 ); 66 } 67 debug(`Installing Expo Go version for SDK ${sdkVersion} at URL: ${version[versionsKey]}`); 68 url = version[versionsKey] as string; 69 } 70 71 const filename = path.parse(url).name; 72 73 try { 74 const outputPath = getFilePath(filename); 75 debug(`Downloading Expo Go from "${url}" to "${outputPath}".`); 76 debug( 77 `The requested copy of Expo Go might already be cached in: "${getExpoHomeDirectory()}". You can disable the cache with EXPO_NO_CACHE=1` 78 ); 79 await profile(downloadAppAsync)({ 80 url, 81 // Save all encrypted cache data to `~/.expo/expo-go` 82 cacheDirectory: 'expo-go', 83 outputPath, 84 extract: shouldExtractResults, 85 onProgress({ progress, total }) { 86 if (progress && total) { 87 if (!bar) { 88 if (spinner.isSpinning) { 89 spinner.stop(); 90 } 91 bar = createProgressBar('Downloading the Expo Go app [:bar] :percent :etas', { 92 width: 64, 93 total: 100, 94 // clear: true, 95 complete: '=', 96 incomplete: ' ', 97 }); 98 } 99 bar!.update(progress, total); 100 } 101 }, 102 }); 103 return outputPath; 104 } finally { 105 spinner.stop(); 106 // @ts-expect-error 107 bar?.terminate(); 108 } 109} 110