使用 Golang 实现 appium/appium-uiautomator2-server 的客户端库
- electricbubble/guia2-ext-opencv 直接通过指定图片进行操作
如果使用
IOS
设备, 可查看 electricbubble/gwda
go get github.com/electricbubble/guia2
首次使用需要在
Android
设备中安装两个apk
appium-uiautomator2-server-debug-androidTest.apk
appium-uiautomator2-server-vXX.XX.XX.apk
apk
可以选择通过 appium/appium-uiautomator2-server 进行构建
也可以直接从这里下载 electricbubble/appium-uiautomator2-server-apk再通过
adb
启动appium-uiautomator2-server
adb shell am instrument -w io.appium.uiautomator2.server.test/androidx.test.runner.AndroidJUnitRunner # ⬇️ 后台运行 adb shell "nohup am instrument -w io.appium.uiautomator2.server.test/androidx.test.runner.AndroidJUnitRunner >/sdcard/uia2server.log 2>&1 &" # or adb -s $serial shell "nohup am instrument -w io.appium.uiautomator2.server.test/androidx.test.runner.AndroidJUnitRunner >/sdcard/uia2server.log 2>&1 &"
该函数使用期间, Android
设备必须一直保持 USB
的连接 (模拟器
也使用该函数)
- 先通过
USB
连接Android
设备 - 让设备在 5555 端口监听 TCP/IP 连接
adb tcpip 5555 # or adb -s $serial tcpip 5555
- 查询
Android
设备的IP
(这一步骤开始可选择断开USB
连接) - 通过
IP
连接Android
设备adb connect $deviceIP
- 确认连接状态
看到以下格式的设备, 说明连接成功
adb devices
$deviceIP:5555 device
package main
import (
"fmt"
"github.com/electricbubble/guia2"
"io/ioutil"
"log"
"os"
)
func main() {
driver, err := guia2.NewUSBDriver()
// driver, err := guia2.NewWiFiDriver("192.168.1.28")
checkErr(err)
defer func() { _ = driver.Dispose() }()
// err = driver.AppLaunch("tv.danmaku.bili")
err = driver.AppLaunch("tv.danmaku.bili", guia2.BySelector{ResourceIdID: "tv.danmaku.bili:id/action_bar_root"})
checkErr(err, "launch the app until the element appears")
// fmt.Println(driver.Source())
// return
deviceSize, err := driver.DeviceSize()
checkErr(err)
var startX, startY, endX, endY int
startX = deviceSize.Width / 2
startY = deviceSize.Height / 2
endX = startX
endY = startY / 2
err = driver.Swipe(startX, startY, endX, endY)
checkErr(err)
var startPoint, endPoint guia2.PointF
startPoint = guia2.PointF{X: float64(startX), Y: float64(startY)}
endPoint = guia2.PointF{X: startPoint.X, Y: startPoint.Y * 1.6}
err = driver.SwipePointF(startPoint, endPoint)
checkErr(err)
element, err := driver.FindElement(guia2.BySelector{ResourceIdID: "tv.danmaku.bili:id/expand_search"})
checkErr(err)
err = element.Click()
checkErr(err)
bySelector := guia2.BySelector{UiAutomator: guia2.NewUiSelectorHelper().Focused(true).String()}
element, err = waitForElement(driver, bySelector)
checkErr(err)
err = element.SendKeys("雾山五行")
checkErr(err)
err = driver.PressKeyCode(guia2.KCEnter, guia2.KMEmpty)
checkErr(err)
bySelector = guia2.BySelector{UiAutomator: guia2.NewUiSelectorHelper().TextStartsWith("番剧").String()}
element, err = waitForElement(driver, bySelector)
checkErr(err)
checkErr(element.Click())
bySelector = guia2.BySelector{UiAutomator: guia2.NewUiSelectorHelper().Text("立即观看").String()}
element, err = waitForElement(driver, bySelector)
checkErr(err)
checkErr(element.Click())
bySelector = guia2.BySelector{ResourceIdID: "tv.danmaku.bili:id/videoview_container_space"}
element, err = waitForElement(driver, bySelector)
checkErr(err)
// time.Sleep(time.Second * 5)
screenshot, err := element.Screenshot()
checkErr(err)
userHomeDir, _ := os.UserHomeDir()
checkErr(ioutil.WriteFile(userHomeDir+"/Desktop/element.png", screenshot.Bytes(), 0600))
err = driver.PressKeyCode(guia2.KCMediaPause, guia2.KMEmpty)
checkErr(err)
err = driver.PressBack()
checkErr(err)
}
func waitForElement(driver *guia2.Driver, bySelector guia2.BySelector) (element *guia2.Element, err error) {
var ce error
exists := func(d *guia2.Driver) (bool, error) {
element, ce = d.FindElement(bySelector)
if ce == nil {
return true, nil
}
// 如果直接返回 error 将直接终止 `driver.Wait`
return false, nil
}
if err = driver.Wait(exists); err != nil {
return nil, fmt.Errorf("%s: %w", err.Error(), ce)
}
return
}
func checkErr(err error, msg ...string) {
if err == nil {
return
}
var output string
if len(msg) != 0 {
output = msg[0] + " "
}
output += err.Error()
log.Fatalln(output)
}
感谢小伙伴提供的
红米 Note 5A
Thank you JetBrains for providing free open source licenses