forked from qinjian/FlexometerSetup
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
138 lines
4.5 KiB
138 lines
4.5 KiB
import { spawn } from 'child_process'
|
|
import path from 'path'
|
|
import fs from 'fs'
|
|
import fsp from 'fs/promises'
|
|
import { fileURLToPath } from 'url'
|
|
import { app } from 'electron'
|
|
|
|
// ESM 下没有 __dirname,使用 import.meta.url 计算当前目录
|
|
const __filename = fileURLToPath(import.meta.url)
|
|
const __dirname = path.dirname(__filename)
|
|
|
|
const isWin = process.platform === 'win32'
|
|
const adbBinary = isWin ? 'adb.exe' : 'adb'
|
|
|
|
// 解析 adb 可执行文件路径(开发/打包均可用)
|
|
function resolveAdbPath() {
|
|
const resources = process.resourcesPath || ''
|
|
const candidates = [
|
|
// 开发:项目根目录 resources/adbSDK/adb(.exe)(与 electron-builder extraResources 对应)
|
|
path.join(process.cwd(), 'resources', 'adbSDK', adbBinary),
|
|
// 开发:与本文件同级的 ../adbSDK/adb(.exe)
|
|
path.join(__dirname, '..', 'adbSDK', adbBinary),
|
|
// 开发:构建输出 out/adbSDK/adb(.exe)(如有)
|
|
path.join(process.cwd(), 'out', 'adbSDK', adbBinary),
|
|
// 生产:extraResources 复制到 resources/adbSDK
|
|
path.join(resources, 'adbSDK', adbBinary),
|
|
// 生产:若使用 asarUnpack,位于 app.asar.unpacked
|
|
path.join(resources, 'app.asar.unpacked', 'adbSDK', adbBinary)
|
|
]
|
|
|
|
for (const p of candidates) {
|
|
try {
|
|
if (fs.existsSync(p)) return p
|
|
} catch {}
|
|
}
|
|
throw new Error(
|
|
`adb executable not found. Tried:\n${candidates.join('\n')}\n` +
|
|
'Please ensure adbSDK exists in development (resources/adbSDK) and is listed in extraResources for production.'
|
|
)
|
|
}
|
|
|
|
const adbPath = resolveAdbPath()
|
|
const adbDir = path.dirname(adbPath)
|
|
|
|
function getAdbSerial(ip) {
|
|
if (!ip) throw new Error('ip required')
|
|
return ip.includes(':') ? ip : `${ip}:5555`
|
|
}
|
|
|
|
/**
|
|
* 运行 adb 命令的通用封装
|
|
*/
|
|
function runAdb(args, options = {}) {
|
|
return new Promise((resolve, reject) => {
|
|
// 先行校验,给出更明确的错误
|
|
if (!fs.existsSync(adbPath)) {
|
|
return reject(new Error(`adb not found at ${adbPath}`))
|
|
}
|
|
const child = spawn(adbPath, args, { cwd: adbDir, windowsHide: true, ...options })
|
|
let stdout = ''
|
|
let stderr = ''
|
|
|
|
child.stdout?.on('data', (d) => (stdout += d.toString()))
|
|
child.stderr?.on('data', (d) => (stderr += d.toString()))
|
|
child.on('error', (err) => reject(err))
|
|
child.on('close', (code) => {
|
|
if (code === 0) return resolve({ stdout: stdout.trim(), stderr: stderr.trim() })
|
|
const err = new Error(`adb exited with ${code}: ${stderr || stdout}`)
|
|
err.code = code
|
|
err.stdout = stdout
|
|
err.stderr = stderr
|
|
reject(err)
|
|
})
|
|
})
|
|
}
|
|
|
|
// 下面其余 API 保持不变(仅把 fs/promises 改为 fsp 引用)
|
|
async function connect(ip) {
|
|
if (!ip) throw new Error('ip required')
|
|
return runAdb(['connect', getAdbSerial(ip)])
|
|
}
|
|
|
|
async function disconnect(ip) {
|
|
if (ip) return runAdb(['disconnect', getAdbSerial(ip)])
|
|
return runAdb(['disconnect'])
|
|
}
|
|
|
|
async function pull(remotePath, destFilename, ip) {
|
|
const dest = path.join(adbDir, destFilename || path.basename(remotePath))
|
|
await fsp.mkdir(adbDir, { recursive: true })
|
|
const serialArgs = ip ? ['-s', getAdbSerial(ip)] : []
|
|
await runAdb([...serialArgs, 'pull', remotePath, dest])
|
|
return dest
|
|
}
|
|
|
|
async function push(localPath, remotePath, ip) {
|
|
const serialArgs = ip ? ['-s', getAdbSerial(ip)] : []
|
|
return runAdb([...serialArgs, 'push', localPath, remotePath])
|
|
}
|
|
|
|
async function readLocalOLE() {
|
|
const file = path.join(adbDir, 'OLE.ini')
|
|
const text = await fsp.readFile(file, 'utf8')
|
|
const lines = text.split(/\r?\n/).filter(Boolean)
|
|
return lines[0] ? lines[0] : null
|
|
}
|
|
|
|
async function writeFirstOLE(line1) {
|
|
const file = path.join(adbDir, 'OLE.ini')
|
|
let second = '1.000000'
|
|
try {
|
|
const text = await fsp.readFile(file, 'utf8')
|
|
const lines = text.split(/\r?\n/).filter(Boolean)
|
|
if (lines.length >= 2) second = lines[1]
|
|
} catch {}
|
|
const content = `${line1}\n${second}\n`
|
|
await fsp.writeFile(file, content, 'utf8')
|
|
return file
|
|
}
|
|
|
|
async function getParametersFromDevice(ip) {
|
|
if (ip) await connect(ip)
|
|
await pull('/data/OLE.ini', 'OLE.ini', ip)
|
|
return readLocalOLE()
|
|
}
|
|
|
|
async function setFirstParameter({ param, ip, toSystem = false }) {
|
|
if (param == null) throw new Error('param required')
|
|
const local = await writeFirstOLE(param)
|
|
if (ip) await connect(ip)
|
|
await push(local, '/data/', ip)
|
|
if (toSystem) {
|
|
await push(local, '/system/etc/', ip)
|
|
}
|
|
return { local }
|
|
}
|
|
|
|
export { adbPath, runAdb, connect, pull, push, readLocalOLE, writeFirstOLE, getParametersFromDevice, setFirstParameter, disconnect, getAdbSerial }
|
|
|