如果你有很多手机,然后需要在这些手机上同时执行相同的操作,这个时候如果能有一种办法批量操作,将会大大提高效率,节省很多时间。本文将介绍基于uiautomator2实现的群控手机方案。
uiautomator2 是 一种 Android 自动化测试框架,提供了点击、长按、输入文本、滑动、拖拽、截屏等方法,能够模拟用户的各种动作。
本方案采用python的web端框架django+vue前端框架实现,支持在页面选择手机,执行配置的命令,多部手机会同时执行操作(页面做的比较简陋,见谅)。
大致的流程也比较简单,基于在页面配置的命令,调用uiautomator2的相关api实现,有兴趣的朋友也可以了解下uiautomator2相关的接口,动手来实现一遍
这里贴上前端的实现代码
<template>
<div class="common-layout">
<el-container>
<el-header>
<div style="font-weight: bolder;text-align: center;font-size: 30px">手机群控</div>
</el-header>
<el-main>
<el-row>
<el-col :span="12">
<el-card class="box-card">
<div style="display: flex;justify-content: space-between;align-items:center">
<div style="font-weight: bolder;">设备列表</div>
<el-button link type="text" @click="getDeviceList">刷新</el-button>
</div>
<el-table :data="deviceListData" style="width: 100%;" height="75vh" @selection-change="selectDevices" ref="deviceTable">
<el-table-column type="selection" width="55"/>
<el-table-column prop="sn" label="设备编号"/>
<el-table-column prop="name" label="设备名称"/>
<el-table-column prop="status" label="状态"/>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button link type="text" size="small" @click="editDevice(scope.row)"
>编辑
</el-button
>
<!--<el-button link type="primary" size="small">删除</el-button>-->
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
<el-col :span="12">
<el-card class="box-card">
<div style="display: flex;justify-content: space-between;align-items:center">
<div style="font-weight: bolder;">命令列表</div>
<el-button link type="text" @click="addCommandVisible = true">添加</el-button>
</div>
<el-table :data="commandListData" style="width: 100%" height="75vh" >
<el-table-column width="55"/>
<el-table-column prop="name" label="名称"/>
<el-table-column prop="creatTime" label="创建时间"/>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button link type="primary" size="small" @click="updateCommand(scope.row)">编辑</el-button>
<el-button link type="primary" size="small" @click="deleteCommand(scope.row.name)">删除</el-button>
<el-button link type="primary" size="small" @click="executeCommand(scope.row.name)">执行</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
</el-row>
</el-main>
</el-container>
<el-dialog :visible.sync="addCommandVisible" title="添加/编辑命令">
<el-input v-model="commandInfo.name" autocomplete="off" placeholder="请输入命令名称"></el-input>
<el-table :row-class-name="tableRowClassName" :data="commandInfo.commands" border style="width: 100%">
<el-table-column align="center" width="100px" type="index" label="序号"></el-table-column>
<el-table-column align="center" prop="operation" label="操作">
<template slot-scope="scope">
<el-select @change="operationChange(scope.row.operation,scope.row.index)" size="small"
v-model="scope.row.operation" placeholder="请选择操作类型">
<el-option v-for="item in operationOption" :key="item.value" :label="item.label"
:value="item.value"></el-option>
</el-select>
</template>
</el-table-column>
<el-table-column align="center" prop="param" label="参数">
<template #default="scope">
<el-input size="small" v-model="scope.row.param" placeholder="非必填,有则填写"></el-input>
</template>
</el-table-column>
<el-table-column align="center" prop="delayTime" label="延时">
<template #default="scope">
<el-input size="small" v-model="scope.row.delayTime" placeholder="填写延时时长,单位秒"></el-input>
</template>
</el-table-column>
<el-table-column align="center" prop="date" label="操作">
<template slot-scope="scope">
<el-button link type="primary" size="small" @click="addForm">添加</el-button>
<el-button link type="primary" size="small" v-if="commandInfo.commands.length>1"
@click="removeIdx(scope.row,scope.row.index)" style="color:rgb(216,30,6)">删除
</el-button>
</template>
</el-table-column>
</el-table>
<template #footer>
<span class="dialog-footer">
<el-button @click="addCommandVisible = false">取消</el-button>
<el-button type="primary" @click="addCommand">
确定
</el-button>
</span>
</template>
</el-dialog>
<el-dialog title="编辑设备" :visible.sync="updateDeviceVisible">
<el-form :model="deviceInfo">
<el-form-item label="设备编号" :label-width="formLabelWidth">
<el-input v-model="deviceInfo.sn" autocomplete="off" disabled></el-input>
</el-form-item>
<el-form-item label="设备名称" :label-width="formLabelWidth">
<el-input v-model="deviceInfo.name" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="updateDeviceVisible = false">取 消</el-button>
<el-button type="primary" @click="updateDevice">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {getDeviceList, updateDevice,getCommandList,addCommand,deleteCommand,executeCommand} from '@/api/device'
export default {
name: 'device',
data() {
return {
formLabelWidth: '140px',
addCommandVisible: false,
commandInfo: {
name:"",
commands: [
{
operation: '',
param: '',
delayTime: ''
}
]
},
operationOption: [
{
value: '单击',
label: '单击'
},
{
value: '返回',
label: '返回'
},
{
value: '右滑',
label: '右滑'
},
{
value: '截屏',
label: '截屏'
},
{
value: '点击Home键',
label: '点击Home键'
},
{
value: '卸载',
label: '卸载'
},
{
value: '输入文字',
label: '输入文字'
},
{
value: '左滑',
label: '左滑'
}
],
deviceListData: [],
commandListData: [],
deviceInfo: {
sn: "",
name: ""
},
executeParam:{
devices:[],
name:""
},
updateDeviceVisible:false,
}
},
mounted() {
this.getDeviceList()
this.getCommandList()
},
methods: {
selectDevices(val) {
let selection = this.$refs.deviceTable.selection;
this.executeParam.devices = []
for (let item of selection){
this.executeParam.devices.push(item.sn)
}
console.log(JSON.stringify(this.executeParam.devices))
},
getDeviceList() {
getDeviceList().then(res => {
if (res.code === 0) {
this.deviceListData = res.data;
} else {
this.$message.error('查询失败!')
}
this.loading = false
}).catch(err => {
this.loading = false
this.$message.error(err)
})
},
operationChange(operation, index) {
this.commandInfo.commands[index].operation = operation
},
editDevice(data){
this.deviceInfo = data
this.updateDeviceVisible = true;
},
updateDevice() {
updateDevice(this.deviceInfo).then(res => {
if (res.code === 0) {
this.getDeviceList()
} else {
this.$message.error('查询失败!')
}
this.loading = false
this.updateDeviceVisible = false;
}).catch(err => {
this.loading = false
this.$message.error(err)
})
},
getCommandList() {
getCommandList().then(res => {
if (res.code === 0) {
this.commandListData = res.data;
} else {
this.$message.error('查询失败!')
}
this.loading = false
}).catch(err => {
this.loading = false
this.$message.error(err)
})
},
addCommand() {
addCommand(this.commandInfo).then(res => {
if (res.code === 0) {
this.getCommandList()
} else {
this.$message.error('命令添加失败!')
}
this.loading = false
this.addCommandVisible = false;
}).catch(err => {
this.loading = false
this.$message.error(err)
})
},
updateCommand(data){
this.addCommandVisible = true;
this.commandInfo.name = data.name
this.commandInfo.commands = data.commands
},
deleteCommand(name){
deleteCommand(name).then(res => {
if (res.code === 0) {
this.getCommandList()
} else {
this.$message.error('查询失败!')
}
this.loading = false
}).catch(err => {
this.loading = false
this.$message.error(err)
})
},
executeCommand(name){
if (this.executeParam.devices.length === 0){
this.$message.error('请先在左侧选择设备!')
return
}
this.executeParam.name = name
executeCommand(this.executeParam).then(res => {
if (res.code === 0) {
this.$message.success('执行完成!')
} else {
this.$message.error('执行失败!')
}
this.loading = false
}).catch(err => {
this.loading = false
this.$message.error(err)
})
},
// 添加index
tableRowClassName({row, rowIndex}) {
row.index = rowIndex
},
// 添加操作
addForm() {
if (this.isDataComplete()) {
this.commandInfo.commands.push({
operation: '',
param: '',
delayTime: ''
})
} else {
this.$message({
message: '请完善信息后再添加',
type: 'warning'
})
}
},
isDataComplete() {
return this.commandInfo.commands.every(
(item) => item.operation
)
},
// 删除操作
removeIdx(item, index) {
this.commandInfo.commands.splice(index, 1)
this.$message({
message: '删除成功',
type: 'success'
})
}
}
}
</script>
<style scoped>
</style>
实际的效果可以看下视频演示
如何用电脑批量操作多部手机
感兴趣的同学可以加v交流,vx:duenbs