UNPKG

appium-adb

Version:

Android Debug Bridge interface

146 lines 6.55 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.extractUniversalApk = extractUniversalApk; const logger_1 = require("../logger"); const node_path_1 = __importDefault(require("node:path")); const support_1 = require("@appium/support"); const lru_cache_1 = require("lru-cache"); const helpers_1 = require("../helpers"); const async_lock_1 = __importDefault(require("async-lock")); const bluebird_1 = __importDefault(require("bluebird")); const node_crypto_1 = __importDefault(require("node:crypto")); const AAB_CACHE = new lru_cache_1.LRUCache({ max: 10, dispose: (extractedFilesRoot) => support_1.fs.rimraf(extractedFilesRoot), }); const AAB_CACHE_GUARD = new async_lock_1.default(); const UNIVERSAL_APK = 'universal.apk'; process.on('exit', () => { if (!AAB_CACHE.size) { return; } const paths = [...AAB_CACHE.values()]; logger_1.log.debug(`Performing cleanup of ${paths.length} cached .aab ` + support_1.util.pluralize('package', paths.length)); for (const appPath of paths) { try { // Asynchronous calls are not supported in onExit handler support_1.fs.rimrafSync(appPath); } catch (e) { logger_1.log.warn(e.message); } } }); /** * Builds a universal .apk from the given .aab package. See * https://developer.android.com/studio/command-line/bundletool#generate_apks * for more details. * * @param aabPath Full path to the source .aab package * @param opts Options for APK creation * @returns The path to the resulting universal .apk. The .apk is stored in the internal cache * by default. * @throws {Error} If there was an error while creating the universal .apk */ async function extractUniversalApk(aabPath, opts = {}) { if (!(await support_1.fs.exists(aabPath))) { throw new Error(`The file at '${aabPath}' either does not exist or is not accessible`); } const aabName = node_path_1.default.basename(aabPath); const apkName = aabName.substring(0, aabName.length - node_path_1.default.extname(aabName).length) + '.apk'; const tmpRoot = await support_1.tempDir.openDir(); const tmpApksPath = node_path_1.default.join(tmpRoot, `${aabName}.apks`); try { return await AAB_CACHE_GUARD.acquire(aabPath, async () => { const aabHash = await support_1.fs.hash(aabPath); const { keystore, keystorePassword, keyAlias, keyPassword } = opts; let cacheHash = aabHash; if (keystore) { if (!(await support_1.fs.exists(keystore))) { throw new Error(`The keystore file at '${keystore}' either does not exist ` + `or is not accessible`); } if (!keystorePassword || !keyAlias || !keyPassword) { throw new Error('It is mandatory to also provide keystore password, key alias, ' + 'and key password if the keystore path is set'); } const keystoreHash = await support_1.fs.hash(keystore); const keyAliasHash = node_crypto_1.default.createHash('sha1'); keyAliasHash.update(keyAlias); cacheHash = [cacheHash, keystoreHash, keyAliasHash.digest('hex')].join(':'); } logger_1.log.debug(`Calculated the cache key for '${aabPath}': ${cacheHash}`); if (AAB_CACHE.has(cacheHash)) { const cachedRoot = AAB_CACHE.get(cacheHash); if (cachedRoot) { const resultPath = node_path_1.default.resolve(cachedRoot, apkName); if (await support_1.fs.exists(resultPath)) { return resultPath; } } AAB_CACHE.delete(cacheHash); } await this.initAapt2(); const binaries = this.binaries; const args = [ 'build-apks', '--aapt2', binaries.aapt2, '--bundle', aabPath, '--output', tmpApksPath, ...(keystore ? [ '--ks', keystore, '--ks-pass', `pass:${keystorePassword}`, '--ks-key-alias', keyAlias, '--key-pass', `pass:${keyPassword}`, ] : []), '--mode=universal', ]; logger_1.log.debug(`Preparing universal .apks bundle from '${aabPath}'`); await this.execBundletool(args, `Cannot build a universal .apks bundle from '${aabPath}'`); logger_1.log.debug(`Unpacking universal application bundle at '${tmpApksPath}' to '${tmpRoot}'`); await (0, helpers_1.unzipFile)(tmpApksPath, tmpRoot); let universalApkPath; const fileDeletionPromises = []; const allFileNames = await support_1.fs.readdir(tmpRoot); for (const fileName of allFileNames) { const fullPath = node_path_1.default.join(tmpRoot, fileName); if (fileName === UNIVERSAL_APK) { universalApkPath = fullPath; } else { fileDeletionPromises.push(support_1.fs.rimraf(fullPath)); } } try { await bluebird_1.default.all(fileDeletionPromises); } catch { } if (!universalApkPath) { logger_1.log.debug(`The following items were extracted from the .aab bundle: ${allFileNames}`); throw new Error(`${UNIVERSAL_APK} cannot be found in '${aabPath}' bundle. ` + `Does the archive contain a valid application bundle?`); } const resultPath = node_path_1.default.join(tmpRoot, apkName); logger_1.log.debug(`Found ${UNIVERSAL_APK} at '${universalApkPath}'. Caching it to '${resultPath}'`); await support_1.fs.mv(universalApkPath, resultPath); AAB_CACHE.set(cacheHash, tmpRoot); return resultPath; }); } catch (e) { await support_1.fs.rimraf(tmpRoot); throw e; } } //# sourceMappingURL=aab-utils.js.map