UNPKG

@expo/cli

Version:
352 lines (351 loc) 12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { isOSType: ()=>isOSType, getContainerPathAsync: ()=>getContainerPathAsync, getInfoPlistValueAsync: ()=>getInfoPlistValueAsync, openUrlAsync: ()=>openUrlAsync, openAppIdAsync: ()=>openAppIdAsync, bootAsync: ()=>bootAsync, getBootedSimulatorsAsync: ()=>getBootedSimulatorsAsync, isDeviceBootedAsync: ()=>isDeviceBootedAsync, bootDeviceAsync: ()=>bootDeviceAsync, installAsync: ()=>installAsync, uninstallAsync: ()=>uninstallAsync, getDevicesAsync: ()=>getDevicesAsync, simctlAsync: ()=>simctlAsync }); function _spawnAsync() { const data = /*#__PURE__*/ _interopRequireDefault(require("@expo/spawn-async")); _spawnAsync = function() { return data; }; return data; } function _bplistCreator() { const data = /*#__PURE__*/ _interopRequireDefault(require("bplist-creator")); _bplistCreator = function() { return data; }; return data; } function _fs() { const data = /*#__PURE__*/ _interopRequireDefault(require("fs")); _fs = function() { return data; }; return data; } function _os() { const data = /*#__PURE__*/ _interopRequireDefault(require("os")); _os = function() { return data; }; return data; } function _path() { const data = /*#__PURE__*/ _interopRequireDefault(require("path")); _path = function() { return data; }; return data; } const _xcrun = require("./xcrun"); const _log = /*#__PURE__*/ _interopRequireWildcard(require("../../../log")); const _errors = require("../../../utils/errors"); const _fn = require("../../../utils/fn"); const _plist = require("../../../utils/plist"); const _profile = require("../../../utils/profile"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for(var key in obj){ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } const debug = require("debug")("expo:simctl"); function isOSType(value) { if (!value || typeof value !== "string") return false; const knownTypes = [ "iOS", "tvOS", "watchOS", "macOS" ]; if (!knownTypes.includes(value)) { _log.warn(`Unknown OS type: ${value}. Expected one of: ${knownTypes.join(", ")}`); } return true; } async function getContainerPathAsync(device, { appId }) { try { const { stdout } = await simctlAsync([ "get_app_container", resolveId(device), appId ]); return stdout.trim(); } catch (error) { var ref; if ((ref = error.stderr) == null ? void 0 : ref.match(/No such file or directory/)) { return null; } throw error; } } async function getInfoPlistValueAsync(device, { appId , key , containerPath }) { const ensuredContainerPath = containerPath != null ? containerPath : await getContainerPathAsync(device, { appId }); if (ensuredContainerPath) { try { const { output } = await (0, _spawnAsync().default)("defaults", [ "read", `${ensuredContainerPath}/Info`, key ], { stdio: "pipe" }); return output.join("\n").trim(); } catch { return null; } } return null; } /** Rewrite the simulator permissions to allow opening deep links without needing to prompt the user first. */ async function updateSimulatorLinkingPermissionsAsync(device, { url , appId }) { if (!device.udid || !appId) { debug("Skipping deep link permissions as missing properties could not be found:", { url, appId, udid: device.udid }); return; } debug("Rewriting simulator permissions to support deep linking:", { url, appId, udid: device.udid }); let scheme; try { // Attempt to extract the scheme from the URL. scheme = new URL(url).protocol.slice(0, -1); } catch (error) { debug(`Could not parse the URL scheme: ${error.message}`); return; } // Get the hard-coded path to the simulator's scheme approval plist file. const plistPath = _path().default.join(_os().default.homedir(), `Library/Developer/CoreSimulator/Devices`, device.udid, `data/Library/Preferences/com.apple.launchservices.schemeapproval.plist`); const plistData = _fs().default.existsSync(plistPath) ? await (0, _plist.parsePlistAsync)(plistPath) : // Can be tested by launching a new simulator or by deleting the file and relaunching the simulator. {}; debug("Allowed links:", plistData); const key = `com.apple.CoreSimulator.CoreSimulatorBridge-->${scheme}`; // Replace any existing value for the scheme with the new appId. plistData[key] = appId; debug("Allowing deep link:", { key, appId }); try { const data = (0, _bplistCreator().default)(plistData); // Write the updated plist back to disk await _fs().default.promises.writeFile(plistPath, data); } catch (error1) { _log.warn(`Could not update simulator linking permissions: ${error1.message}`); } } const updateSimulatorLinkingPermissionsAsyncMemo = (0, _fn.memoize)(updateSimulatorLinkingPermissionsAsync); async function openUrlAsync(device, options) { if (options.appId) { await (0, _profile.profile)(updateSimulatorLinkingPermissionsAsyncMemo, "updateSimulatorLinkingPermissionsAsync")({ udid: device.udid }, options); } try { // Skip logging since this is likely to fail. await simctlAsync([ "openurl", resolveId(device), options.url ]); } catch (error) { var ref; if (!((ref = error.stderr) == null ? void 0 : ref.match(/Unable to lookup in current state: Shut/))) { throw error; } // If the device was in a weird in-between state ("Shutting Down" or "Shutdown"), then attempt to reboot it and try again. // This can happen when quitting the Simulator app, and immediately pressing `i` to reopen the project. // First boot the simulator await bootDeviceAsync({ udid: resolveId(device) }); // Finally, try again... return await openUrlAsync(device, options); } } async function openAppIdAsync(device, options) { const results = await openAppIdInternalAsync(device, options); // Similar to 194, this is a conformance issue which indicates that the given device has no app that can handle our launch request. if (results.status === 4) { throw new _errors.CommandError("APP_NOT_INSTALLED", results.stderr); } return results; } async function openAppIdInternalAsync(device, options) { try { return await simctlAsync([ "launch", resolveId(device), options.appId ]); } catch (error) { if ("status" in error) { return error; } throw error; } } async function bootAsync(device) { await bootDeviceAsync(device); return isDeviceBootedAsync(device); } async function getBootedSimulatorsAsync() { const simulatorDeviceInfo = await getRuntimesAsync("devices"); return Object.values(simulatorDeviceInfo.devices).flatMap((runtime)=>runtime.filter((device)=>device.state === "Booted")); } async function isDeviceBootedAsync(device) { // Simulators can be booted even if the app isn't running :( const devices = await getBootedSimulatorsAsync(); if (device.udid) { var ref; return (ref = devices.find((bootedDevice)=>bootedDevice.udid === device.udid)) != null ? ref : null; } var ref1; return (ref1 = devices[0]) != null ? ref1 : null; } async function bootDeviceAsync(device) { try { // Skip logging since this is likely to fail. await simctlAsync([ "boot", device.udid ]); } catch (error) { var ref; if (!((ref = error.stderr) == null ? void 0 : ref.match(/Unable to boot device in current state: Booted/))) { throw error; } } } async function installAsync(device, options) { return simctlAsync([ "install", resolveId(device), options.filePath ]); } async function uninstallAsync(device, options) { return simctlAsync([ "uninstall", resolveId(device), options.appId ]); } function parseSimControlJSONResults(input) { try { return JSON.parse(input); } catch (error) { // Nov 15, 2020: Observed this can happen when opening the simulator and the simulator prompts the user to update the xcode command line tools. // Unexpected token I in JSON at position 0 if (error.message.includes("Unexpected token")) { _log.error(`Apple's simctl returned malformed JSON:\n${input}`); } throw error; } } /** Get all runtime devices given a certain type. */ async function getRuntimesAsync(type, query) { const result = await simctlAsync([ "list", type, "--json", query ]); const info = parseSimControlJSONResults(result.stdout); for (const runtime of Object.keys(info.devices)){ // Given a string like 'com.apple.CoreSimulator.SimRuntime.tvOS-13-4' const runtimeSuffix = 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("."); const sims = info.devices[runtime]; for (const device of sims){ device.runtime = runtime; device.osVersion = osVersion; device.windowName = `${device.name} (${osVersion})`; device.osType = osType; } } return info; } async function getDevicesAsync() { const simulatorDeviceInfo = await getRuntimesAsync("devices"); return Object.values(simulatorDeviceInfo.devices).flat(); } async function simctlAsync(args, options) { return (0, _xcrun.xcrunAsync)([ "simctl", ...args ], options); } function resolveId(device) { var _udid; return (_udid = device.udid) != null ? _udid : "booted"; } //# sourceMappingURL=simctl.js.map