UNPKG

cadb

Version:

安卓/鸿蒙系统截图/录屏工具

298 lines (284 loc) 8.55 kB
/** * Created by Niki on 2024/10/12 15:24. * Email: m13296644326@163.com */ const program = require('commander'); const {execFileSync} = require('child_process'); const { shellConfigs, logRed, logGreen, ctripHarmony, ztripHarmony, ctripAndroid, ztripAndroid, } = require('../common/constants'); const { isHarmonyDeviceConnected, isAndroidDeviceConnected, chooseAndroidRealDeviceId, hdcPath, adbPath, chooseHarmonyRealDeviceId, loadOrCollectProjectPathBatch, } = require('../common/utils'); const path = require('path'); const os = require('os'); const fs = require('fs'); const _ = require('lodash'); const moment = require('moment'); // 安装包路径 let appointedFilePath = ''; let extraInstallCmd = ''; // TODO: 实现从项目安装debug安装包; 并指定安装路径 program // 使用中括号表示可选参数, 尖括号表示必选参数 .arguments('[filePath]') .option('-ca --ctripA', 'install ctrip android apk') .option('-za --ztripA', 'install ztrip android apk') .option('-ch --ctripH', 'install ctrip harmony hap') .option('-zh --ztripH', 'install ztrip harmony hap') .option('-c, --noCache', 'drop local project path cache') .action(async (filePath, optionArgs) => { await parseParams(filePath, optionArgs); run(); }) .parse(process.argv); async function parseParams(filePath, optionArgs) { if (!filePath && _.isEmpty(optionArgs)) { return; } if (filePath) { appointedFilePath = filePath; } else { let keyName = ''; const {ctripA, ztripA, ctripH, ztripH, noCache} = optionArgs; if (ctripA) { keyName = ctripAndroid; } else if (ztripA) { keyName = ztripAndroid; } else if (ctripH) { keyName = ctripHarmony; } else if (ztripH) { keyName = ztripHarmony; } if (!keyName) { return; } const pathList = await loadOrCollectProjectPathBatch([keyName], noCache); const projectPath = pathList[0]; const apkPathMap = require('../config/apk_path_map_config.json'); const { apkPath: relativeApkPath, apkPathBak: relativeApkPathBak, extraCmd = '', } = apkPathMap[keyName]; appointedFilePath = path.join(projectPath, relativeApkPath); if (!fs.existsSync(appointedFilePath)) { if (!relativeApkPathBak) { logRed(`安装包路径不存在: ${appointedFilePath}`); process.exit(); return; } // 使用备用路径 appointedFilePath = path.join(projectPath, relativeApkPathBak); } console.log('安装包路径: ', appointedFilePath); extraInstallCmd = extraCmd; } } async function run() { const ok = checkPathIfNeed(); if (!ok) { return; } const consumed = doAndroidInstall(); if (!consumed) { console.log('\r\n尝试连接鸿蒙设备'); await doHarmonyInstall(); } } async function doHarmonyInstall() { let dList = isHarmonyDeviceConnected(); if (!dList) { return false; } console.log('\r\n开始安装hap至鸿蒙设备\r\n'); const newestFileInfo = getNewestBundleFileInfo('hap'); // 仅自动模式拦截 if (!newestFileInfo && !appointedFilePath) { return false; } printBundleInfo(newestFileInfo); const realDeviceId = await chooseHarmonyRealDeviceId(dList); executeHarmonyInstall(newestFileInfo, realDeviceId); return true; } function doAndroidInstall() { let dList = isAndroidDeviceConnected(); if (!dList) { return false; } console.log('\r\n开始安装apk至安卓设备\r\n'); const newestFileInfo = getNewestBundleFileInfo('apk'); // 仅自动模式拦截 if (!newestFileInfo && !appointedFilePath) { return false; } printBundleInfo(newestFileInfo); executeAndroidInstall(newestFileInfo, chooseAndroidRealDeviceId(dList)); return true; } function checkPathIfNeed() { if (!appointedFilePath) { return true; } if (!fs.existsSync(appointedFilePath)) { logRed(`文件不存在: ${appointedFilePath}`); return false; } if ( !appointedFilePath.endsWith('apk') && !appointedFilePath.endsWith('hap') ) { logRed(`文件后缀不正确: ${appointedFilePath}`); return false; } return true; } function executeHarmonyInstall(fileInfo, realDeviceCmd = '') { console.log('\r\neverything is ok, performing install task\r\n'); const cmdInstall = ['install', fileInfo?.filePath || appointedFilePath]; if (realDeviceCmd) { cmdInstall.unshift(...realDeviceCmd.split(' ')); } let resultHM = execFileSync(hdcPath, cmdInstall, shellConfigs); console.log('execute: ', `hdc ${cmdInstall.join(' ')}\r\n`); console.log(resultHM); if (resultHM.includes('successfully.')) { logGreen('安装成功\r\n'); } else { logRed('安装失败\r\n'); } } function executeAndroidInstall(fileInfo, realDeviceCmd = '') { console.log('\r\neverything is ok, performing install task\r\n'); const cmdInstall = [ 'install', extraInstallCmd, fileInfo?.filePath || appointedFilePath, ]; if (realDeviceCmd) { cmdInstall.unshift(...realDeviceCmd.split(' ')); } let result = execFileSync(adbPath, cmdInstall, shellConfigs); console.log('execute: ', `adb ${cmdInstall.join(' ')}\r\n`); console.log(result); if (result.includes('Success')) { logGreen('安装成功\r\n'); } else { logRed('安装失败\r\n'); } } // ZhiXing_V10.9.0_10-14_16-48_hgb_Release_PROD_19553812.hap // ZhiXing_V10.9.0_10-15_11-30_10037_PROD_19558710.apk // 例子2: ZhiXing_V10.9.0_hgb_Release_PROD_19568481.hap /** * 获取一个小时内的最新的安装文件 */ function getNewestBundleFileInfo(fileType) { let newestFilePath; let newestFileName; if (!appointedFilePath) { const bundleFileList = fs .readdirSync(getDefaultDownloadPath()) .filter(bFileName => { return ( bFileName.endsWith(`.${fileType}`) && /.+_V\d+\.\d+\.\d+_.+/.test(bFileName) ); }) .sort((a, b) => { return ( fs.statSync(path.join(getDefaultDownloadPath(), b)).mtimeMs - fs.statSync(path.join(getDefaultDownloadPath(), a)).mtimeMs ); }); if (_.isEmpty(bundleFileList)) { logRed(`${getDefaultDownloadPath()}目录下未找到${fileType}文件\r\n`); return null; } newestFilePath = path.join(getDefaultDownloadPath(), bundleFileList[0]); newestFileName = bundleFileList[0]; } else { newestFilePath = appointedFilePath; newestFileName = path.basename(appointedFilePath); } console.log(`file: ${newestFileName}`); // 一个小时之内的文件; 暂时不做校验 /*if (Date.now() - fs.statSync(newestFilePath).mtimeMs > 1000 * 60 * 60) { logRed( `${getDefaultDownloadPath()}目录下未找到1小时内的${fileType}文件\r\n`, ); return null; }*/ // 例子1: ZhiXing_App_V10.8.8_09-29_14-11_Release_PROD_19515986.hap // 例子2: ZhiXing_V10.9.0_hgb_Release_PROD_19568481.hap if (/(.+)_(V\d+\.\d+\.\d+)_(.+)/.test(newestFileName)) { const rest = RegExp.$3; const appName = RegExp.$1; const versionName = RegExp.$2; let otherInfo = null; if (/(\d{2}-\d{2}_\d{2}-\d{2})_.+/.test(rest)) { const [, , buildMode = '', env = '', buildId = ''] = rest.split('_'); otherInfo = { env, buildMode, buildId: buildId.replace(`.${fileType}`, ''), }; } else if (/([a-zA-Z]+)_.+/.test(rest)) { const [, buildMode = '', env = '', buildId = ''] = rest.split('_'); otherInfo = { env, buildMode, buildId: buildId.replace(`.${fileType}`, ''), }; } if (!otherInfo) { return null; } return { appName, versionName, filePath: newestFilePath, createTime: fs.statSync(newestFilePath).mtimeMs, ...otherInfo, }; } return null; } function printBundleInfo(fileInfo) { if (_.isEmpty(fileInfo)) { return; } const tableData = {}; if (fileInfo.appName.toLowerCase().includes('zhixing')) { tableData['应用名称'] = '智行'; } if (fileInfo.appName.toLowerCase().includes('ctrip')) { tableData['应用名称'] = '携程'; } tableData['版本号'] = fileInfo.versionName; tableData['环境'] = fileInfo.env; tableData['构建模式'] = fileInfo.buildMode; tableData['下载时间'] = `${moment( fileInfo.createTime, null, 'zh-cn', ).fromNow()}`; // tableData['构建ID'] = fileInfo.buildId; console.table(tableData); } function getDefaultDownloadPath() { return path.resolve(os.homedir(), 'Downloads'); }