"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getConnectedDevices = getConnectedDevices; exports.isEnabled = isEnabled; exports.runOnDevice = runOnDevice; function _debug() { const data = _interopRequireDefault(require("debug")); _debug = function () { return data; }; return data; } function _fs() { const data = require("fs"); _fs = function () { return data; }; return data; } function _getenv() { const data = require("getenv"); _getenv = function () { return data; }; return data; } function path() { const data = _interopRequireWildcard(require("path")); path = function () { return data; }; return data; } function _lib() { const data = require("./native-run/ios/lib"); _lib = function () { return data; }; return data; } function _xcode() { const data = require("./native-run/ios/utils/xcode"); _xcode = function () { return data; }; return data; } function _process() { const data = require("./native-run/utils/process"); _process = function () { return data; }; return data; } 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; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const EXPO_USE_APPLE_DEVICE = (0, _getenv().boolish)('EXPO_USE_APPLE_DEVICE', false); const debug = (0, _debug().default)('expo:xdl:ios:utils:device'); function isEnabled() { return EXPO_USE_APPLE_DEVICE; } async function getConnectedDevices() { const usbmuxClient = new (_lib().UsbmuxdClient)(_lib().UsbmuxdClient.connectUsbmuxdSocket()); const usbmuxDevices = await usbmuxClient.getDevices(); usbmuxClient.socket.end(); return Promise.all(usbmuxDevices.map(async d => { const socket = await new (_lib().UsbmuxdClient)(_lib().UsbmuxdClient.connectUsbmuxdSocket()).connect(d, 62078); const device = await new (_lib().LockdowndClient)(socket).getAllValues(); socket.end(); return device; })); } async function runOnDevice({ udid, appPath, bundleId, waitForApp, deltaPath, onProgress }) { const clientManager = await _lib().ClientManager.create(udid); try { await mountDeveloperDiskImage(clientManager); const packageName = path().basename(appPath); const destPackagePath = path().join('PublicStaging', packageName); await uploadApp(clientManager, appPath, destPackagePath); const installer = await clientManager.getInstallationProxyClient(); await installer.installApp(destPackagePath, bundleId, { // https://github.com/ios-control/ios-deploy/blob/0f2ffb1e564aa67a2dfca7cdf13de47ce489d835/src/ios-deploy/ios-deploy.m#L2491-L2508 ApplicationsType: 'Any', CFBundleIdentifier: bundleId, CloseOnInvalidate: '1', InvalidateOnDetach: '1', IsUserInitiated: '1', // Disable checking for wifi devices, this is nominally faster. PreferWifi: '0', // Only info I could find on these: // https://github.com/wwxxyx/Quectel_BG96/blob/310876f90fc1093a59e45e381160eddcc31697d0/Apple_Homekit/homekit_certification_tools/ATS%206/ATS%206/ATS.app/Contents/Frameworks/CaptureKit.framework/Versions/A/Resources/MobileDevice/MobileInstallation.h#L112-L121 PackageType: 'Developer', ShadowParentKey: deltaPath // SkipUninstall: '1' }, onProgress); const { [bundleId]: appInfo } = await installer.lookupApp([bundleId]); // launch fails with EBusy or ENotFound if you try to launch immediately after install await (0, _process().wait)(200); const debugServerClient = await launchApp(clientManager, { appInfo, detach: !waitForApp }); if (waitForApp) { (0, _process().onBeforeExit)(async () => { // causes continue() to return debugServerClient.halt(); // give continue() time to return response await (0, _process().wait)(64); }); debug(`Waiting for app to close...\n`); const result = await debugServerClient.continue(); // TODO: I have no idea what this packet means yet (successful close?) // if not a close (ie, most likely due to halt from onBeforeExit), then kill the app if (result !== 'W00') { await debugServerClient.kill(); } } } finally { clientManager.end(); } } async function mountDeveloperDiskImage(clientManager) { const imageMounter = await clientManager.getMobileImageMounterClient(); // Check if already mounted. If not, mount. if (!(await imageMounter.lookupImage()).ImageSignature) { // verify DeveloperDiskImage exists (TODO: how does this work on Windows/Linux?) // TODO: if windows/linux, download? const version = await (await clientManager.getLockdowndClient()).getValue('ProductVersion'); const developerDiskImagePath = await (0, _xcode().getDeveloperDiskImagePath)(version); const developerDiskImageSig = (0, _fs().readFileSync)(`${developerDiskImagePath}.signature`); await imageMounter.uploadImage(developerDiskImagePath, developerDiskImageSig); await imageMounter.mountImage(developerDiskImagePath, developerDiskImageSig); } } async function uploadApp(clientManager, srcPath, destinationPath) { const afcClient = await clientManager.getAFCClient(); try { await afcClient.getFileInfo('PublicStaging'); } catch (err) { if (err instanceof _lib().AFCError && err.status === _lib().AFC_STATUS.OBJECT_NOT_FOUND) { await afcClient.makeDirectory('PublicStaging'); } else { throw err; } } await afcClient.uploadDirectory(srcPath, destinationPath); } async function launchApp(clientManager, { appInfo, detach }) { let tries = 0; while (tries < 3) { const debugServerClient = await clientManager.getDebugserverClient(); await debugServerClient.setMaxPacketSize(1024); await debugServerClient.setWorkingDir(appInfo.Container); await debugServerClient.launchApp(appInfo.Path, appInfo.CFBundleExecutable); const result = await debugServerClient.checkLaunchSuccess(); if (result === 'OK') { if (detach) { // https://github.com/libimobiledevice/libimobiledevice/blob/25059d4c7d75e03aab516af2929d7c6e6d4c17de/tools/idevicedebug.c#L455-L464 const res = await debugServerClient.sendCommand('D', []); debug('Disconnect from debug server request:', res); if (res !== 'OK') { console.warn('Something went wrong while attempting to disconnect from iOS debug server, you may need to reopen the app manually.'); } } return debugServerClient; } else if (result === 'EBusy' || result === 'ENotFound') { debug('Device busy or app not found, trying to launch again in .5s...'); tries++; debugServerClient.socket.end(); await (0, _process().wait)(500); } else { throw new Error(`There was an error launching app: ${result}`); } } throw new Error('Unable to launch app, number of tries exceeded'); } //# sourceMappingURL=AppleDevice.js.map