介绍脱离PC机执行uiautomator2脚本
itomcoil 2025-06-12 13:17 13 浏览
前面介绍过了python uiautomator2的大概情况,今天主要介绍一下怎么在脱离PC机的情况下执行uiautomator2的脚本。
现在说python uiautomator2的脚本怎么脱机执行。
要在Android上配置python运行环境,有以下几个可以选择:
1. Qpython
2. pydroid3
3. Termux
根据其他网友的踩坑经验,推荐使用Termux来配置环境,步骤如下:
1. 下载Termux,通过adb安装到手机上;
2. 启动Termux,在Termux里执行更新资源的命令:
pkg update
pkg updrade
3. 安装python:
pkg install python(安装完成后可以执行python,检查是否成功)
4. 安装运行UIAutomator2需要的库:
apt install libxml libxslt
apt install libjpeg-turbo
5. 安装UIAutomator2库:
pip install –upgrade –pre uiautomator2
虽然上面已经配置了很多东西,但是实际情况是即使已经完成了上面的配置,还不能马上执行脚本。
6. 需要在PC上初始化手机上的atx-agent,就是在连接了手机时,执行命令:
python –m uiautomator2 init
7. 由于步骤6默认安装的atx-agent位置是/data/local/tmp/atx-agent,而Termux访问不了这个文件,两种解决方案:
7.1 每次启动手机时都在PC端启动它,命令:
adb shell /data/local/tmp/atx-agent server –d #启动并后台运行
7.2 把atx-agent移动到Termux能访问的位置,比如$HOME下面,赋予权限755
上面两种方案的区别是通过adb启动,atx-agent获得的是root权限,可以唤起app而无需鉴权,如果在Termux启动,相当于在一个子系统启动,权限等同于Termux,不能操作其他app。
8. 完成以上的准备,就可以在Android执行python脚本了,假设脚本名称是test_script.py,且已经存储到了Android系统中,可以通过执行命令启动:
python test_script.py
最后提醒一点,在pc上执行和在Android上执行,ut.connect()的参数不一样,在Android上需要这样写:driver = ut.connect(“127.0.0.1:7912”)
看到这里是不是不想玩python uiautomator2脱机执行了?
明明我只是想刷一下小游戏的分数,或者想在年会上抢个小奖品,至于搞得这么麻烦吗?当然不至于,因为还有另一个方式,直接在Android项目中写uiautomator2的脚本。
下面就来介绍写在Android项目中的uiautomator2脚本脱机执行方式,当然这种实现方式也有个前提条件,给这个Android工程root权限或者一些特定的权限,最好是手机root。
来说一下实现思路:
第一步:新建一个Android工程
第二步:在布局文件上加一个Button控件,并注册监听事件
第三步:实现第二步中的监听事件具体逻辑,逻辑包括生成执行脚本的命令,执行命令
第四步:新建一个module,在里面写具体的执行脚本
下面分享一下代码,我这便是以kotlin展示。
这个是Android工程的activity文件,主要是实现android页面上那个执行按钮的逻辑:
package com.example.mytest
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Button
import android.widget.Toast
import com.example.mytest.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private val TAG = "MainActivity"
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.btnRun.setOnClickListener{runMyUiautomator()}
}
private fun runMyUiautomator() {
Log.i(TAG, "runMyUiautomator: ")
UiautomatorThread().start()
Toast.makeText(this, "start run", Toast.LENGTH_SHORT).show()
}
class UiautomatorThread : Thread() {
override fun run() {
super.run()
val commond = generateCommand("com.example.mytestcase", "ExampleInstrumentedTest", "test1")
val cmdUtils = CMDUtils()
val res: CMDUtils.CMDResult = cmdUtils.execCommand(commond, false)
Log.i("UiautomatorThread", "run: " + res?.error + "--------" + res?.success)
}
fun generateCommand(pkgName: String, clsName: String, mtdNam: String): String {
val commond = "am instrument -w -m -e debug false -e class \'$pkgName.$clsName#$mtdNam\' $pkgName.test/androidx.test.runner.AndroidJUnitRunner"
Log.i("generateCommand: ", commond)
return commond
}
}
}
这个是执行脚本的工具类:
package com.example.mytest
import android.util.Log
import java.io.*
class CMDUtils {
private val TAG = "CMDUtil"
class CMDResult(var resultCode: Int = -1, var error: String = "error", var success: String = "success")
val tag = "CommandExecution"
val COMMAND_SU = "su"
val COMMAND_SH = "sh"
val COMMAND_EXIT = "exit\n"
val COMMAND_LINE_END = "\n"
fun execCommand(command: String, isRoot: Boolean): CMDResult {
val commandResult = CMDResult()
if (command.isEmpty()) {
return commandResult
}
var process: Process? = null
var os: DataOutputStream? = null
var successResult: BufferedReader? = null
var errorResult: BufferedReader? = null
var successMsg: StringBuilder? = null
var errorMsg: StringBuilder? = null
try {
process = Runtime.getRuntime().exec(if (isRoot) COMMAND_SU else COMMAND_SH)
os = DataOutputStream(process.outputStream)
os.write(command.toByteArray())
os.writeBytes(COMMAND_LINE_END)
os.flush()
os.writeBytes(COMMAND_EXIT)
os.flush()
commandResult.resultCode = process.waitFor()
// 获取错误信息
successMsg = StringBuilder()
errorMsg = StringBuilder()
successResult = BufferedReader(InputStreamReader(process.inputStream))
errorResult = BufferedReader(InputStreamReader(process.errorStream))
var s: String? = successResult.readLine()
while (s != null) {
successMsg.append(s)
s = successResult.readLine()
}
s = errorResult.readLine()
while (s != null) {
errorMsg.append(s)
s = errorResult.readLine()
}
commandResult.success = successMsg.toString()
commandResult.error = errorMsg.toString()
Log.i(tag, commandResult.resultCode.toString() + " | " + commandResult.success + " | " + commandResult.error)
} catch (e: IOException) {
val errMsg = e.message
when {
errMsg != null -> Log.e(tag, errMsg)
else -> e.printStackTrace()
}
} catch (e: Exception) {
val errMsg = e.message
when {
errMsg != null -> Log.e(tag, errMsg)
else -> e.printStackTrace()
}
} finally {
try {
os?.close()
successResult?.close()
errorResult?.close()
} catch (e: IOException) {
val errMsg = e.message
when {
errMsg != null -> Log.e(tag, errMsg)
else -> e.printStackTrace()
}
}
process?.destroy()
}
return commandResult
}
}
这个是真正的uiautomator2脚本,当然这里我是随便写的,脚本的意思是启动微信,点击一个空间,然后进行滑动:
package com.example.mytestcase
import android.content.Context
import android.content.Intent
import androidx.test.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiSelector
import org.junit.Test
import org.junit.runner.RunWith
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleInstrumentedTest {
private lateinit var mDevice: UiDevice
@Test
fun test1() {
// Context of the app under test.
mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
val packageName = "com.tencent.mm"
val activityName = "com.tencent.mm.ui.LauncherUI"
val context: Context = InstrumentationRegistry.getContext()
val intent: Intent? = context.packageManager.getLaunchIntentForPackage(packageName)
intent?.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
context.startActivity(intent)
mDevice.findObject(UiSelector().resourceId("com.tencent.mm:id/a4k")).click()
mDevice.swipe(50, 500, 50, 50, 1)
}
}
相关推荐
- selenium(WEB自动化工具)
-
定义解释Selenium是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7,8,9,10,11),MozillaF...
- 开发利器丨如何使用ELK设计微服务中的日志收集方案?
-
【摘要】微服务各个组件的相关实践会涉及到工具,本文将会介绍微服务日常开发的一些利器,这些工具帮助我们构建更加健壮的微服务系统,并帮助排查解决微服务系统中的问题与性能瓶颈等。我们将重点介绍微服务架构中...
- 高并发系统设计:应对每秒数万QPS的架构策略
-
当面试官问及"如何应对每秒几万QPS(QueriesPerSecond)"时,大概率是想知道你对高并发系统设计的理解有多少。本文将深入探讨从基础设施到应用层面的解决方案。01、理解...
- 2025 年每个 JavaScript 开发者都应该了解的功能
-
大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发。1.Iteratorhelpers开发者...
- JavaScript Array 对象
-
Array对象Array对象用于在变量中存储多个值:varcars=["Saab","Volvo","BMW"];第一个数组元素的索引值为0,第二个索引值为1,以此类推。更多有...
- Gemini 2.5编程全球霸榜,谷歌重回AI王座,神秘模型曝光,奥特曼迎战
-
刚刚,Gemini2.5Pro编程登顶,6美元性价比碾压Claude3.7Sonnet。不仅如此,谷歌还暗藏着更强的编程模型Dragontail,这次是要彻底翻盘了。谷歌,彻底打了一场漂亮的翻...
- 动力节点最新JavaScript教程(高级篇),深入学习JavaScript
-
JavaScript是一种运行在浏览器中的解释型编程语言,它的解释器被称为JavaScript引擎,是浏览器的一部分,JavaScript广泛用于浏览器客户端编程,通常JavaScript脚本是通过嵌...
- 一文看懂Kiro,其 Spec工作流秒杀Cursor,可移植至Claude Code
-
当Cursor的“即兴编程”开始拖累项目质量,AWS新晋IDEKiro以Spec工作流打出“先规范后编码”的系统工程思维:需求-设计-任务三件套一次生成,文档与代码同步落地,复杂项目不...
- 「晚安·好梦」努力只能及格,拼命才能优秀
-
欢迎光临,浏览之前点击上面的音乐放松一下心情吧!喜欢的话给小编一个关注呀!Effortscanonlypass,anddesperatelycanbeexcellent.努力只能及格...
- JavaScript 中 some 与 every 方法的区别是什么?
-
大家好,很高兴又见面了,我是姜茶的编程笔记,我们一起学习前端相关领域技术,共同进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力在JavaScript中,Array.protot...
- 10个高效的Python爬虫框架,你用过几个?
-
小型爬虫需求,requests库+bs4库就能解决;大型爬虫数据,尤其涉及异步抓取、内容管理及后续扩展等功能时,就需要用到爬虫框架了。下面介绍了10个爬虫框架,大家可以学习使用!1.Scrapysc...
- 12个高效的Python爬虫框架,你用过几个?
-
实现爬虫技术的编程环境有很多种,Java、Python、C++等都可以用来爬虫。但很多人选择Python来写爬虫,为什么呢?因为Python确实很适合做爬虫,丰富的第三方库十分强大,简单几行代码便可实...
- pip3 install pyspider报错问题解决
-
运行如下命令报错:>>>pip3installpyspider观察上面的报错问题,需要安装pycurl。是到这个网址:http://www.lfd.uci.edu/~gohlke...
- PySpider框架的使用
-
PysiderPysider是一个国人用Python编写的、带有强大的WebUI的网络爬虫系统,它支持多种数据库、任务监控、项目管理、结果查看、URL去重等强大的功能。安装pip3inst...
- 「机器学习」神经网络的激活函数、并通过python实现激活函数
-
神经网络的激活函数、并通过python实现whatis激活函数感知机的网络结构如下:左图中,偏置b没有被画出来,如果要表示出b,可以像右图那样做。用数学式来表示感知机:上面这个数学式子可以被改写:...
- 一周热门
- 最近发表
- 标签列表
-
- ps图案在哪里 (33)
- super().__init__ (33)
- python 获取日期 (34)
- 0xa (36)
- super().__init__()详解 (33)
- python安装包在哪里找 (33)
- linux查看python版本信息 (35)
- python怎么改成中文 (35)
- php文件怎么在浏览器运行 (33)
- eval在python中的意思 (33)
- python安装opencv库 (35)
- python div (34)
- sticky css (33)
- python中random.randint()函数 (34)
- python去掉字符串中的指定字符 (33)
- python入门经典100题 (34)
- anaconda安装路径 (34)
- yield和return的区别 (33)
- 1到10的阶乘之和是多少 (35)
- python安装sklearn库 (33)
- dom和bom区别 (33)
- js 替换指定位置的字符 (33)
- python判断元素是否存在 (33)
- sorted key (33)
- shutil.copy() (33)