"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