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

如果你有很多手机,然后需要在这些手机上同时执行相同的操作,这个时候如果能有一种办法批量操作,将会大大提高效率,节省很多时间。本文将介绍基于uiautomator2实现的群控手机方案。

uiautomator2 是 一种 Android 自动化测试框架,提供了点击、长按、输入文本、滑动、拖拽、截屏等方法,能够模拟用户的各种动作。

本方案采用python的web端框架django+vue前端框架实现,支持在页面选择手机,执行配置的命令,多部手机会同时执行操作(页面做的比较简陋,见谅)。

大致的流程也比较简单,基于在页面配置的命令,调用uiautomator2的相关api实现,有兴趣的朋友也可以了解下uiautomator2相关的接口,动手来实现一遍

这里贴上前端的实现代码

javascript 复制代码
<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>

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

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

相关推荐
爱吃沙鱼4 小时前
Charles安装证书过程(手机)
智能手机
普密斯科技5 小时前
手机外观边框缺陷视觉检测智慧方案
人工智能·计算机视觉·智能手机·自动化·视觉检测·集成测试
暗碳8 小时前
adb无线连接手机后scrcpy连接报错ERROR: Could not find any ADB device
adb·智能手机
云云32118 小时前
怎么通过亚矩阵云手机实现营销?
大数据·服务器·安全·智能手机·矩阵
云云32120 小时前
云手机方案全解析
大数据·服务器·安全·智能手机·矩阵
云云32121 小时前
云手机能用来干什么?云手机在跨境电商领域的用途
服务器·线性代数·安全·智能手机·矩阵
云云32121 小时前
云手机方案总结
服务器·线性代数·安全·智能手机·矩阵
咸芝麻鱼1 天前
Android Studio | 连接手机设备后,启动App时出现:Waiting For DebuggerApplication (App名)...
android·adb·智能手机·android studio
AORO_BEIDOU2 天前
单北斗+鸿蒙系统+国产芯片,遨游防爆手机自主可控“三保险”
华为·智能手机·harmonyos
云云3212 天前
搭建云手机平台的技术要求?
服务器·线性代数·安全·智能手机·矩阵