perf: 🚀 合并无线连接及有线连接到设备列表

This commit is contained in:
viarotel 2023-09-18 15:07:28 +08:00
parent 63a3de514b
commit e84f24e816
13 changed files with 117 additions and 225 deletions

View File

@ -10,6 +10,11 @@ export default defineConfig({
plugins: [externalizeDepsPlugin()], plugins: [externalizeDepsPlugin()],
}, },
preload: { preload: {
resolve: {
alias: {
'@resources': resolve('resources'),
},
},
plugins: [externalizeDepsPlugin()], plugins: [externalizeDepsPlugin()],
}, },
renderer: { renderer: {

View File

@ -4,7 +4,8 @@
"compilerOptions": { "compilerOptions": {
"baseUrl": ".", "baseUrl": ".",
"paths": { "paths": {
"@renderer/*": ["src/renderer/src/*"] "@renderer/*": ["src/renderer/src/*"],
"@resources/*": ["resources/*"]
} }
} }
} }

View File

@ -16,7 +16,6 @@ function createWindow() {
webPreferences: { webPreferences: {
preload: join(__dirname, '../preload/index.js'), preload: join(__dirname, '../preload/index.js'),
sandbox: false, sandbox: false,
devTools: true,
}, },
}) })

View File

@ -1,6 +1,6 @@
import { contextBridge } from 'electron' import { contextBridge } from 'electron'
export function addContext(key, value) { export function exposeContext(key, value) {
if (process.contextIsolated) { if (process.contextIsolated) {
try { try {
contextBridge.exposeInMainWorld(key, value) contextBridge.exposeInMainWorld(key, value)

View File

@ -1,74 +1,4 @@
import { electronAPI } from '@electron-toolkit/preload' import plugins from './plugins/index.js'
import { Adb } from '@devicefarmer/adbkit' import { exposeContext } from './helpers/index.js'
import scrcpyPath from '../../resources/core/scrcpy.exe?asset&asarUnpack' plugins.install(exposeContext)
import adbPath from '../../resources/core/adb.exe?asset&asarUnpack'
import { addContext } from './helpers/index.js'
const util = require('node:util')
const exec = util.promisify(require('node:child_process').exec)
// Custom APIs for renderer
const api = {}
// Use `contextBridge` APIs to expose Electron APIs to
// renderer only if context isolation is enabled, otherwise
// just add to the DOM global.
addContext('electron', electronAPI)
addContext('api', api)
addContext('adbkit', () => {
const client = Adb.createClient({ bin: adbPath })
console.log('client', client)
const getDevices = async () => await client.listDevicesWithPaths()
const shell = async (id, command) => await client.getDevice(id).shell(command)
const kill = async (...params) => await client.kill(...params)
const connect = async (...params) => await client.connect(...params)
const disconnect = async (...params) => await client.disconnect(...params)
const watch = async (callback) => {
const tracker = await client.trackDevices()
tracker.on('add', (device) => {
callback(device)
})
tracker.on('remove', (device) => {
callback(device)
})
tracker.on('end', (ret) => {
callback(ret)
})
tracker.on('error', (err) => {
callback(err)
})
const close = () => tracker.end()
return close
}
window.addEventListener('beforeunload', () => {
kill()
})
return {
getDevices,
shell,
kill,
connect,
disconnect,
watch,
}
})
addContext('scrcpy', () => {
const shell = command =>
exec(`${scrcpyPath} ${command}`, { env: { ...process.env, ADB: adbPath } })
return {
shell,
}
})

View File

@ -0,0 +1,53 @@
import { Adb } from '@devicefarmer/adbkit'
import adbPath from '@resources/core/adb.exe?asset&asarUnpack'
let client = null
window.addEventListener('beforeunload', () => {
if (client) {
client.kill()
}
})
const getDevices = async () => await client.listDevicesWithPaths()
const shell = async (id, command) => await client.getDevice(id).shell(command)
const kill = async (...params) => await client.kill(...params)
const connect = async (...params) => await client.connect(...params)
const disconnect = async (...params) => await client.disconnect(...params)
const watch = async (callback) => {
const tracker = await client.trackDevices()
tracker.on('add', (device) => {
callback(device)
})
tracker.on('remove', (device) => {
callback(device)
})
tracker.on('end', (ret) => {
callback(ret)
})
tracker.on('error', (err) => {
callback(err)
})
const close = () => tracker.end()
return close
}
export default () => {
client = Adb.createClient({ bin: adbPath })
console.log('client', client)
return {
getDevices,
shell,
kill,
connect,
disconnect,
watch,
}
}

View File

@ -0,0 +1,3 @@
import { electronAPI } from '@electron-toolkit/preload'
export default () => electronAPI

View File

@ -0,0 +1,11 @@
import electron from './electron/index.js'
import adbkit from './adbkit/index.js'
import scrcpy from './scrcpy/index.js'
export default {
install(expose) {
expose('electron', electron())
expose('adbkit', adbkit())
expose('scrcpy', scrcpy())
},
}

View File

@ -0,0 +1,12 @@
import adbPath from '@resources/core/adb.exe?asset&asarUnpack'
import scrcpyPath from '@resources/core/scrcpy.exe?asset&asarUnpack'
const util = require('node:util')
const exec = util.promisify(require('node:child_process').exec)
const shell = command =>
exec(`${scrcpyPath} ${command}`, { env: { ...process.env, ADB: adbPath } })
export default () => ({
shell,
})

View File

@ -15,33 +15,27 @@
</template> </template>
<script> <script>
import Wired from './components/Wired/index.vue' import Devices from './components/Devices/index.vue'
import Wireless from './components/Wireless/index.vue'
import Advanced from './components/Advanced/index.vue' import Advanced from './components/Advanced/index.vue'
export default { export default {
components: { components: {
Wired, Devices,
Wireless,
Advanced, Advanced,
}, },
data() { data() {
return { return {
tabsModel: [ tabsModel: [
{ {
label: '有线模式', label: '设备列表',
prop: 'Wired', prop: 'Devices',
},
{
label: '无线模式',
prop: 'Wireless',
}, },
{ {
label: '高级配置', label: '高级配置',
prop: 'Advanced', prop: 'Advanced',
}, },
], ],
activeTab: 'Wired', activeTab: 'Devices',
} }
}, },
mounted() {}, mounted() {},

View File

@ -3,7 +3,7 @@
<div class="flex items-center flex-none space-x-2"> <div class="flex items-center flex-none space-x-2">
<el-input v-model="formData.host" placeholder="192.168.0.1" class="w-72"> <el-input v-model="formData.host" placeholder="192.168.0.1" class="w-72">
<template #prepend> <template #prepend>
无线调试地址 无线连接设备
</template> </template>
</el-input> </el-input>
<div class="text-gray-500 text-sm"> <div class="text-gray-500 text-sm">
@ -37,15 +37,18 @@
<el-table-column prop="id" label="设备 ID" /> <el-table-column prop="id" label="设备 ID" />
<el-table-column prop="name" label="设备名称"> <el-table-column prop="name" label="设备名称">
<template #default="{ row }"> <template #default="{ row }">
<div v-if="row.$unauthorized" class="flex items-center"> <div class="flex items-center">
<el-tooltip content="请重新插拔设备并点击允许USB调试" placement="top-start"> <el-tooltip
v-if="row.$unauthorized"
content="设备可能未授权成功请重新插拔设备并点击允许USB调试"
placement="top-start"
>
<el-icon class="mr-1 text-red-600 text-lg"> <el-icon class="mr-1 text-red-600 text-lg">
<WarningFilled /> <WarningFilled />
</el-icon> </el-icon>
</el-tooltip> </el-tooltip>
设备未授权 {{ row.name }}
</div> </div>
<span v-else class="">{{ row.name }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" width="300" align="center"> <el-table-column label="操作" width="300" align="center">
@ -53,11 +56,11 @@
<el-button type="primary" :loading="row.$loading" @click="handleStart(row)"> <el-button type="primary" :loading="row.$loading" @click="handleStart(row)">
{{ row.$loading ? '镜像中' : '开始镜像' }} {{ row.$loading ? '镜像中' : '开始镜像' }}
</el-button> </el-button>
<el-button :disabled="!row.$loading" type="default" @click="handleScreenUp(row)"> <el-button type="default" @click="handleScreenUp(row)">
点亮屏幕 点亮屏幕
</el-button> </el-button>
<el-button <el-button
:disabled="!row.$loading" v-if="row.$wireless"
type="danger" type="danger"
:loading="row.$stopLoading" :loading="row.$stopLoading"
@click="handleStop(row)" @click="handleStop(row)"
@ -146,18 +149,18 @@ export default {
}, },
async getDeviceData() { async getDeviceData() {
this.loading = true this.loading = true
await sleep(500) await sleep()
try { try {
const data = await this.$adb.getDevices() const data = await this.$adb.getDevices()
this.deviceList = (data || []) this.deviceList = (data || []).map(item => ({
.filter(item => isIPWithPort(item.id)) ...item,
.map(item => ({ name: item.model ? item.model.split(':')[1] : '未授权设备',
...item, $loading: false,
name: item.model ? item.model.split(':')[1] : '未授权设备', $stopLoading: false,
$loading: false, $unauthorized: item.type === 'unauthorized',
$stopLoading: false, $wireless: isIPWithPort(item.id),
$unauthorized: item.type === 'unauthorized', }))
}))
console.log('getDeviceData.data', this.deviceList) console.log('getDeviceData.data', this.deviceList)
} }
catch (error) { catch (error) {

View File

@ -1,119 +0,0 @@
<template>
<div class="h-full flex flex-col">
<div class="flex items-center flex-none">
<el-button type="primary" @click="getDeviceData">
刷新设备
</el-button>
<el-button type="warning" @click="handleReset">
重启服务
</el-button>
</div>
<div class="pt-4 flex-1 h-0 overflow-hidden">
<el-table
v-loading="loading"
:element-loading-text="loadingText"
:data="deviceList"
style="width: 100%"
border
height="100%"
>
<template #empty>
<el-empty description="设备列表为空" />
</template>
<el-table-column prop="id" label="设备 ID" />
<el-table-column prop="name" label="设备名称">
<template #default="{ row }">
<div v-if="row.$unauthorized" class="flex items-center">
<el-tooltip content="请重新插拔设备并点击允许USB调试" placement="top-start">
<el-icon class="mr-1 text-red-600 text-lg">
<WarningFilled />
</el-icon>
</el-tooltip>
设备未授权
</div>
<span v-else class="">{{ row.name }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="300" align="center">
<template #default="{ row }">
<el-button type="primary" :loading="row.$loading" @click="handleStart(row)">
{{ row.$loading ? '镜像中' : '开始镜像' }}
</el-button>
<el-button
:disabled="!row.$loading"
type="default"
@click="handleScreenUp(row)"
>
点亮屏幕
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</template>
<script>
import { isIPWithPort, sleep } from '@renderer/utils/index.js'
export default {
data() {
return {
loading: false,
loadingText: '初始化中...',
deviceList: [],
}
},
created() {
this.getDeviceData()
this.$adb.watch(() => {
this.getDeviceData()
})
},
methods: {
handleScreenUp(row) {
this.$adb.shell(row.id, 'input keyevent KEYCODE_POWER')
},
handleReset() {
this.$electron.ipcRenderer.send('restart-app')
},
async handleStart(row) {
row.$loading = true
try {
await this.$scrcpy.shell(`-s ${row.id}`)
}
catch (error) {
if (error.message)
this.$message.warning(error.message)
}
row.$loading = false
},
async getDeviceData() {
this.loading = true
await sleep(500)
try {
const data = await this.$adb.getDevices()
this.deviceList = (data || [])
.filter(item => !isIPWithPort(item.id))
.map(item => ({
...item,
name: item.model ? item.model.split(':')[1] : '未授权设备',
$loading: false,
$unauthorized: item.type === 'unauthorized',
}))
console.log('getDeviceData.data', this.deviceList)
}
catch (error) {
if (error.message)
this.$message.warning(error.message)
this.deviceList = []
}
this.loading = false
this.loadingText = '正在获取设备列表...'
},
},
}
</script>
<style></style>

View File

@ -11,7 +11,7 @@ const app = createApp(App)
app.use(plugins) app.use(plugins)
app.config.globalProperties.$electron = window.electron app.config.globalProperties.$electron = window.electron
app.config.globalProperties.$adb = window.adbkit() app.config.globalProperties.$adb = window.adbkit
app.config.globalProperties.$scrcpy = window.scrcpy() app.config.globalProperties.$scrcpy = window.scrcpy
app.mount('#app') app.mount('#app')