Appium 是一个开源、跨平台的测试自动化工具,适用于原生、混合以及移动 Web 和桌面应用程序。我们支持模拟器(iOS)、模拟器(Android)和真实设备(iOS、Android、Windows、Mac)
总的来说,其实三端都支持的,啥都可以干,Windows、Mac、Android、Ios,Web 都支持。
主要是我的手机是安卓 黑鲨手机,所以,就拿安卓手机来进行测试。.
注
另外,我这边尽量以.Net C#代码为主,也会提示如何用 Node.js 或者 java 敲代码,巴拉巴拉。
Appium 之安卓环境
适用于 Android 的 UiAutomator2 驱动程序
需要配置
-
1. 为您的平台正确安装和配置了 Java 8
-
2. 最低要求的 Android SDK Build Tools 版本为 24
装个 Android Studio 就差不多了,再配置一下 SDK 的版本,这一块,可以网上找资料。
Appium 需要的应用软件
-
1. Appium GUI Desktop (服务端)
-
2. Appium Inspector (客户端能查看 UIA 结构 xpath)
以下是具体的地址:
https://github.com/appium/appium-desktop/releases/tag/v1.22.3-4
https://github.com/appium/appium-inspector/releases/tag/v2022.5.4
下载安装后,是这个样子的
Appium GUI Desktop

Appium Inspector

手机开发者模式打开 Debug 调试模式

打开 Debug 模式,然后,USB 线连接到电脑上,通过 adb 命令来查看设备的连接状态.
adb 的地址大概在 D:\Android\android-sdk\platform-tools 你自己的 android-sdk 下面。
当然,如果你电脑上 adb.exe 多的话,可以任选一个,都是可以的。
电脑 adb.exe 连接手机
.\adb.exe devices
通过此命令来查看 当前连接的设备信息(可以是虚拟机,不过我用的是真机)
大致如下:

我的安卓设备名字就是 (2ff57aa0) 也可能是一个 IP 地址。
开启 Appium GUI Desktop 服务

这个服务是需要配置 Android 相关信息的。

我这边配置如上。
这时候,就可以直接开启服务了。

就像下边这样子

其中这个里面就是服务端的控制台,里面会经过内置的 http 协议,很多问题也可以从这个里面查看。
大致实现应用逻辑
大致的业务逻辑是这样的,我会打开安卓里的快手短视频 APP,然后,划拉两下,然后,录个视频,顺便,截个图,最后,退出应用。
要做的事情就是
-
1. 如何打开快手的 APP
-
2. 如何划拉视频
-
3. 如何录制视频
-
4. 如何截图
-
5. 如何退出应用
会围绕着,这几个点进行展开操作。
如何打开快手 APP
首先我们得获取手机快手 APP 的 PackageName 和启动的主 ActivityName,包名可以通过应用的详细信息里找到。但是,启动的 ActivityName 当下现在只能先通过 ADB 的命令获取。
我们先打开快手 APP,然后,执行以下 ADB 命令(要先保证 设备是上线的)
.\adb.exe -s 2ff57aa0 shell dumpsys window w |findstr \/ |findstr name=
其中 2ff57aa0 是我手机的设备 id。找不到的可以执行上边【电脑 adb.exe 连接手机】这一步进行获取
执行上面后,结果如下:

这里就看到了快手 APP 的 PackageName 和 主 ActivityName 。
com.smile.gifmaker/com.yxcorp.gifshow.HomeActivity
那么 ,配置里的
-
1. appPackage : com.smile.gifmaker
-
2. appActivity : com.yxcorp.gifshow.HomeActivity
Appium Inspector 找相应的元素
打开应用
打开应用,然后,填写如下信息

最少需要填写这一个条件,当然还有其他条件,可以参考官方
{
"platformName": "Android"
}
界面大致介绍

-
1. 手机界面临时截图,显示速度有点慢大致 2 秒才显示出来。
-
2. 选择视频中的元素,7 和 9 就会出现相应的结构和 Xpath
-
3. 是滑动操作(点一下是起始点,点第二下是目标点,松手后,有动作)
-
4. 点击的坐标点
-
5. 刷新当前 1 的截图
-
6. 录制动作(很实用,支持 js,java,python,就是不支持 C# ,不过我就是用 C#写的)
-
7. 元素结构列表类似于谷歌游览器的 F12
-
8. 具体的元素实际信息有 Xpath 信息
-
9. 对当前元素进行点击
我们录制一个 往下滑的视频
可以看到,我们已经录制了相关的脚本
js%20的大致如下:
driver.touchAction([
{action: 'press', x: 434, y: 1400},
{action: 'moveTo', x: 561, y: 447},
'release'
]);
driver.touchAction([
{action: 'press', x: 525, y: 1547},
{action: 'moveTo', x: 571, y: 613},
'release'
]);
java%20的大致如下:
(new TouchAction(driver))
.press(PointOption.point(434, 1400}))
.moveTo(PointOption.point(561, 447}))
.release()
.perform();
(new TouchAction(driver))
.press(PointOption.point(525, 1547}))
.moveTo(PointOption.point(571, 613}))
.release()
.perform();
python%20的大致如下:
actions = ActionChains(driver)
actions.w3c_actions = ActionBuilder(driver, mouse=PointerInput(interaction.POINTER_TOUCH, "touch"))
actions.w3c_actions.pointer_action.move_to_location(434, 1400)
actions.w3c_actions.pointer_action.pointer_down()
actions.w3c_actions.pointer_action.move_to_location(561, 447)
actions.w3c_actions.pointer_action.release()
actions.perform()
actions = ActionChains(driver)
actions.w3c_actions = ActionBuilder(driver, mouse=PointerInput(interaction.POINTER_TOUCH, "touch"))
actions.w3c_actions.pointer_action.move_to_location(525, 1547)
actions.w3c_actions.pointer_action.pointer_down()
actions.w3c_actions.pointer_action.move_to_location(571, 613)
actions.w3c_actions.pointer_action.release()
actions.perform()
基于Appium.Net的开发
如果是node.js%20那就是%20webdriverio%20的开发,基于.Net的开发那就是%20Appium.Net
先安装Nuget包
Install-Package Appium.WebDriver -Version 4.3.1
整体业务代码如下:
static void Main(string[] args)
{
var url = new Uri("http://127.0.0.1:4723/wd/hub");
var capabilities = new AppiumOptions();
capabilities.AddAdditionalCapability(MobileCapabilityType.AutomationName, AutomationName.AndroidUIAutomator2);
capabilities.AddAdditionalCapability(MobileCapabilityType.PlatformName, "Android");
capabilities.AddAdditionalCapability(MobileCapabilityType.PlatformVersion, "10");
capabilities.AddAdditionalCapability(MobileCapabilityType.DeviceName, "2ff57aa0");
var _driver = new AndroidDriver<AppiumWebElement>(url, capabilities, TimeSpan.FromSeconds(180));
_driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
//启动快手APP
_driver.StartActivity("com.smile.gifmaker", "com.yxcorp.gifshow.HomeActivity");
//滑动两次
var touchAction = new TouchAction(_driver);
touchAction.Press(507, 1612).Wait(1000).MoveTo(576, 500).Release().Perform();
Thread.Sleep(5 * 1000);
var touchAction2 = new TouchAction(_driver);
touchAction2.Press(434, 1622).Wait(1000).MoveTo(494, 564).Release().Perform();
Thread.Sleep(5 * 1000);
//录屏,目前没声音
_driver.StartRecordingScreen(AndroidStartScreenRecordingOptions
.GetAndroidStartScreenRecordingOptions()
.WithTimeLimit(TimeSpan.FromSeconds(20)));
var result = _driver.StopRecordingScreen();
byte[] decode = Convert.FromBase64String(result);
//录屏的MP4保存到本地
var fileName = "VideoRecording_test.mp4";
File.WriteAllBytes(fileName, decode);
//截屏
var Screen = _driver.GetScreenshot();
using (MemoryStream memoryStream = new MemoryStream(Screen.AsByteArray))
{
using var img = Image.FromStream(memoryStream);
img.Save("123.jpg", ImageFormat.Jpeg);
}
//结束app
_driver.TerminateApp("com.smile.gifmaker");
_driver?.Quit();
Console.ReadLine();
}
基于 Node.js Appium 的开发
const fs = require('fs');
const wdio = require("webdriverio");
const opts = {
path: '/wd/hub',
port: 4723,
capabilities: {
platformName: "Android",
platformVersion: "10",
deviceName: "2ff57aa0",
automationName: "UiAutomator2"
}
};
async function main() {
const driver = await wdio.remote(opts);
await driver.startActivity("com.smile.gifmaker", "com.yxcorp.gifshow.HomeActivity");
await driver.pause(2000);
await driver.touchAction([
{action: 'press', x: 507, y: 1612},
{action: 'moveTo', x: 576, y: 500},
'release'
]);
await driver.pause(2000);
await driver.touchAction([
{action: 'press', x: 507, y: 1612},
{action: 'moveTo', x: 576, y: 500},
'release'
]);
await driver.startRecordingScreen();
let screen = await driver.stopRecordingScreen();
let videoBinary = Buffer.from(screen, 'base64');
await fs.writeFileSync('./video.mp4', videoBinary);
let screenshot = await driver.takeScreenshot();
let screenshotBinary = Buffer.from(screenshot, 'base64');
await fs.writeFileSync('./screenshot.jpg', screenshotBinary);
await driver.terminateApp("com.smile.gifmaker");
await driver.deleteSession();
}
main();
node.js 我试了,有一些bug,应该是库的问题,但是整体逻辑目前没啥问题,有需要的朋友可以自行解决。
效果如下:
脚本的录屏和脚本的截图
手机的操作界面
总结
RPA的东西,说容易也容易,说难也难,操作看着挺容易,内部的东西,还是挺麻烦的。
代码地址
https://github.com/kesshei/AppiumDemo.git
https://gitee.com/kesshei/AppiumDemo.git
参考文档
https://appium.io/
阅
一键三连呦!,感谢大佬的支持,您的支持就是我的动力!
Appium%20Inspector
手机开发者模式打开%20Debug%20调试模式
打开%20Debug%20模式,然后,USB%20线连接到电脑上,通过%20adb%20命令来查看设备的连接状态.
adb%20的地址大概在%20D:\Android\android-sdk\platform-tools%20你自己的%20android-sdk%20下面。
当然,如果你电脑上%20adb.exe%20多的话,可以任选一个,都是可以的。
电脑%20adb.exe%20连接手机
.\adb.exe devices
通过此命令来查看%20当前连接的设备信息(可以是虚拟机,不过我用的是真机)
大致如下:
我的安卓设备名字就是%20(2ff57aa0)%20也可能是一个%20IP%20地址。
开启%20Appium%20GUI%20Desktop%20服务
这个服务是需要配置%20Android%20相关信息的。
我这边配置如上。
这时候,就可以直接开启服务了。
就像下边这样子

其中这个里面就是服务端的控制台,里面会经过内置的 http 协议,很多问题也可以从这个里面查看。
大致实现应用逻辑
大致的业务逻辑是这样的,我会打开安卓里的快手短视频 APP,然后,划拉两下,然后,录个视频,顺便,截个图,最后,退出应用。
要做的事情就是
-
1. 如何打开快手的 APP
-
2. 如何划拉视频
-
3. 如何录制视频
-
4. 如何截图
-
5. 如何退出应用
会围绕着,这几个点进行展开操作。
如何打开快手 APP
首先我们得获取手机快手 APP 的 PackageName 和启动的主 ActivityName,包名可以通过应用的详细信息里找到。但是,启动的 ActivityName 当下现在只能先通过 ADB 的命令获取。
我们先打开快手 APP,然后,执行以下 ADB 命令(要先保证 设备是上线的)
.\adb.exe -s 2ff57aa0 shell dumpsys window w |findstr \/ |findstr name=
其中 2ff57aa0 是我手机的设备 id。找不到的可以执行上边【电脑 adb.exe 连接手机】这一步进行获取
执行上面后,结果如下:

这里就看到了快手 APP 的 PackageName 和 主 ActivityName 。
com.smile.gifmaker/com.yxcorp.gifshow.HomeActivity
那么 ,配置里的
-
1. appPackage : com.smile.gifmaker
-
2. appActivity : com.yxcorp.gifshow.HomeActivity
Appium Inspector 找相应的元素
打开应用
打开应用,然后,填写如下信息

最少需要填写这一个条件,当然还有其他条件,可以参考官方
{
"platformName": "Android"
}
界面大致介绍

-
1. 手机界面临时截图,显示速度有点慢大致 2 秒才显示出来。
-
2. 选择视频中的元素,7 和 9 就会出现相应的结构和 Xpath
-
3. 是滑动操作(点一下是起始点,点第二下是目标点,松手后,有动作)
-
4. 点击的坐标点
-
5. 刷新当前 1 的截图
-
6. 录制动作(很实用,支持 js,java,python,就是不支持 C# ,不过我就是用 C#写的)
-
7. 元素结构列表类似于谷歌游览器的 F12
-
8. 具体的元素实际信息有 Xpath 信息
-
9. 对当前元素进行点击
我们录制一个 往下滑的视频

可以看到,我们已经录制了相关的脚本

js 的大致如下:
driver.touchAction([
{action: 'press', x: 434, y: 1400},
{action: 'moveTo', x: 561, y: 447},
'release'
]);
driver.touchAction([
{action: 'press', x: 525, y: 1547},
{action: 'moveTo', x: 571, y: 613},
'release'
]);
java 的大致如下:
(new TouchAction(driver))
.press(PointOption.point(434, 1400}))
.moveTo(PointOption.point(561, 447}))
.release()
.perform();
(new TouchAction(driver))
.press(PointOption.point(525, 1547}))
.moveTo(PointOption.point(571, 613}))
.release()
.perform();
python 的大致如下:
actions = ActionChains(driver)
actions.w3c_actions = ActionBuilder(driver, mouse=PointerInput(interaction.POINTER_TOUCH, "touch"))
actions.w3c_actions.pointer_action.move_to_location(434, 1400)
actions.w3c_actions.pointer_action.pointer_down()
actions.w3c_actions.pointer_action.move_to_location(561, 447)
actions.w3c_actions.pointer_action.release()
actions.perform()
actions = ActionChains(driver)
actions.w3c_actions = ActionBuilder(driver, mouse=PointerInput(interaction.POINTER_TOUCH, "touch"))
actions.w3c_actions.pointer_action.move_to_location(525, 1547)
actions.w3c_actions.pointer_action.pointer_down()
actions.w3c_actions.pointer_action.move_to_location(571, 613)
actions.w3c_actions.pointer_action.release()
actions.perform()
基于Appium.Net的开发
如果是node.js 那就是 webdriverio 的开发,基于.Net的开发那就是 Appium.Net
先安装Nuget包
Install-Package Appium.WebDriver -Version 4.3.1
整体业务代码如下:
static void Main(string[] args)
{
var url = new Uri("http://127.0.0.1:4723/wd/hub");
var capabilities = new AppiumOptions();
capabilities.AddAdditionalCapability(MobileCapabilityType.AutomationName, AutomationName.AndroidUIAutomator2);
capabilities.AddAdditionalCapability(MobileCapabilityType.PlatformName, "Android");
capabilities.AddAdditionalCapability(MobileCapabilityType.PlatformVersion, "10");
capabilities.AddAdditionalCapability(MobileCapabilityType.DeviceName, "2ff57aa0");
var _driver = new AndroidDriver<AppiumWebElement>(url, capabilities, TimeSpan.FromSeconds(180));
_driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);
//启动快手APP
_driver.StartActivity("com.smile.gifmaker", "com.yxcorp.gifshow.HomeActivity");
//滑动两次
var touchAction = new TouchAction(_driver);
touchAction.Press(507, 1612).Wait(1000).MoveTo(576, 500).Release().Perform();
Thread.Sleep(5 * 1000);
var touchAction2 = new TouchAction(_driver);
touchAction2.Press(434, 1622).Wait(1000).MoveTo(494, 564).Release().Perform();
Thread.Sleep(5 * 1000);
//录屏,目前没声音
_driver.StartRecordingScreen(AndroidStartScreenRecordingOptions
.GetAndroidStartScreenRecordingOptions()
.WithTimeLimit(TimeSpan.FromSeconds(20)));
var result = _driver.StopRecordingScreen();
byte[] decode = Convert.FromBase64String(result);
//录屏的MP4保存到本地
var fileName = "VideoRecording_test.mp4";
File.WriteAllBytes(fileName, decode);
//截屏
var Screen = _driver.GetScreenshot();
using (MemoryStream memoryStream = new MemoryStream(Screen.AsByteArray))
{
using var img = Image.FromStream(memoryStream);
img.Save("123.jpg", ImageFormat.Jpeg);
}
//结束app
_driver.TerminateApp("com.smile.gifmaker");
_driver?.Quit();
Console.ReadLine();
}
基于 Node.js Appium 的开发
const fs = require('fs');
const wdio = require("webdriverio");
const opts = {
path: '/wd/hub',
port: 4723,
capabilities: {
platformName: "Android",
platformVersion: "10",
deviceName: "2ff57aa0",
automationName: "UiAutomator2"
}
};
async function main() {
const driver = await wdio.remote(opts);
await driver.startActivity("com.smile.gifmaker", "com.yxcorp.gifshow.HomeActivity");
await driver.pause(2000);
await driver.touchAction([
{action: 'press', x: 507, y: 1612},
{action: 'moveTo', x: 576, y: 500},
'release'
]);
await driver.pause(2000);
await driver.touchAction([
{action: 'press', x: 507, y: 1612},
{action: 'moveTo', x: 576, y: 500},
'release'
]);
await driver.startRecordingScreen();
let screen = await driver.stopRecordingScreen();
let videoBinary = Buffer.from(screen, 'base64');
await fs.writeFileSync('./video.mp4', videoBinary);
let screenshot = await driver.takeScreenshot();
let screenshotBinary = Buffer.from(screenshot, 'base64');
await fs.writeFileSync('./screenshot.jpg', screenshotBinary);
await driver.terminateApp("com.smile.gifmaker");
await driver.deleteSession();
}
main();
node.js 我试了,有一些bug,应该是库的问题,但是整体逻辑目前没啥问题,有需要的朋友可以自行解决。
效果如下:
脚本的录屏和脚本的截图

手机的操作界面
总结
RPA的东西,说容易也容易,说难也难,操作看着挺容易,内部的东西,还是挺麻烦的。
代码地址
https://github.com/kesshei/AppiumDemo.git
https://gitee.com/kesshei/AppiumDemo.git
参考文档
https://appium.io/