appium-adb
Version:
Android Debug Bridge interface
283 lines • 10.9 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getJavaForOs = exports.getJavaHome = exports.getResourcePath = exports.DEFAULT_ADB_EXEC_TIMEOUT = exports.APK_INSTALL_TIMEOUT = exports.APK_EXTENSION = exports.APKS_EXTENSION = void 0;
exports.getSdkRootFromEnv = getSdkRootFromEnv;
exports.requireSdkRoot = requireSdkRoot;
exports.unzipFile = unzipFile;
exports.buildInstallArgs = buildInstallArgs;
exports.readPackageManifest = readPackageManifest;
const node_path_1 = __importDefault(require("node:path"));
const support_1 = require("@appium/support");
const logger_1 = require("./logger");
const lodash_1 = __importDefault(require("lodash"));
const teen_process_1 = require("teen_process");
// Constants
exports.APKS_EXTENSION = '.apks';
exports.APK_EXTENSION = '.apk';
exports.APK_INSTALL_TIMEOUT = 60000;
exports.DEFAULT_ADB_EXEC_TIMEOUT = 20000; // in milliseconds
const MODULE_NAME = 'appium-adb';
// Public methods
/**
* Calculates the absolute path to the given resource
*/
exports.getResourcePath = lodash_1.default.memoize(async function getResourcePath(relPath) {
const moduleRoot = await getModuleRoot();
const resultPath = node_path_1.default.resolve(moduleRoot, relPath);
if (!(await support_1.fs.exists(resultPath))) {
throw new Error(`Cannot find the resource '${relPath}' under the '${moduleRoot}' ` +
`folder of ${MODULE_NAME} Node.js module`);
}
return resultPath;
});
/**
* Retrieves the actual path to SDK root folder from the system environment
*/
function getSdkRootFromEnv() {
return process.env.ANDROID_HOME || process.env.ANDROID_SDK_ROOT;
}
/**
* Retrieves the actual path to SDK root folder
*/
async function requireSdkRoot(customRoot = null) {
const sdkRoot = customRoot || getSdkRootFromEnv();
const docMsg = 'Read https://developer.android.com/studio/command-line/variables for more details';
if (!sdkRoot || lodash_1.default.isEmpty(sdkRoot)) {
throw new Error(`Neither ANDROID_HOME nor ANDROID_SDK_ROOT environment variable was exported. ${docMsg}`);
}
if (!(await support_1.fs.exists(sdkRoot))) {
throw new Error(`The Android SDK root folder '${sdkRoot}' does not exist on the local file system. ${docMsg}`);
}
const stats = await support_1.fs.stat(sdkRoot);
if (!stats.isDirectory()) {
throw new Error(`The Android SDK root '${sdkRoot}' must be a folder. ${docMsg}`);
}
return sdkRoot;
}
/**
* @param zipPath
* @param dstRoot
*/
async function unzipFile(zipPath, dstRoot = node_path_1.default.dirname(zipPath)) {
logger_1.log.debug(`Unzipping '${zipPath}' to '${dstRoot}'`);
await support_1.zip.assertValidZip(zipPath);
await support_1.zip.extractAllTo(zipPath, dstRoot);
logger_1.log.debug('Unzip successful');
}
exports.getJavaHome = lodash_1.default.memoize(async function getJavaHome() {
const result = process.env.JAVA_HOME;
if (!result) {
throw new Error('The JAVA_HOME environment variable is not set for the current process');
}
if (!(await support_1.fs.exists(result))) {
throw new Error(`The JAVA_HOME location '${result}' must exist`);
}
const stats = await support_1.fs.stat(result);
if (!stats.isDirectory()) {
throw new Error(`The JAVA_HOME location '${result}' must be a valid folder`);
}
return result;
});
exports.getJavaForOs = lodash_1.default.memoize(async function getJavaForOs() {
let javaHome;
let errMsg;
try {
javaHome = await (0, exports.getJavaHome)();
}
catch (err) {
const error = err;
errMsg = error.message;
}
const executableName = `java${support_1.system.isWindows() ? '.exe' : ''}`;
if (javaHome) {
const resultPath = node_path_1.default.resolve(javaHome, 'bin', executableName);
if (await support_1.fs.exists(resultPath)) {
return resultPath;
}
}
try {
return await support_1.fs.which(executableName);
}
catch {
// Ignore and throw custom error below
}
throw new Error(`The '${executableName}' binary could not be found ` +
`neither in PATH nor under JAVA_HOME (${javaHome ? node_path_1.default.resolve(javaHome, 'bin') : errMsg})`);
});
/**
* Transforms given options into the list of `adb install.install-multiple` command arguments
*/
function buildInstallArgs(apiLevel, options = {}) {
const result = [];
if (!support_1.util.hasValue(options.replace) || options.replace) {
result.push('-r');
}
if (options.allowTestPackages) {
result.push('-t');
}
if (options.useSdcard) {
result.push('-s');
}
if (options.grantPermissions) {
if (apiLevel < 23) {
logger_1.log.debug(`Skipping permissions grant option, since ` +
`the current API level ${apiLevel} does not support applications ` +
`permissions customization`);
}
else {
result.push('-g');
}
}
// For multiple-install
if (options.partialInstall) {
result.push('-p');
}
return result;
}
/**
* Extracts various package manifest details
* from the given application file.
*/
async function readPackageManifest(apkPath) {
await this.initAapt2();
const aapt2Binary = this.binaries?.aapt2;
if (!aapt2Binary) {
throw new Error('aapt2 binary is not available');
}
const args = ['dump', 'badging', apkPath];
logger_1.log.debug(`Reading package manifest: '${support_1.util.quote([aapt2Binary, ...args])}'`);
let stdout;
try {
({ stdout } = await (0, teen_process_1.exec)(aapt2Binary, args));
}
catch (e) {
const error = e;
const prefix = `Cannot read the manifest from '${apkPath}'`;
const suffix = `Original error: ${error.stderr || error.message}`;
if (error.stderr && lodash_1.default.includes(error.stderr, `Unable to open 'badging'`)) {
throw new Error(`${prefix}. Update build tools to use a newer aapt2 version. ${suffix}`);
}
throw new Error(`${prefix}. ${suffix}`);
}
const extractValue = (line, propPattern, valueTransformer) => {
const match = propPattern.exec(line);
if (match) {
return valueTransformer ? valueTransformer(match[1]) : match[1];
}
return undefined;
};
const extractArray = (line, propPattern, valueTransformer) => {
let match;
const resultArray = [];
while ((match = propPattern.exec(line))) {
resultArray.push(valueTransformer ? valueTransformer(match[1]) : match[1]);
}
return resultArray;
};
const toInt = (x) => parseInt(x, 10);
const result = {
name: '',
versionCode: 0,
minSdkVersion: 0,
compileSdkVersion: 0,
usesPermissions: [],
launchableActivity: {
name: '',
},
architectures: [],
locales: [],
densities: [],
};
for (const line of stdout.split('\n')) {
if (line.startsWith('package:')) {
for (const [name, pattern, transformer] of [
['name', /name='([^']+)'/, null],
['versionCode', /versionCode='([^']+)'/, toInt],
['versionName', /versionName='([^']+)'/, null],
['platformBuildVersionName', /platformBuildVersionName='([^']+)'/, null],
['platformBuildVersionCode', /platformBuildVersionCode='([^']+)'/, toInt],
['compileSdkVersion', /compileSdkVersion='([^']+)'/, toInt],
['compileSdkVersionCodename', /compileSdkVersionCodename='([^']+)'/, null],
]) {
const value = extractValue(line, pattern, transformer);
if (!lodash_1.default.isUndefined(value)) {
result[name] = value;
}
}
}
else if (line.startsWith('sdkVersion:') || line.startsWith('minSdkVersion:')) {
const value = extractValue(line, /[sS]dkVersion:'([^']+)'/, toInt);
if (value) {
result.minSdkVersion = value;
}
}
else if (line.startsWith('targetSdkVersion:')) {
const value = extractValue(line, /targetSdkVersion:'([^']+)'/, toInt);
if (value) {
result.targetSdkVersion = value;
}
}
else if (line.startsWith('uses-permission:')) {
const value = extractValue(line, /name='([^']+)'/, null);
if (value) {
result.usesPermissions.push(value);
}
}
else if (line.startsWith('launchable-activity:')) {
for (const [name, pattern] of [
['name', /name='([^']+)'/],
['label', /label='([^']+)'/],
['icon', /icon='([^']+)'/],
]) {
const value = extractValue(line, pattern, null);
if (value) {
result.launchableActivity[name] = value;
}
}
}
else if (line.startsWith('locales:')) {
result.locales = extractArray(line, /'([^']+)'/g, null);
}
else if (line.startsWith('native-code:')) {
result.architectures = extractArray(line, /'([^']+)'/g, null);
}
else if (line.startsWith('densities:')) {
result.densities = extractArray(line, /'([^']+)'/g, toInt);
}
}
return result;
}
// Private methods
/**
* Calculates the absolute path to the current module's root folder
*/
const getModuleRoot = lodash_1.default.memoize(async function getModuleRoot() {
let moduleRoot = node_path_1.default.dirname(node_path_1.default.resolve(__filename));
let isAtFsRoot = false;
while (!isAtFsRoot) {
const manifestPath = node_path_1.default.join(moduleRoot, 'package.json');
try {
if (await support_1.fs.exists(manifestPath)) {
const manifestContent = await support_1.fs.readFile(manifestPath, 'utf8');
const manifest = JSON.parse(manifestContent);
if (manifest.name === MODULE_NAME) {
return moduleRoot;
}
}
}
catch {
// Ignore errors and continue searching
}
const parentDir = node_path_1.default.dirname(moduleRoot);
isAtFsRoot = moduleRoot.length <= parentDir.length;
moduleRoot = parentDir;
}
if (isAtFsRoot) {
throw new Error(`Cannot find the root folder of the ${MODULE_NAME} Node.js module`);
}
return moduleRoot;
});
//# sourceMappingURL=helpers.js.map