Socket
Socket
Sign inDemoInstall

native-run

Package Overview
Dependencies
41
Maintainers
1
Versions
55
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.0.7 to 0.0.10

dist/android/utils/apk.js

12

dist/android/help.js

@@ -6,7 +6,7 @@ "use strict";

Run an APK on a device or emulator target
Run an .apk on a device or emulator target
Targets are selected as follows:
1) --target using device/emulator serial number or AVD ID
2) A connected device, unless --emulator is used
2) A connected device, unless --virtual is used
3) A running emulator

@@ -23,6 +23,10 @@

--sdk-info ........... Print SDK information, then quit
--json ............... Output JSON
--apk <path> ......... Deploy specified APK file
--app <path> ......... Deploy specified .apk file
--device ............. Use a device if available
--emulator ........... Prefer an emulator
With --list prints connected devices
--virtual ............ Prefer an emulator
With --list prints available emulators
--target <id> ........ Use a specific target

@@ -29,0 +33,0 @@ --connect ............ Tie process to app process

@@ -9,4 +9,5 @@ "use strict";

if (args.includes('--list')) {
const cmd = await Promise.resolve().then(() => require('./list'));
return cmd.run(args);
const list = await Promise.resolve().then(() => require('./list'));
process.stdout.write(await list.run(args));
return;
}

@@ -13,0 +14,0 @@ if (args.includes('--sdk-info')) {

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const list_1 = require("../utils/list");
const adb_1 = require("./utils/adb");

@@ -8,5 +9,16 @@ const avd_1 = require("./utils/avd");

const sdk = await sdk_1.getSDK();
const devices = (await adb_1.getDevices(sdk))
const [devices, virtualDevices] = await Promise.all([
getDeviceTargets(sdk),
getVirtualTargets(sdk),
]);
return list_1.list(args, devices, virtualDevices);
}
exports.run = run;
async function getDeviceTargets(sdk) {
return (await adb_1.getDevices(sdk))
.filter(device => device.type === 'hardware')
.map(device => deviceToTarget(device));
.map(deviceToTarget);
}
exports.getDeviceTargets = getDeviceTargets;
async function getVirtualTargets(sdk) {
const avds = await avd_1.getInstalledAVDs(sdk);

@@ -17,27 +29,5 @@ const defaultAvd = await avd_1.getDefaultAVD(sdk, avds);

}
const virtualDevices = avds.map(avd => avdToTarget(avd));
if (args.includes('--json')) {
process.stdout.write(JSON.stringify({ devices, virtualDevices }));
return;
}
process.stdout.write('Devices:\n\n');
if (devices.length === 0) {
process.stdout.write(' No connected devices found\n');
}
else {
for (const device of devices) {
process.stdout.write(` ${formatTarget(device)}\n`);
}
}
process.stdout.write('\nVirtual Devices:\n\n');
if (virtualDevices.length === 0) {
process.stdout.write(' No virtual devices found\n');
}
else {
for (const avd of virtualDevices) {
process.stdout.write(` ${formatTarget(avd)}\n`);
}
}
return avds.map(avdToTarget);
}
exports.run = run;
exports.getVirtualTargets = getVirtualTargets;
function deviceToTarget(device) {

@@ -48,2 +38,5 @@ return {

id: device.serial,
format() {
return `${this.model} (API ${this.sdkVersion}) ${this.id}`;
},
};

@@ -56,8 +49,6 @@ }

id: avd.id,
format() {
return `${this.name} (API ${this.sdkVersion}) ${this.id}`;
},
};
}
function formatTarget(target) {
return `
${target.name ? `${target.name} ` : ''}${target.model ? `${target.model} ` : ''}(API ${target.sdkVersion}) ${target.id}
`.trim();
}

@@ -8,2 +8,3 @@ "use strict";

const adb_1 = require("./utils/adb");
const apk_1 = require("./utils/apk");
const avd_1 = require("./utils/avd");

@@ -14,10 +15,4 @@ const run_1 = require("./utils/run");

const sdk = await sdk_1.getSDK();
const apk = cli_1.getOptionValue(args, '--apk');
// TODO: get application id and activity from apk
const app = cli_1.getOptionValue(args, '--app');
const activity = cli_1.getOptionValue(args, '--activity', '.MainActivity');
if (!apk) {
throw new errors_1.RunException('--apk is required');
}
if (!app) {
const apkPath = cli_1.getOptionValue(args, '--app');
if (!apkPath) {
throw new errors_1.RunException('--app is required');

@@ -27,13 +22,14 @@ }

log_1.log(`Selected ${device.type === 'hardware' ? 'hardware device' : 'emulator'} ${device.serial}\n`);
const { appId, activityName } = await apk_1.getApkInfo(apkPath);
await adb_1.waitForBoot(sdk, device);
await run_1.installApkToDevice(sdk, device, apk, app);
log_1.log(`Starting application activity ${app}/${activity}...\n`);
await adb_1.startActivity(sdk, device, app, activity);
await run_1.installApkToDevice(sdk, device, apkPath, appId);
log_1.log(`Starting application activity ${appId}/${activityName}...\n`);
await adb_1.startActivity(sdk, device, appId, activityName);
log_1.log(`Run Successful\n`);
if (args.includes('--connect')) {
process_1.onBeforeExit(async () => {
await adb_1.closeApp(sdk, device, app);
await adb_1.closeApp(sdk, device, appId);
});
log_1.log(`Waiting for app to close...\n`);
await adb_1.waitForClose(sdk, device, app);
await adb_1.waitForClose(sdk, device, appId);
}

@@ -46,3 +42,3 @@ }

const target = cli_1.getOptionValue(args, '--target');
const preferEmulator = args.includes('--emulator');
const preferEmulator = args.includes('--virtual');
if (target) {

@@ -49,0 +45,0 @@ const targetDevice = await run_1.selectDeviceByTarget(sdk, devices, avds, target);

@@ -73,3 +73,3 @@ "use strict";

exports.selectVirtualDevice = selectVirtualDevice;
async function installApkToDevice(sdk, device, apk, app) {
async function installApkToDevice(sdk, device, apk, appId) {
process.stdout.write(`Installing ${apk}...\n`);

@@ -83,3 +83,3 @@ try {

process.stdout.write(`${e.message} Uninstalling and trying again...\n`);
await adb_1.uninstallApp(sdk, device, app);
await adb_1.uninstallApp(sdk, device, appId);
await adb_1.installApk(sdk, device, apk);

@@ -86,0 +86,0 @@ return;

@@ -11,2 +11,3 @@ "use strict";

--verbose ............ Print verbose output to stderr
--list ............... Print connected devices and virtual devices

@@ -13,0 +14,0 @@ `;

@@ -24,2 +24,5 @@ "use strict";

}
else if (platform === '--list') {
await list(args);
}
else {

@@ -40,2 +43,20 @@ if (!platform || platform === 'help' || args.includes('--help') || args.includes('-h') || platform.startsWith('-')) {

exports.run = run;
async function list(args) {
const [iosOutput, androidOutput] = await Promise.all([
Promise.resolve().then(() => require('./ios/list')).then(iosList => iosList.run(args)),
Promise.resolve().then(() => require('./android/list')).then(androidList => androidList.run(args)),
]);
if (!args.includes('--json')) {
process.stdout.write(`iOS ${iosOutput}\n`);
process.stdout.write(`Android ${androidOutput}`);
}
else {
const adjustLines = (output) => output.split('\n').map(line => ` ${line}`).join('\n').trim();
process.stdout.write(`
{
"ios": ${adjustLines(iosOutput)},
"android": ${adjustLines(androidOutput)}
}`);
}
}
function serializeError(e) {

@@ -42,0 +63,0 @@ let error;

@@ -6,8 +6,31 @@ "use strict";

Run an .app or .ipa on a device or simulator target
Targets are selected as follows:
1) --target using device/simulator UUID
2) A connected device, unless --virtual is used
3) A running simulator
If the above criteria are not met, the app is run on the default simulator
(the last simulator in the list).
Use --list to list available targets.
Options:
--list ............... Print available targets, then quit
--json ............... Output JSON
--app <path> ......... Deploy specified .app or .ipa file
--device ............. Use a device if available
With --list prints connected devices
--virtual ............ Prefer a simulator
With --list prints available simulators
--target <id> ........ Use a specific target
--connect ............ Tie process to app process
`;
async function run() {
process.stdout.write(help);
process.stdout.write(`${help}\n`);
}
exports.run = run;

@@ -10,3 +10,4 @@ "use strict";

const list = await Promise.resolve().then(() => require('./list'));
return list.run(args);
process.stdout.write(await list.run(args));
return;
}

@@ -13,0 +14,0 @@ const runCmd = await Promise.resolve().then(() => require('./run'));

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const list_1 = require("../utils/list");
const device_1 = require("./utils/device");
const simulator_1 = require("./utils/simulator");
async function run(args) {
// TODO check for darwin?
const simulators = await device_1.getSimulators();
const devices = await device_1.getConnectedDevicesInfo();
if (args.includes('--json')) {
const result = { devices, simulators };
process.stdout.write(JSON.stringify(result, undefined, 2) + '\n');
return;
}
process.stdout.write('Devices:\n\n');
if (devices.length === 0) {
process.stdout.write(' No connected devices found\n');
}
else {
for (const device of devices) {
process.stdout.write(` ${formatDevice(device)}\n`);
}
}
process.stdout.write('\nSimulators:\n\n');
for (const sim of simulators) {
process.stdout.write(` ${formatSimulator(sim)}\n`);
}
const [devices, simulators] = await Promise.all([
(await device_1.getConnectedDevices()).map(deviceToTarget),
(await simulator_1.getSimulators()).map(simulatorToTarget),
]);
return list_1.list(args, devices, simulators);
}
exports.run = run;
function formatDevice(device) {
return `
${device.name} ${device.model} (${device.sdkVersion}) ${device.id}
`.trim();
function deviceToTarget(device) {
return {
name: device.DeviceName,
model: device.ProductType,
sdkVersion: device.ProductVersion,
id: device.UniqueDeviceID,
format() {
return `${this.name} ${this.model} ${this.sdkVersion} ${this.id}`;
},
};
}
function formatSimulator(sim) {
return `
${sim.name} (${sim.sdkVersion}) ${sim.id}
`.trim();
function simulatorToTarget(simulator) {
return {
name: simulator.name,
sdkVersion: simulator.runtime.version,
id: simulator.udid,
format() {
return `${this.name} ${this.sdkVersion} ${this.id}`;
},
};
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_fs_1 = require("@ionic/utils-fs");
const child_process_1 = require("child_process");
const Debug = require("debug");
const fs_1 = require("fs");
const node_ioslib_1 = require("node-ioslib");
const path = require("path");
const util_1 = require("util");
const errors_1 = require("../errors");
const cli_1 = require("../utils/cli");
const process_1 = require("../utils/process");
const app_1 = require("./utils/app");
const device_1 = require("./utils/device");
const simulator_1 = require("./utils/simulator");
const debug = Debug('native-run:ios:run');
const wait = util_1.promisify(setTimeout);
async function run(args) {
let appPath = cli_1.getOptionValue(args, '--app');
if (!appPath) {
throw new errors_1.RunException('--app argument is required.');
throw new errors_1.Exception('--app argument is required.');
}
const udid = cli_1.getOptionValue(args, '--target');
const preferSimulator = args.includes('--simulator');
const preferSimulator = args.includes('--virtual');
const waitForApp = args.includes('--connect');

@@ -30,20 +26,20 @@ const isIPA = appPath.endsWith('.ipa');

debug(`Unzipping .ipa to ${tempDir}`);
const appDir = await unzipApp(appPath, tempDir);
const appDir = await app_1.unzipIPA(appPath, tempDir);
appPath = path.join(tempDir, appDir);
}
const bundleId = await getBundleId(appPath);
const bundleId = await app_1.getBundleId(appPath);
const [devices, simulators] = await Promise.all([
device_1.getConnectedDevicesInfo(),
device_1.getSimulators(),
device_1.getConnectedDevices(),
simulator_1.getSimulators(),
]);
// try to run on device or simulator with udid
if (udid) {
if (devices.find(d => d.id === udid)) {
await runOnDevice(udid, appPath, bundleId, waitForApp);
if (devices.find(d => d.UniqueDeviceID === udid)) {
await device_1.runOnDevice(udid, appPath, bundleId, waitForApp);
}
else if (simulators.find(s => s.id === udid)) {
await runOnSimulator(udid, appPath, bundleId, waitForApp);
else if (simulators.find(s => s.udid === udid)) {
await simulator_1.runOnSimulator(udid, appPath, bundleId, waitForApp);
}
else {
throw new Error(`No device or simulator with udid ${udid} found`);
throw new errors_1.Exception(`No device or simulator with udid ${udid} found`);
}

@@ -53,7 +49,7 @@ }

// no udid, use first connected device
await runOnDevice(devices[0].id, appPath, bundleId, waitForApp);
await device_1.runOnDevice(devices[0].UniqueDeviceID, appPath, bundleId, waitForApp);
}
else {
// use default sim
await runOnSimulator(simulators[simulators.length - 1].id, appPath, bundleId, waitForApp);
await simulator_1.runOnSimulator(simulators[simulators.length - 1].udid, appPath, bundleId, waitForApp);
}

@@ -71,207 +67,1 @@ }

exports.run = run;
async function runOnSimulator(udid, appPath, bundleId, waitForApp) {
debug(`Booting simulator ${udid}`);
const bootResult = child_process_1.spawnSync('xcrun', ['simctl', 'boot', udid], { encoding: 'utf8' });
// TODO: is there a better way to check this?
if (bootResult.status && !bootResult.stderr.includes('Unable to boot device in current state: Booted')) {
throw new Error(`There was an error booting simulator: ${bootResult.stderr}`);
}
debug(`Installing ${appPath} on ${udid}`);
const installResult = child_process_1.spawnSync('xcrun', ['simctl', 'install', udid, appPath], { encoding: 'utf8' });
if (installResult.status) {
throw new Error(`There was an error installing app on simulator: ${installResult.stderr}`);
}
const xCodePath = await getXCodePath();
debug(`Running simulator ${udid}`);
const openResult = child_process_1.spawnSync('open', [`${xCodePath}/Applications/Simulator.app`, '--args', '-CurrentDeviceUDID', udid], { encoding: 'utf8' });
if (openResult.status) {
throw new Error(`There was an error opening simulator: ${openResult.stderr}`);
}
debug(`Launching ${appPath} on ${udid}`);
const launchResult = child_process_1.spawnSync('xcrun', ['simctl', 'launch', udid, bundleId], { encoding: 'utf8' });
if (launchResult.status) {
throw new Error(`There was an error launching app on simulator: ${launchResult.stderr}`);
}
if (waitForApp) {
process_1.onBeforeExit(async () => {
const terminateResult = child_process_1.spawnSync('xcrun', ['simctl', 'terminate', udid, bundleId], { encoding: 'utf8' });
if (terminateResult.status) {
debug('Unable to terminate app on simulator');
}
});
process.stdout.write(`Waiting for app to close...\n`);
await waitForSimulatorClose(udid, bundleId);
}
}
async function waitForSimulatorClose(udid, bundleId) {
return new Promise(resolve => {
// poll service list for bundle id
const interval = setInterval(async () => {
try {
const data = child_process_1.spawnSync('xcrun', ['simctl', 'spawn', udid, 'launchctl', 'list'], { encoding: 'utf8' });
// if bundle id isn't in list, app isn't running
if (data.stdout.indexOf(bundleId) === -1) {
clearInterval(interval);
resolve();
}
}
catch (e) {
debug('Error received from launchctl: %O', e);
debug('App %s no longer found in process list for %s', bundleId, udid);
clearInterval(interval);
resolve();
}
}, 500);
});
}
async function runOnDevice(udid, appPath, bundleId, waitForApp) {
const clientManager = await node_ioslib_1.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);
const { [bundleId]: appInfo } = await installer.lookupApp([bundleId]);
// launch fails with EBusy or ENotFound if you try to launch immediately after install
await wait(200);
const debugServerClient = await launchApp(clientManager, appInfo);
if (waitForApp) {
process_1.onBeforeExit(async () => {
// causes continue() to return
debugServerClient.halt();
// give continue() time to return response
await 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 getDeveloperDiskImagePath(version);
const developerDiskImageSig = fs_1.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 node_ioslib_1.AFCError && err.status === node_ioslib_1.AFC_STATUS.OBJECT_NOT_FOUND) {
await afcClient.makeDirectory('PublicStaging');
}
else {
throw err;
}
}
await afcClient.uploadDirectory(srcPath, destinationPath);
}
async function launchApp(clientManager, appInfo) {
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') {
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 wait(500);
}
else {
throw new errors_1.RunException(`There was an error launching app: ${result}`);
}
}
throw new errors_1.RunException('Unable to launch app, number of tries exceeded');
}
async function getXCodePath() {
try {
const { stdout } = await process_1.execFile('xcode-select', ['-p'], { encoding: 'utf8' });
if (stdout) {
return stdout.trim();
}
}
catch (_a) { } // tslint:disable-line
throw new Error('Unable to get Xcode location. Is Xcode installed?');
}
async function getDeveloperDiskImagePath(version) {
const xCodePath = await getXCodePath();
const versionDirs = await utils_fs_1.readDir(`${xCodePath}/Platforms/iPhoneOS.platform/DeviceSupport/`);
const versionPrefix = version.match(/\d+\.\d+/);
if (versionPrefix === null) {
throw new Error(`Invalid iOS version: ${version}`);
}
// Can look like "11.2 (15C107)"
for (const dir of versionDirs) {
if (dir.includes(versionPrefix[0])) {
return `${xCodePath}/Platforms/iPhoneOS.platform/DeviceSupport/${dir}/DeveloperDiskImage.dmg`;
}
}
throw new Error(`Unable to find Developer Disk Image path for SDK ${version}. Do you have the right version of Xcode?`);
}
// TODO: cross platform? Use plist/bplist
async function getBundleId(packagePath) {
const plistPath = path.resolve(packagePath, 'Info.plist');
try {
const { stdout } = await process_1.execFile('/usr/libexec/PlistBuddy', ['-c', 'Print :CFBundleIdentifier', plistPath], { encoding: 'utf8' });
if (stdout) {
return stdout.trim();
}
}
catch (_a) { } // tslint:disable-line
throw new Error('Unable to get app bundle identifier');
}
async function unzipApp(srcPath, destPath) {
const yauzl = await Promise.resolve().then(() => require('yauzl'));
const open = util_1.promisify(yauzl.open.bind(yauzl));
let appDir = '';
return new Promise(async (resolve, reject) => {
const zipfile = await open(srcPath, { lazyEntries: true });
const openReadStream = util_1.promisify(zipfile.openReadStream.bind(zipfile));
zipfile.once('error', reject);
zipfile.once('end', () => { appDir ? resolve(appDir) : reject('Unable to determine .app directory from .ipa'); });
zipfile.readEntry();
zipfile.on('entry', async (entry) => {
debug(`Unzip: ${entry.fileName}`);
const dest = path.join(destPath, entry.fileName);
if (entry.fileName.endsWith('/')) {
await utils_fs_1.mkdirp(dest);
if (entry.fileName.endsWith('.app/')) {
appDir = entry.fileName;
}
zipfile.readEntry();
}
else {
await utils_fs_1.mkdirp(path.dirname(dest));
const readStream = await openReadStream(entry);
readStream.on('end', () => { zipfile.readEntry(); });
const writeStream = fs_1.createWriteStream(path.join(destPath, entry.fileName));
readStream.pipe(writeStream);
}
});
});
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const child_process_1 = require("child_process"); // TODO: need cross-spawn for windows?
const Debug = require("debug");
const fs_1 = require("fs");
const node_ioslib_1 = require("node-ioslib");
async function getSimulators() {
const simctl = child_process_1.spawnSync('xcrun', ['simctl', 'list', '--json'], { encoding: 'utf8' });
const output = JSON.parse(simctl.stdout);
return output.runtimes
.filter(runtime => runtime.name.indexOf('watch') === -1 && runtime.name.indexOf('tv') === -1)
.map(runtime => output.devices[runtime.name]
.filter(device => !device.availability.includes('unavailable'))
.map(device => ({
name: device.name,
sdkVersion: runtime.version,
id: device.udid,
})))
.reduce((prev, next) => prev.concat(next)) // flatten array of runtime devices arrays
.sort((a, b) => a.name < b.name ? -1 : 1);
}
exports.getSimulators = getSimulators;
async function getConnectedDevicesInfo() {
const path = require("path");
const util_1 = require("util");
const errors_1 = require("../../errors");
const process_1 = require("../../utils/process");
const path_1 = require("./path");
const debug = Debug('native-run:ios:utils:device');
const wait = util_1.promisify(setTimeout);
async function getConnectedDevices() {
const usbmuxClient = new node_ioslib_1.UsbmuxdClient(node_ioslib_1.UsbmuxdClient.connectUsbmuxdSocket());
const devices = await usbmuxClient.getDevices();
const usbmuxDevices = await usbmuxClient.getDevices();
usbmuxClient.socket.end();
const deviceInfos = await Promise.all(devices.map(async (device) => {
const socket = await new node_ioslib_1.UsbmuxdClient(node_ioslib_1.UsbmuxdClient.connectUsbmuxdSocket()).connect(device, 62078);
const deviceInfo = await new node_ioslib_1.LockdowndClient(socket).getAllValues();
return Promise.all(usbmuxDevices.map(async (d) => {
const socket = await new node_ioslib_1.UsbmuxdClient(node_ioslib_1.UsbmuxdClient.connectUsbmuxdSocket()).connect(d, 62078);
const device = await new node_ioslib_1.LockdowndClient(socket).getAllValues();
socket.end();
return deviceInfo;
return device;
}));
return deviceInfos.map(deviceInfo => ({
name: deviceInfo.DeviceName,
model: deviceInfo.ProductType,
sdkVersion: deviceInfo.ProductVersion,
id: deviceInfo.UniqueDeviceID,
}));
}
exports.getConnectedDevicesInfo = getConnectedDevicesInfo;
exports.getConnectedDevices = getConnectedDevices;
async function runOnDevice(udid, appPath, bundleId, waitForApp) {
const clientManager = await node_ioslib_1.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);
const { [bundleId]: appInfo } = await installer.lookupApp([bundleId]);
// launch fails with EBusy or ENotFound if you try to launch immediately after install
await wait(200);
const debugServerClient = await launchApp(clientManager, appInfo);
if (waitForApp) {
process_1.onBeforeExit(async () => {
// causes continue() to return
debugServerClient.halt();
// give continue() time to return response
await 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();
}
}
exports.runOnDevice = runOnDevice;
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 path_1.getDeveloperDiskImagePath(version);
const developerDiskImageSig = fs_1.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 node_ioslib_1.AFCError && err.status === node_ioslib_1.AFC_STATUS.OBJECT_NOT_FOUND) {
await afcClient.makeDirectory('PublicStaging');
}
else {
throw err;
}
}
await afcClient.uploadDirectory(srcPath, destinationPath);
}
async function launchApp(clientManager, appInfo) {
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') {
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 wait(500);
}
else {
throw new errors_1.Exception(`There was an error launching app: ${result}`);
}
}
throw new errors_1.Exception('Unable to launch app, number of tries exceeded');
}
{
"name": "native-run",
"version": "0.0.7",
"version": "0.0.10",
"description": "A CLI for running apps on iOS/Android devices and simulators/emulators",

@@ -5,0 +5,0 @@ "bin": {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc