fix: 🔨 修复直接进行无线连接时没有处理配对设备的问题

This commit is contained in:
viarotel 2023-10-11 16:42:47 +08:00
parent 2371b26d6a
commit 4263d07076
11 changed files with 278 additions and 41 deletions

View File

@ -54,4 +54,4 @@ jobs:
dist/*.yml
dist/*.blockmap
env:
GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}

View File

@ -17,4 +17,4 @@ jobs:
with:
release-type: node
package-name: release-please-action
token: ${{ secrets.ACCESS_TOKEN }}
token: ${{ secrets.GH_TOKEN }}

View File

@ -1,3 +1,4 @@
provider: generic
url: https://example.com/auto-updates
provider: github
owner: viarotel-org
repo: escrcpy
updaterCacheDirName: escrcpy-updater

View File

@ -45,5 +45,6 @@ appImage:
artifactName: ${name}-${version}.${ext}
npmRebuild: false
publish:
provider: generic
url: https://example.com/auto-updates
provider: github
owner: viarotel-org
repo: escrcpy

View File

@ -19,7 +19,7 @@ function createWindow() {
// Create the browser window.
const mainWindow = new BrowserWindow({
icon,
minWidth: 900,
minWidth: 1000,
minHeight: 700,
show: false,
autoHideMenuBar: true,

View File

@ -1,4 +1,5 @@
import { app, ipcMain } from 'electron'
import './updater/index.js'
ipcMain.on('restart-app', () => {
app.relaunch()

View File

@ -0,0 +1,90 @@
import { app, dialog, ipcMain } from 'electron'
import { is } from '@electron-toolkit/utils'
import { autoUpdater } from 'electron-updater'
const path = require('node:path')
// dev-start, 这里是为了在本地做应用升级测试使用,正式环境请务必删除
if (is.dev && process.env.ELECTRON_RENDERER_URL) {
autoUpdater.updateConfigPath = path.join(__dirname, '../../../../dev-app-update.yml')
}
Object.defineProperty(app, 'isPackaged', {
get() {
return true
},
})
// dev-end
// 触发检查更新(此方法用于被渲染线程调用,例如页面点击检查更新按钮来调用此方法)
ipcMain.on('check-for-update', () => {
console.log('触发检查更新')
autoUpdater.checkForUpdates()
})
// 设置自动下载为false(默认为true检测到有更新就自动下载)
autoUpdater.autoDownload = false
// 检测下载错误
autoUpdater.on('error', (error) => {
console.error('更新异常', error)
})
// 检测是否需要更新
autoUpdater.on('checking-for-update', () => {
console.log('正在检查更新……')
})
// 检测到可以更新时
autoUpdater.on('update-available', (releaseInfo) => {
console.log('检测到新版本,确认是否下载')
const releaseNotes = releaseInfo.releaseNotes
let releaseContent = ''
if (releaseNotes) {
if (typeof releaseNotes === 'string') {
releaseContent = releaseNotes
}
else if (Array.isArray(releaseNotes)) {
releaseNotes.forEach((releaseNote) => {
releaseContent += `${releaseNote}\n`
})
}
}
else {
releaseContent = '暂无更新说明'
}
// 弹框确认是否下载更新releaseContent是更新日志
dialog
.showMessageBox({
type: 'info',
title: '应用有新的更新',
detail: releaseContent,
message: '发现新版本,是否现在更新?',
buttons: ['否', '是'],
})
.then(({ response }) => {
if (response === 1) {
// 下载更新
autoUpdater.downloadUpdate()
}
})
})
// 检测到不需要更新时
autoUpdater.on('update-not-available', () => {
console.log('现在使用的就是最新版本,不用更新')
})
// 更新下载进度
autoUpdater.on('download-progress', (progress) => {
console.log('下载进度', progress)
})
// 当需要更新的内容下载完成后
autoUpdater.on('update-downloaded', () => {
console.log('下载完成,准备更新')
dialog
.showMessageBox({
title: '安装更新',
message: '更新下载完毕,应用将重启并进行安装',
})
.then(() => {
// 退出并安装应用
setImmediate(() => autoUpdater.quitAndInstall())
})
})

View File

@ -12,17 +12,34 @@ window.addEventListener('beforeunload', () => {
}
})
const shell = async command => exec(`${adbPath} ${command}`)
const getDevices = async () => await client.listDevicesWithPaths()
const shell = async (id, command) => await client.getDevice(id).shell(command)
const rawShell = async command => exec(`${adbPath} ${command}`)
const deviceShell = 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 getDeviceIP = async (id) => {
try {
const { stdout } = await shell(`-s ${id} shell ip -f inet addr show wlan0`)
// console.log('stdout', stdout)
const reg = /inet ([0-9.]+)\/\d+/
const match = stdout.match(reg)
const value = match[1]
return value
}
catch (error) {
return false
}
}
const tcpip = async (id, port = 5555) => await client.getDevice(id).tcpip(port)
const watch = async (callback) => {
const tracker = await client.trackDevices()
tracker.on('add', (device) => {
callback('add', device)
tracker.on('add', async (ret) => {
const host = await getDeviceIP(ret.id)
callback('add', { ...ret, $host: host })
})
tracker.on('remove', (device) => {
@ -47,12 +64,14 @@ export default () => {
console.log('client', client)
return {
getDevices,
shell,
rawShell,
getDevices,
deviceShell,
kill,
connect,
disconnect,
watch,
getDeviceIP,
tcpip,
}
}

View File

@ -0,0 +1,90 @@
<template>
<el-dialog v-model="visible" title="无线配对" width="600" append-to-body>
<div class="text-red-500 text-sm pb-8 pl-4">
注意可以在 开发者选项 -> 无线调试(可以点进去) -> 使用配对码配对设备 中获取以下信息
</div>
<el-form :model="formData" label-width="100px">
<el-form-item label="配对IP地址" prop="host">
<el-input v-model="formData.host" placeholder="请输入配对IP地址" class="" clearable>
</el-input>
</el-form-item>
<el-form-item label="配对端口号" prop="port">
<el-input
v-model.number="formData.port"
type="number"
placeholder="请输入配对端口号"
:min="0"
clearable
class=""
>
</el-input>
</el-form-item>
<el-form-item
label="配对码"
prop="pair"
:rules="[{ required: true, message: '配对码不能为空' }]"
>
<el-input
v-model.number="formData.pair"
type="number"
placeholder="请输入配对码"
:min="0"
clearable
class=""
>
</el-input>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="handleClose">
取消
</el-button>
<el-button type="primary" @click="handleSubmit">
确定
</el-button>
</template>
</el-dialog>
</template>
<script>
export default {
emits: ['success'],
data() {
return {
visible: false,
formData: {
host: '',
port: '',
pair: '',
},
}
},
methods: {
show({ params = {} } = {}) {
this.formData = {
...this.$options.data().formData,
host: params.host,
}
this.visible = true
},
handleClose() {
this.visible = false
},
async handleSubmit() {
try {
const command = `pair ${this.formData.host}:${this.formData.port} ${this.formData.pair}`
// console.log(command)
await this.$adb.rawShell(command)
this.$emit('success')
this.handleClose()
}
catch (error) {
this.$message.warning(error.message)
}
},
},
}
</script>
<style></style>

View File

@ -1,7 +1,7 @@
<template>
<div class="h-full flex flex-col">
<div class="flex items-center flex-none space-x-2">
<el-input v-model="formData.host" placeholder="192.168.0.1" class="w-86" clearable>
<el-input v-model="formData.host" placeholder="192.168.0.1" class="w-86 flex-none" clearable>
<template #prepend>
无线连接
</template>
@ -15,7 +15,7 @@
placeholder="5555"
:min="0"
clearable
class="w-32"
class="w-32 flex-none"
>
</el-input>
@ -68,6 +68,9 @@
<el-button type="primary" :loading="row.$loading" @click="handleMirror(row)">
{{ row.$loading ? '镜像中' : '开始镜像' }}
</el-button>
<el-button v-if="!row.$wireless" type="primary" @click="handleWifi(row)">
无线模式
</el-button>
<el-button type="default" @click="handleScreenUp(row)">
点亮屏幕
</el-button>
@ -83,14 +86,19 @@
</el-table-column>
</el-table>
</div>
<PairDialog ref="pairDialog" @success="onPairSuccess" />
</div>
</template>
<script>
import { isIPWithPort, sleep } from '@renderer/utils/index.js'
import storage from '@renderer/utils/storages'
import PairDialog from './PairDialog/index.vue'
export default {
components: {
PairDialog,
},
data() {
const adbCache = storage.get('adbCache') || {}
return {
@ -106,55 +114,80 @@ export default {
},
created() {
this.getDeviceData()
this.$adb.watch(async (type, ret) => {
console.log('adb.watch.ret', ret)
this.$adb.watch(() => {
this.getDeviceData()
if (type === 'add' && !isIPWithPort(ret.id)) {
this.formData = {
...this.formData,
host: ret.$host,
}
}
})
},
methods: {
async handleWifi(row) {
try {
const host = await this.$adb.getDeviceIP(row.id)
const port = await this.$adb.tcpip(row.id, 5555)
this.formData.host = host
this.formData.port = port
console.log('host:port', `${host}:${port}`)
this.handleConnect()
}
catch (error) {
console.warn(error.message)
}
},
onPairSuccess() {
this.handleConnect()
},
handleScreenUp(row) {
this.$adb.shell(row.id, 'input keyevent KEYCODE_POWER')
this.$adb.deviceShell(row.id, 'input keyevent KEYCODE_POWER')
},
handleReset() {
this.$electron.ipcRenderer.send('restart-app')
},
async handleConnect({ pairCode = '' } = {}) {
async handleConnect() {
if (!this.formData.host) {
this.$message.warning('无线调试地址不能为空')
return false
}
this.connectLoading = true
try {
await this.$adb.connect(this.formData.host, this.formData.port || 5555, pairCode)
await this.$adb.connect(this.formData.host, this.formData.port || 5555)
this.$message.success('连接设备成功')
storage.set('adbCache', this.formData)
}
catch (error) {
if (error.message) {
this.$message.warning(error.message)
}
if (error.message.includes('10060')) {
this.handlePair()
}
this.handleError(error.message)
}
this.connectLoading = false
},
async handlePair() {
async handleError(message) {
try {
const { value } = await this.$prompt('', '提示', {
confirmButtonText: '确定',
await this.$confirm(
`
<div class="pb-4 text-sm text-red-500">错误详情${message}</div>
<div>可能有以下原因</div>
<div>1. IP地址或端口号错误</div>
<div>2. 设备未与当前电脑配对成功</div>
<div>3. 电脑网络和提供的设备网络IP不在同一个局域网中</div>
<div>4. 其他未知错误</div>
`,
'连接设备失败',
{
dangerouslyUseHTMLString: true,
confirmButtonText: '配对',
cancelButtonText: '取消',
inputType: 'number',
inputPlaceholder: '请输入配对码',
closeOnClickModal: false,
})
await this.$adb.rawShell(
`pair ${this.formData.host}:${this.formData.port || 5555} ${this.value}`,
type: 'warning',
},
)
this.handleConnect({ pairCode: value })
this.$refs.pairDialog.show({ params: { ...this.formData } })
}
catch (error) {
console.warn(error.message)
@ -177,7 +210,9 @@ export default {
async handleMirror(row) {
row.$loading = true
try {
await this.$scrcpy.shell(`--serial=${row.id} ${this.addScrcpyConfigs()}`)
await this.$scrcpy.shell(
`--serial=${row.id} --window-title=${row.name}-${row.id} ${this.addScrcpyConfigs()}`,
)
}
catch (error) {
this.$message.warning(error.message)

View File

@ -10,7 +10,7 @@ export function sleep(time = 1000) {
export function isIPWithPort(ip) {
const regex
= /^((25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d):([1-9]|[1-9]\d{1,3}|[1-6][0-5][0-5][0-3][0-5])$/
= /^((25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d):(1\d{0,4}|[1-9]\d{0,3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$/
return regex.test(ip)
}