appium-xcuitest-driver
Version:
Appium driver for iOS using XCUITest for backend
116 lines • 5.05 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AppTerminationClient = void 0;
const lodash_1 = __importDefault(require("lodash"));
const appium_ios_device_1 = require("appium-ios-device");
const utils_1 = require("../utils");
const installation_proxy_client_1 = require("./installation-proxy-client");
const remotexpc_utils_1 = require("./remotexpc-utils");
class AppTerminationClient {
udid;
platformVersion;
devicectl;
log;
constructor(udid, platformVersion, devicectl, log) {
this.udid = udid;
this.platformVersion = platformVersion;
this.devicectl = devicectl;
this.log = log;
}
async terminate(bundleId) {
let result;
if ((0, utils_1.isIos18OrNewerPlatform)(this.platformVersion)) {
try {
result = await this.terminateRemoteXPC(bundleId);
}
catch (err) {
this.log.warn(`Failed to terminate '${bundleId}' via RemoteXPC: ${err.message}`);
result = await this.terminateLegacy(bundleId);
}
}
else {
result = await this.terminateLegacy(bundleId);
}
if (result.terminated) {
this.log.debug(`Killed process for '${bundleId}' app with PID ${result.pid}`);
return true;
}
switch (result.reason) {
case 'not_running':
this.log.info(`The process of '${bundleId}' app was not running`);
break;
case 'error':
this.log.warn(`Failed to kill '${bundleId}'. Original error: ${result.detail ?? 'unknown'}`);
break;
}
return false;
}
async terminateRemoteXPC(bundleId) {
const Services = await (0, remotexpc_utils_1.getRemoteXPCServices)();
const dvt = await Services.startDVTService(this.udid);
const remoteXPCConnection = dvt.remoteXPC;
try {
const pid = await dvt.processControl.getPidForBundleIdentifier(bundleId);
if (!pid) {
return { terminated: false, reason: 'not_running' };
}
await dvt.processControl.kill(pid);
return { terminated: true, pid };
}
finally {
await remoteXPCConnection.close();
}
}
async terminateLegacy(bundleId) {
let instrumentService;
let installProxyClient;
try {
installProxyClient = await installation_proxy_client_1.InstallationProxyClient.create(this.udid, false);
const apps = await installProxyClient.listApplications({
returnAttributes: ['CFBundleIdentifier', 'CFBundleExecutable'],
});
if (!apps[bundleId]) {
return { terminated: false, reason: 'not_running' };
}
const executableName = apps[bundleId].CFBundleExecutable;
this.log.debug(`The executable name for the bundle id '${bundleId}' was '${executableName}'`);
if ((0, utils_1.isIos17OrNewerPlatform)(this.platformVersion)) {
this.log.debug(`Calling devicectl to kill the process`);
const pids = (await this.devicectl.listProcesses())
.filter(({ executable }) => executable.endsWith(`/${executableName}`))
.map(({ processIdentifier }) => processIdentifier);
if (lodash_1.default.isEmpty(pids)) {
return { terminated: false, reason: 'not_running' };
}
await this.devicectl.sendSignalToProcess(pids[0], 2);
return { terminated: true, pid: pids[0] };
}
// iOS < 17: use instrument service
instrumentService = await appium_ios_device_1.services.startInstrumentService(this.udid);
const processes = await instrumentService.callChannel(appium_ios_device_1.INSTRUMENT_CHANNEL.DEVICE_INFO, 'runningProcesses');
const process = processes.selector.find((proc) => proc.name === executableName);
if (!process) {
return { terminated: false, reason: 'not_running' };
}
await instrumentService.callChannel(appium_ios_device_1.INSTRUMENT_CHANNEL.PROCESS_CONTROL, 'killPid:', `${process.pid}`);
return { terminated: true, pid: process.pid };
}
catch (err) {
const detail = err.stderr ?? err.message;
return { terminated: false, reason: 'error', detail: String(detail) };
}
finally {
if (installProxyClient) {
await installProxyClient.close();
}
if (instrumentService) {
instrumentService.close();
}
}
}
}
exports.AppTerminationClient = AppTerminationClient;
//# sourceMappingURL=app-termination-client.js.map