UNPKG

xdl

Version:
302 lines (293 loc) 10.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CoreSimulatorError = void 0; exports.devicePlistToSimulatorDevice = devicePlistToSimulatorDevice; exports.getBootedDeviceAsync = getBootedDeviceAsync; exports.getContainerPathAsync = getContainerPathAsync; exports.getDeviceInfoAsync = getDeviceInfoAsync; exports.isEnabled = isEnabled; exports.listDevicesAsync = listDevicesAsync; function _fs() { const data = _interopRequireDefault(require("fs")); _fs = function () { return data; }; return data; } function _getenv() { const data = require("getenv"); _getenv = function () { return data; }; return data; } function _glob() { const data = require("glob"); _glob = function () { return data; }; return data; } 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 _internal() { const data = require("../internal"); _internal = function () { return data; }; return data; } function _parseBinaryPlistAsync() { const data = require("../utils/parseBinaryPlistAsync"); _parseBinaryPlistAsync = function () { return data; }; return data; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // Enable this to test the JS version of simctl const EXPO_USE_CORE_SIM = (0, _getenv().boolish)('EXPO_USE_CORE_SIM', false); function isEnabled() { return EXPO_USE_CORE_SIM; } var DeviceState; (function (DeviceState) { DeviceState[DeviceState["BOOTED"] = 3] = "BOOTED"; DeviceState[DeviceState["SHUTDOWN"] = 1] = "SHUTDOWN"; })(DeviceState || (DeviceState = {})); class CoreSimulatorError extends Error { constructor(message, code) { super(message); this.message = message; this.code = code; } } /** * CoreSimulator devices folder. * * @returns /Users/evanbacon/Library/Developer/CoreSimulator/Devices */ exports.CoreSimulatorError = CoreSimulatorError; function getDevicesDirectory() { return _path().default.join(_os().default.homedir(), '/Library/Developer/CoreSimulator/Devices/'); } /** * CoreSimulator device folder, asserts when the device is invalid. * * @param props.udid device udid. Cannot be `booted`. * @returns /Users/evanbacon/Library/Developer/CoreSimulator/Devices/EFEEA6EF-E3F5-4EDE-9B72-29EAFA7514AE/ */ async function getDirectoryForDeviceAsync(udid) { const deviceFolder = _path().default.join(getDevicesDirectory(), udid); // Invalid udid (no matching device) if (!_fs().default.existsSync(deviceFolder)) { const possibleUdids = await getDirectoriesAsync(getDevicesDirectory()); let errorMessage = `Invalid iOS Simulator device UDID: ${udid}.`; if (possibleUdids.length) { errorMessage += ` Expected one of: ${possibleUdids.join(', ')}`; } throw new CoreSimulatorError(errorMessage, 'INVALID_UDID'); } return deviceFolder; } async function resolveUdidAsync(udid) { if (udid === 'booted') { const bootedDevice = await getBootedDeviceAsync(); if (!bootedDevice) { throw new CoreSimulatorError('No devices are booted.', 'INVALID_UDID'); } udid = bootedDevice.UDID; _internal().Logger.global.debug('Resolved booted device: ' + udid); } return udid; } async function listDevicesAsync() { const devicesDirectory = getDevicesDirectory(); const devices = await getDirectoriesAsync(devicesDirectory); return (await Promise.all(devices.map(async device => { const plistPath = _path().default.join(devicesDirectory, device, 'device.plist'); if (!_fs().default.existsSync(plistPath)) return null; // The plist is stored in binary format const data = await (0, _parseBinaryPlistAsync().parseBinaryPlistAsync)(plistPath); return devicePlistToSimulatorDevice(devicesDirectory, data); }))).filter(Boolean); } async function getDeviceInfoAsync({ udid } = {}) { if (!udid || udid === 'booted') { const bootedDevice = await getBootedDeviceAsync(); if (!bootedDevice) { throw new CoreSimulatorError('No devices are booted.', 'INVALID_UDID'); } const deviceDirectory = await getDirectoryForDeviceAsync(bootedDevice.UDID); return devicePlistToSimulatorDevice(deviceDirectory, bootedDevice); } const deviceDirectory = await getDirectoryForDeviceAsync(udid); const plistPath = _path().default.join(deviceDirectory, 'device.plist'); // The plist is stored in binary format const data = await (0, _parseBinaryPlistAsync().parseBinaryPlistAsync)(plistPath); return devicePlistToSimulatorDevice(deviceDirectory, data); } function devicePlistToSimulatorDevice(deviceDirectory, data) { const runtimeSuffix = data.runtime.split('com.apple.CoreSimulator.SimRuntime.').pop(); // Create an array [tvOS, 13, 4] const [osType, ...osVersionComponents] = runtimeSuffix.split('-'); // Join the end components [13, 4] -> '13.4' const osVersion = osVersionComponents.join('.'); return { ...data, /** * '/Users/name/Library/Developer/CoreSimulator/Devices/00E55DC0-0364-49DF-9EC6-77BE587137D4/data' */ dataPath: _path().default.join(deviceDirectory, 'data'), /** * '/Users/name/Library/Logs/CoreSimulator/00E55DC0-0364-49DF-9EC6-77BE587137D4' */ logPath: _path().default.join(_os().default.homedir(), 'Library/Logs/CoreSimulator', data.UDID), /** * '00E55DC0-0364-49DF-9EC6-77BE587137D4' */ udid: data.UDID, /** * com.apple.CoreSimulator.SimRuntime.tvOS-13-4 */ runtime: data.runtime, isAvailable: !data.isDeleted, /** * 'com.apple.CoreSimulator.SimDeviceType.Apple-TV-1080p' */ deviceTypeIdentifier: data.deviceType, state: data.state === DeviceState.BOOTED ? 'Booted' : 'Shutdown', /** * 'Apple TV' */ name: data.name, /** * 'iOS' */ osType: osType, /** * '13.4' */ osVersion, /** * 'iPhone 11 (13.6)' */ windowName: `${data.name} (${osVersion})`, // Compare state stored under `state` to 3 (booted) isBooted: data.state === DeviceState.BOOTED }; } /** * Get UDID for the first booted simulator. It's unclear if this is the exact method used by `xcrun simctl` to determine which device is "booted". * * @returns EFEEA6EF-E3F5-4EDE-9B72-29EAFA7514AE */ async function getBootedDeviceAsync() { const devicesDirectory = getDevicesDirectory(); const devices = await getDirectoriesAsync(devicesDirectory); // parallelize searching for the matching app return new Promise(async (resolve, reject) => { let complete = false; try { await Promise.all(devices.map(async device => { if (complete) return; const plistPath = _path().default.join(devicesDirectory, device, 'device.plist'); // The plist is stored in binary format const data = await (0, _parseBinaryPlistAsync().parseBinaryPlistAsync)(plistPath); // Compare state stored under `state` to 3 (booted) if (data.state === DeviceState.BOOTED) { complete = true; resolve(data); } })); if (!complete) { resolve(null); } } catch (error) { if (!complete) { reject(error); } } }); } /** * Returns the local path for the installed binary.app on a given Apple simulator. Returns null when the app isn't installed. * * This can be used as a replacement for `xcrun simctl get_app_container <udid> <bundleIdentifier>` but it's over 200x faster. * * @param props.udid device udid. * @param props.bundleIdentifier bundle identifier for app * @returns local file path to installed app binary, e.g. '/Users/evanbacon/Library/Developer/CoreSimulator/Devices/EFEEA6EF-E3F5-4EDE-9B72-29EAFA7514AE/data/Containers/Bundle/Application/FA43A0C6-C2AD-442D-B8B1-EAF3E88CF3BF/Exponent-2.21.3.tar.app' */ async function getContainerPathAsync({ udid, bundleIdentifier }) { udid = await resolveUdidAsync(udid); // Like: `/Users/evanbacon/Library/Developer/CoreSimulator/Devices/EFEEA6EF-E3F5-4EDE-9B72-29EAFA7514AE/data/Containers/Bundle/Application/` // TODO: Maybe shallow glob for `.com.apple.mobile_container_manager.metadata.plist` to find apps faster const appsFolder = _path().default.join(await getDirectoryForDeviceAsync(udid), 'data/Containers/Bundle/Application'); // Get all apps for a device // Like: `['FA43A0C6-C2AD-442D-B8B1-EAF3E88CF3BF']` const apps = await getDirectoriesAsync(appsFolder); // parallelize searching for the matching app return new Promise(async (resolve, reject) => { let complete = false; try { await Promise.all(apps.map(async app => { if (complete) return; const appFolder = _path().default.join(appsFolder, app); const plistPath = _path().default.join(appFolder, '.com.apple.mobile_container_manager.metadata.plist'); // The plist is stored in binary format const data = await (0, _parseBinaryPlistAsync().parseBinaryPlistAsync)(plistPath); // Compare bundle identifier stored under `MCMMetadataIdentifier` if (data.MCMMetadataIdentifier === bundleIdentifier) { // Find .app file in the app folder const binaryPath = findBinaryFileInDirectory(appFolder); if (!binaryPath) { throw new CoreSimulatorError(`Found matching app container at "${appFolder}" but binary (*.app file) is missing.`, 'MALFORMED_BINARY'); } complete = true; resolve(binaryPath); } })); if (!complete) { resolve(null); } } catch (error) { if (!complete) { reject(error); } } }); } function findBinaryFileInDirectory(folder) { // Find .app file in the app folder const binaryPath = (0, _glob().sync)('*.app', { absolute: true, cwd: folder })[0]; return binaryPath || null; } async function getDirectoriesAsync(directory) { return (await _fs().default.promises.readdir(directory, { withFileTypes: true }).catch(() => [])).filter(device => device.isDirectory()).map(device => device.name); } //# sourceMappingURL=CoreSimulator.js.map