当前位置: 首页 > news >正文

如何用电脑批量操作多部手机

如果你有很多手机,然后需要在这些手机上同时执行相同的操作,这个时候如果能有一种办法批量操作,将会大大提高效率,节省很多时间。本文将介绍基于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 = falsethis.$message.error(err)})},operationChange(operation, index) {this.commandInfo.commands[index].operation = operation},editDevice(data){this.deviceInfo = datathis.updateDeviceVisible = true;},updateDevice() {updateDevice(this.deviceInfo).then(res => {if (res.code === 0) {this.getDeviceList()} else {this.$message.error('查询失败!')}this.loading = falsethis.updateDeviceVisible = false;}).catch(err => {this.loading = falsethis.$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 = falsethis.$message.error(err)})},addCommand() {addCommand(this.commandInfo).then(res => {if (res.code === 0) {this.getCommandList()} else {this.$message.error('命令添加失败!')}this.loading = falsethis.addCommandVisible = false;}).catch(err => {this.loading = falsethis.$message.error(err)})},updateCommand(data){this.addCommandVisible = true;this.commandInfo.name = data.namethis.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 = falsethis.$message.error(err)})},executeCommand(name){if (this.executeParam.devices.length === 0){this.$message.error('请先在左侧选择设备!')return}this.executeParam.name = nameexecuteCommand(this.executeParam).then(res => {if (res.code === 0) {this.$message.success('执行完成!')} else {this.$message.error('执行失败!')}this.loading = false}).catch(err => {this.loading = falsethis.$message.error(err)})},// 添加indextableRowClassName({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>

实际的效果可以看下视频演示

如何用电脑批量操作多部手机

相关文章:

  • 二.常见算法--贪心算法
  • 基金基础知识-基金的生命周期
  • 蒙特卡洛+概率潮流!基于蒙特卡洛和新能源出力模拟的概率潮流分布程序代码!
  • AI赋能 企业智能化应用实践
  • Django数据库查询操作
  • C# 观察者模式实现
  • 【Linux】深入理解 Linux 的 chmod 指令
  • 音视频-常用的分析工具介绍-连续补充
  • 基于Django的美团药品数据分析与可视化系统,有多用户功能,可增删改查数据
  • 产品经理交接规范及流程
  • vue3的api风格
  • 【学习笔记】后端(Ⅰ)—— NodeJS(Ⅰ)
  • 鸿蒙HarmonyOS开发:tabs结合tabContent实现底部tabBar导航栏页面布局
  • 再谈Google I/O 2024:开发者必看亮点
  • Redis-
  • 2017届校招提前批面试回顾
  • CentOS从零开始部署Nodejs项目
  • Facebook AccountKit 接入的坑点
  • HTML中设置input等文本框为不可操作
  • Javascript 原型链
  • java第三方包学习之lombok
  • Java基本数据类型之Number
  • Js基础知识(一) - 变量
  • OpenStack安装流程(juno版)- 添加网络服务(neutron)- controller节点
  • PhantomJS 安装
  • Redis 懒删除(lazy free)简史
  • Vue 2.3、2.4 知识点小结
  • Zepto.js源码学习之二
  • 包装类对象
  • 闭包--闭包作用之保存(一)
  • 面试题:给你个id,去拿到name,多叉树遍历
  • 目录与文件属性:编写ls
  • 浅谈Kotlin实战篇之自定义View图片圆角简单应用(一)
  • 适配mpvue平台的的微信小程序日历组件mpvue-calendar
  • MiKTeX could not find the script engine ‘perl.exe‘ which is required to execute ‘latexmk‘.
  • Spring第一个helloWorld
  • TPG领衔财团投资轻奢珠宝品牌APM Monaco
  • 大数据全解:定义、价值及挑战
  • 昨天1024程序员节,我故意写了个死循环~
  • ###51单片机学习(1)-----单片机烧录软件的使用,以及如何建立一个工程项目
  • ###STL(标准模板库)
  • #{}和${}的区别?
  • #android不同版本废弃api,新api。
  • (c语言版)滑动窗口 给定一个字符串,只包含字母和数字,按要求找出字符串中的最长(连续)子串的长度
  • (四) Graphivz 颜色选择
  • (原創) 物件導向與老子思想 (OO)
  • .helper勒索病毒的最新威胁:如何恢复您的数据?
  • .NET 4.0中的泛型协变和反变
  • .NET C# 使用 SetWindowsHookEx 监听鼠标或键盘消息以及此方法的坑
  • .net core 客户端缓存、服务器端响应缓存、服务器内存缓存
  • .NET 跨平台图形库 SkiaSharp 基础应用
  • .pub是什么文件_Rust 模块和文件 - 「译」
  • [AutoSar]BSW_Memory_Stack_004 创建一个简单NV block并调试
  • [C#] 基于 yield 语句的迭代器逻辑懒执行
  • [C++]:for循环for(int num : nums)