"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isPlatformSupported = isPlatformSupported; exports._isSimulatorInstalledAsync = _isSimulatorInstalledAsync; exports._openAndBootSimulatorAsync = _openAndBootSimulatorAsync; exports._isSimulatorRunningAsync = _isSimulatorRunningAsync; exports._dirForSimulatorDevice = _dirForSimulatorDevice; exports._quitSimulatorAsync = _quitSimulatorAsync; exports._isExpoAppInstalledOnCurrentBootedSimulatorAsync = _isExpoAppInstalledOnCurrentBootedSimulatorAsync; exports._waitForExpoAppInstalledOnCurrentBootedSimulatorAsync = _waitForExpoAppInstalledOnCurrentBootedSimulatorAsync; exports._expoVersionOnCurrentBootedSimulatorAsync = _expoVersionOnCurrentBootedSimulatorAsync; exports._checkExpoUpToDateAsync = _checkExpoUpToDateAsync; exports._downloadSimulatorAppAsync = _downloadSimulatorAppAsync; exports._installExpoOnSimulatorAsync = _installExpoOnSimulatorAsync; exports._uninstallExpoAppFromSimulatorAsync = _uninstallExpoAppFromSimulatorAsync; exports._simulatorCacheDirectory = _simulatorCacheDirectory; exports.upgradeExpoAsync = upgradeExpoAsync; exports._openUrlInSimulatorAsync = _openUrlInSimulatorAsync; exports.openUrlInSimulatorSafeAsync = openUrlInSimulatorSafeAsync; exports.openProjectAsync = openProjectAsync; exports.openWebProjectAsync = openWebProjectAsync; function _os() { const data = _interopRequireDefault(require("os")); _os = function () { return data; }; return data; } function _path() { const data = _interopRequireDefault(require("path")); _path = function () { return data; }; return data; } function ConfigUtils() { const data = _interopRequireWildcard(require("@expo/config")); ConfigUtils = function () { return data; }; return data; } function _delayAsync() { const data = _interopRequireDefault(require("delay-async")); _delayAsync = function () { return data; }; return data; } function _globPromise() { const data = _interopRequireDefault(require("glob-promise")); _globPromise = function () { return data; }; return data; } function osascript() { const data = _interopRequireWildcard(require("@expo/osascript")); osascript = function () { return data; }; return data; } function _semver() { const data = _interopRequireDefault(require("semver")); _semver = function () { return data; }; return data; } function _spawnAsync() { const data = _interopRequireDefault(require("@expo/spawn-async")); _spawnAsync = function () { return data; }; return data; } function _fsExtra() { const data = _interopRequireDefault(require("fs-extra")); _fsExtra = function () { return data; }; return data; } function Analytics() { const data = _interopRequireWildcard(require("./Analytics")); Analytics = function () { return data; }; return data; } function _Api() { const data = _interopRequireDefault(require("./Api")); _Api = function () { return data; }; return data; } function _Logger() { const data = _interopRequireDefault(require("./Logger")); _Logger = function () { return data; }; return data; } function _NotificationCode() { const data = _interopRequireDefault(require("./NotificationCode")); _NotificationCode = function () { return data; }; return data; } function _UserSettings() { const data = _interopRequireDefault(require("./UserSettings")); _UserSettings = function () { return data; }; return data; } function Versions() { const data = _interopRequireWildcard(require("./Versions")); Versions = function () { return data; }; return data; } function _XDLError() { const data = _interopRequireDefault(require("./XDLError")); _XDLError = function () { return data; }; return data; } function UrlUtils() { const data = _interopRequireWildcard(require("./UrlUtils")); UrlUtils = function () { return data; }; return data; } function _Webpack() { const data = require("./Webpack"); _Webpack = function () { return data; }; return data; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // @ts-ignore let _lastUrl = null; const SUGGESTED_XCODE_VERSION = `8.2.0`; const XCODE_NOT_INSTALLED_ERROR = 'Simulator not installed. Please visit https://developer.apple.com/xcode/download/ to download Xcode and the iOS simulator. If you already have the latest version of Xcode installed, you may have to run the command `sudo xcode-select -s /Applications/Xcode.app`.'; function isPlatformSupported() { return process.platform === 'darwin'; } function _isLicenseOutOfDate(text) { if (!text) { return false; } let lower = text.toLowerCase(); return lower.includes('xcode') && lower.includes('license'); } async function _xcrunAsync(args) { try { return await (0, _spawnAsync().default)('xcrun', args); } catch (e) { if (_isLicenseOutOfDate(e.stdout) || _isLicenseOutOfDate(e.stderr)) { throw new (_XDLError().default)('XCODE_LICENSE_NOT_ACCEPTED', 'Xcode license is not accepted. Please run `sudo xcodebuild -license`.'); } else { _Logger().default.global.error(`Error running \`xcrun ${args.join(' ')}\`: ${e.stderr}`); throw e; } } } // Simulator installed async function _isSimulatorInstalledAsync() { let result; try { result = (await osascript().execAsync('id of app "Simulator"')).trim(); } catch (e) { console.error("Can't determine id of Simulator app; the Simulator is most likely not installed on this machine", e); _Logger().default.global.error(XCODE_NOT_INSTALLED_ERROR); return false; } if (result !== 'com.apple.iphonesimulator' && result !== 'com.apple.CoreSimulator.SimulatorTrampoline') { console.warn("Simulator is installed but is identified as '" + result + "'; don't know what that is."); _Logger().default.global.error(XCODE_NOT_INSTALLED_ERROR); return false; } // check xcode version try { const { stdout } = await (0, _spawnAsync().default)('xcodebuild', ['-version']); // find something that looks like a dot separated version number let matches = stdout.match(/[\d]{1,2}\.[\d]{1,3}/); if (!matches) { // very unlikely console.error('No version number found from `xcodebuild -version`.'); _Logger().default.global.error('Unable to check Xcode version. Command ran successfully but no version number was found.'); return false; } // we're cheating to use the semver lib, but it expects a proper patch version which xcode doesn't have const version = matches[0] + '.0'; if (!_semver().default.valid(version)) { console.error('Invalid version number found: ' + matches[0]); return false; } if (_semver().default.lt(version, SUGGESTED_XCODE_VERSION)) { console.warn(`Found Xcode ${version}, which is older than the recommended Xcode ${SUGGESTED_XCODE_VERSION}.`); } } catch (e) { // how would this happen? presumably if Simulator id is found then xcodebuild is installed console.error(`Unable to check Xcode version: ${e}`); _Logger().default.global.error(XCODE_NOT_INSTALLED_ERROR); return false; } // make sure we can run simctl try { await _xcrunAsync(['simctl', 'help']); } catch (e) { if (e.isXDLError) { _Logger().default.global.error(e.toString()); } else { console.warn(`Unable to run simctl: ${e.toString()}`); _Logger().default.global.error('xcrun may not be configured correctly. Try running `sudo xcode-select --reset` and running this again.'); } return false; } return true; } // Simulator opened async function _openAndBootSimulatorAsync() { if (!(await _isSimulatorRunningAsync())) { _Logger().default.global.info('Opening iOS simulator'); await (0, _spawnAsync().default)('open', ['-a', 'Simulator']); await _waitForDeviceToBoot(); } else { let bootedDevice = await _bootedSimulatorDeviceAsync(); if (!bootedDevice) { await _bootDefaultSimulatorDeviceAsync(); } } } async function _isSimulatorRunningAsync() { let zeroMeansNo = (await osascript().execAsync('tell app "System Events" to count processes whose name is "Simulator"')).trim(); if (zeroMeansNo === '0') { return false; } return true; } async function _bootDefaultSimulatorDeviceAsync() { _Logger().default.global.info(`Booting device in iOS simulator...`); try { let deviceUDID = await _getDefaultSimulatorDeviceUDIDAsync(); if (!deviceUDID) { deviceUDID = (await _getFirstAvailableDeviceAsync()).udid; } return await _xcrunAsync(['simctl', 'boot', deviceUDID]); } catch (e) { _Logger().default.global.error(`There was a problem booting a device in iOS Simulator. Quit Simulator, and try again.`); throw e; } } async function _getDefaultSimulatorDeviceUDIDAsync() { try { const { stdout: defaultDeviceUDID } = await (0, _spawnAsync().default)('defaults', ['read', 'com.apple.iphonesimulator', 'CurrentDeviceUDID']); return defaultDeviceUDID.trim(); } catch (e) { return null; } } async function _getFirstAvailableDeviceAsync() { const simulatorDeviceInfo = (await _listSimulatorDevicesAsync()).devices; let iOSRuntimesNewestToOldest = Object.keys(simulatorDeviceInfo).filter(runtime => runtime.includes('iOS')).reverse(); const devices = simulatorDeviceInfo[iOSRuntimesNewestToOldest[0]]; for (let i = 0; i < devices.length; i++) { const device = devices[i]; if (device.isAvailable && device.name.includes('iPhone')) { return device; } } throw new Error('No iPhone devices available in Simulator.'); } async function _listSimulatorDevicesAsync() { const result = await _xcrunAsync(['simctl', 'list', 'devices', '--json']); const info = JSON.parse(result.stdout); return info; } async function _waitForDeviceToBoot() { let bootedDevice; const start = Date.now(); do { await (0, _delayAsync().default)(100); bootedDevice = await _bootedSimulatorDeviceAsync(); if (Date.now() - start > 10000) { _Logger().default.global.error(`iOS Simulator device failed to boot. Try opening Simulator first, then running your app.`); throw new Error('Timed out waiting for iOS Simulator device to boot.'); } } while (!bootedDevice); } async function _bootedSimulatorDeviceAsync() { let simulatorDeviceInfo = await _listSimulatorDevicesAsync(); for (let runtime in simulatorDeviceInfo.devices) { let devices = simulatorDeviceInfo.devices[runtime]; for (let i = 0; i < devices.length; i++) { let device = devices[i]; if (device.state === 'Booted') { return device; } } } return null; } function _dirForSimulatorDevice(udid) { return _path().default.resolve(_os().default.homedir(), 'Library/Developer/CoreSimulator/Devices', udid); } async function _quitSimulatorAsync() { return await osascript().execAsync('tell application "Simulator" to quit'); } // Expo installed async function _isExpoAppInstalledOnCurrentBootedSimulatorAsync() { let device = await _bootedSimulatorDeviceAsync(); if (!device) { return false; } let simDir = await _dirForSimulatorDevice(device.udid); let matches = await (0, _globPromise().default)('./data/Containers/Data/Application/**/Snapshots/host.exp.Exponent{,**}', { cwd: simDir }); return matches.length > 0; } async function _waitForExpoAppInstalledOnCurrentBootedSimulatorAsync() { if (await _isExpoAppInstalledOnCurrentBootedSimulatorAsync()) { return true; } else { await (0, _delayAsync().default)(100); return await _waitForExpoAppInstalledOnCurrentBootedSimulatorAsync(); } } async function _expoVersionOnCurrentBootedSimulatorAsync() { let device = await _bootedSimulatorDeviceAsync(); if (!device) { return null; } let simDir = await _dirForSimulatorDevice(device.udid); let matches = await (0, _globPromise().default)('./data/Containers/Bundle/Application/*/Exponent-*.app', { cwd: simDir }); if (matches.length === 0) { return null; } let regex = /Exponent-([0-9.]+)\.app/; let regexMatch = regex.exec(matches[0]); if (!regexMatch) { return null; } return regexMatch[1]; } async function _checkExpoUpToDateAsync() { let versions = await Versions().versionsAsync(); let installedVersion = await _expoVersionOnCurrentBootedSimulatorAsync(); if (!installedVersion || _semver().default.lt(installedVersion, versions.iosVersion)) { _Logger().default.notifications.warn({ code: _NotificationCode().default.OLD_IOS_APP_VERSION }, 'This version of the Expo app is out of date. Uninstall the app and run again to upgrade.'); } } async function _downloadSimulatorAppAsync(url) { // If specific URL given just always download it and don't use cache if (url) { let dir = _path().default.join(_simulatorCacheDirectory(), `Exponent-tmp.app`); await _Api().default.downloadAsync(url, dir, { extract: true }); return dir; } let versions = await Versions().versionsAsync(); let dir = _path().default.join(_simulatorCacheDirectory(), `Exponent-${versions.iosVersion}.app`); if (await _fsExtra().default.pathExists(dir)) { let filesInDir = await _fsExtra().default.readdir(dir); if (filesInDir.length > 0) { return dir; } else { _fsExtra().default.removeSync(dir); } } _fsExtra().default.mkdirpSync(dir); try { await _Api().default.downloadAsync(versions.iosUrl, dir, { extract: true }); } catch (e) { _fsExtra().default.removeSync(dir); throw e; } return dir; } // url: Optional URL of Exponent.app tarball to download async function _installExpoOnSimulatorAsync(url) { _Logger().default.global.info(`Downloading the latest version of Expo client app`); _Logger().default.notifications.info({ code: _NotificationCode().default.START_LOADING }); let dir = await _downloadSimulatorAppAsync(url); _Logger().default.notifications.info({ code: _NotificationCode().default.STOP_LOADING }); _Logger().default.global.info('Installing Expo client on iOS simulator'); _Logger().default.notifications.info({ code: _NotificationCode().default.START_LOADING }); let result = await _xcrunAsync(['simctl', 'install', 'booted', dir]); _Logger().default.notifications.info({ code: _NotificationCode().default.STOP_LOADING }); return result; } async function _uninstallExpoAppFromSimulatorAsync() { try { _Logger().default.global.info('Uninstalling Expo client from iOS simulator.'); await _xcrunAsync(['simctl', 'uninstall', 'booted', 'host.exp.Exponent']); } catch (e) { if (e.message && e.message.includes('No devices are booted.')) { return; } else { console.error(e); throw e; } } } function _simulatorCacheDirectory() { let dotExpoHomeDirectory = _UserSettings().default.dotExpoHomeDirectory(); let dir = _path().default.join(dotExpoHomeDirectory, 'ios-simulator-app-cache'); _fsExtra().default.mkdirpSync(dir); return dir; } async function upgradeExpoAsync() { if (!(await _isSimulatorInstalledAsync())) { return false; } await _openAndBootSimulatorAsync(); await _uninstallExpoAppFromSimulatorAsync(); let installResult = await _installExpoOnSimulatorAsync(); if (installResult.status !== 0) { return false; } if (_lastUrl) { _Logger().default.global.info(`Opening ${_lastUrl} in Expo.`); await _xcrunAsync(['simctl', 'openurl', 'booted', _lastUrl]); _lastUrl = null; } return true; } // Open Url async function _openUrlInSimulatorAsync(url) { return await _xcrunAsync(['simctl', 'openurl', 'booted', url]); } async function openUrlInSimulatorSafeAsync(url, isDetached = false) { if (!(await _isSimulatorInstalledAsync())) { return { success: false, msg: 'Unable to verify Xcode and Simulator installation.' }; } try { await _openAndBootSimulatorAsync(); if (!isDetached && !(await _isExpoAppInstalledOnCurrentBootedSimulatorAsync())) { await _installExpoOnSimulatorAsync(); await _waitForExpoAppInstalledOnCurrentBootedSimulatorAsync(); } if (!isDetached) { _lastUrl = url; _checkExpoUpToDateAsync(); // let this run in background } _Logger().default.global.info(`Opening ${url} in iOS simulator`); await _openUrlInSimulatorAsync(url); } catch (e) { if (e.isXDLError) { // Hit some internal error, don't try again. // This includes Xcode license errors _Logger().default.global.error(e.message); return { success: false, msg: `${e.toString()}` }; } if (isDetached) { _Logger().default.global.error(`Error running app. Have you installed the app already using Xcode? Since you are detached you must build manually. ${e.toString()}`); } else { _Logger().default.global.error(`Error installing or running app. ${e.toString()}`); } return { success: false, msg: `${e.toString()}` }; } Analytics().logEvent('Open Url on Device', { platform: 'ios' }); return { success: true }; } async function openProjectAsync(projectRoot) { let projectUrl = await UrlUtils().constructManifestUrlAsync(projectRoot, { hostType: 'localhost' }); let { exp } = await ConfigUtils().readConfigJsonAsync(projectRoot); let result = await openUrlInSimulatorSafeAsync(projectUrl, !!exp.isDetached); if (result.success) { return { success: true, url: projectUrl }; } else { return { success: result.success, error: result.msg }; } } async function openWebProjectAsync(projectRoot) { const projectUrl = await (0, _Webpack().getUrlAsync)(projectRoot); if (projectUrl === null) { return { success: false, error: `The web project has not been started yet` }; } const result = await openUrlInSimulatorSafeAsync(projectUrl, true); if (result.success) { return { success: true, url: projectUrl }; } else { return { success: result.success, error: result.msg }; } } //# sourceMappingURL=__sourcemaps__/Simulator.js.map