QQコミュニケーショングループ: 815453846 Discord:https://discord.gg/PbJhnZJKDd
このプロジェクトはしばらく (おそらく 2 年ほど) メンテナンスしていませんでしたが、最近、Android ネイティブ オートメーションを再研究する必要がありました。 もちろん、Appium も調べた結果、uiauTomator2 プロジェクトの実行速度が向上したことがわかりました。要素の検出からクリックまでがすべてミリ秒単位で行われ、コードが理解しやすくなりました。これまでにこのような素晴らしいプロジェクトを書いたことがあるとはまったく予想していませんでした。どうしてこのような優れたプロジェクトがゴミを集めることができたのでしょうか。再編成する必要があり、いくつかのジャンク コードをクリーンアップする必要がありました。したがって、プロジェクトのバージョンは 2.xx から 3.xx にアップグレードされました。
まだバージョン 2.xx を使用しているユーザーは、3.xx にアップグレードするかどうかを決定する前に、まず 2to3 を確認してください (個人的にはアップグレードすることを強くお勧めします)。
結局のところ、バージョン2から3はメジャーバージョンアップであり、多くの機能が削除されています。最初に削除するのは atx-agent で、次に atx-agent 関連の関数が多数あります。 init などの非推奨の関数。
さまざまな依存ライブラリのバージョン番号
UiAutomator は、アクセシビリティ サービスに基づいた Android 自動テスト用に Google が提供する Java ライブラリです。これは非常に強力で、サードパーティのアプリをテストし、画面上の任意のアプリの任意の制御属性を取得し、任意の操作を実行できますが、次の 2 つの欠点があります。 1. テスト スクリプトは Java 言語のみを使用できます。 2. テストスクリプト 実行するには、jar または apk パッケージにパッケージ化してデバイスにアップロードする必要があります。
テスト ロジックを Python で記述して、コンピューター上で実行しながら携帯電話を制御できることを期待しています。このアイデアを実現してくれた Xiaocong He (@xiaocong) に非常に感謝します (xiaocong/uiauTomator を参照)。原理は、携帯電話上で http rpc サービスを実行し、uiauTomator の機能を開き、これらの http を使用することです。インターフェイスは Python ライブラリにカプセル化されます。 xiaocong/uiautomator
ライブラリが長い間更新されていないためです。そこで、バージョンを直接フォークして、区別しやすくするために、最後に 2 つの openatx/uiauTomator2 を追加しました。また、対応する Android パッケージのソース コード、openatx/android-uiauTomator-server のコピーもフォークしました。
元のライブラリのバグが修正されたことに加えて、多くの新機能も追加されました。主に次の部分が含まれます。
まずここで説明します。openatx/uiauTomator2 は iOS テストをサポートしていないという質問がよくあるため、iOS 自動テストが必要な場合は、このライブラリ openatx/facebook-wda にアクセスしてください。
追伸:このライブラリは
https://github.com/NeteaseGame/ATXメンテナンスは終了しておりますので、お早めに交換してください。
すでに始めている人向けのクイック リファレンス ガイドです。コメントをお待ちしています。
まず、开发者选项
がオンになっている 1 台 (2 台ではなく) の Android スマートフォンを準備し、それをコンピューターに接続し、 adb devices
実行して接続されたデバイスが表示されることを確認します。
pip3 install -U uiautomator2
実行して uiauTomator2 をインストールします
コマンドラインからpython
実行して、Python 対話型ウィンドウを開きます。次に、ウィンドウに次のコマンドを入力します。
import uiautomator2 as u2
d = u2 . connect () # connect to device
print ( d . info )
以下のような出力が表示されたら、ライブラリの使用を正式に開始できます。このライブラリは機能が多すぎて、その背後に多くのコンテンツがあるため、ゆっくり読む必要があります...
{'currentPackageName': 'net.oneplus.launcher', 'displayHeight': 1920, 'displayRotation': 0, 'displaySizeDpX': 411, 'displaySizeDpY': 731, 'displayWidth': 1080, 'productName': 'OnePlus5', '
screenOn': True, 'sdkInt': 27, 'naturalOrientation': True}
さらに、安定性を維持するために、小黄车
のフローティング ウィンドウの許可を有効にする必要があります。参考記事 py-uiauTomator2 はフローティング ウィンドウを通じてサービスを長時間利用可能にします
通常は成功しますが、予期せぬ事態が発生する可能性があります。 QQ グループに参加して問題を報告できます (グループ番号は一番上にあります)。グループには問題解決を手伝ってくれる偉い人がたくさんいます。
スポンサーの皆様、ありがとうございます!
空の
優れた記事の推薦 (フィードバックが必要な場合は QQ グループへようこそ)
成都-测试只会一点点
インストール
デバイスに接続する
コマンドライン
グローバル設定
アプリ管理
UIの自動化
貢献者
ライセンス
uiautomator2 をインストールする
pip install -U uiautomator2
インストールが成功したかどうかをテストします。 uiautomator2 --help
UIインスペクター
pip install uiautodev
# 启动
uiauto.dev
ブラウザで https://uiauto.dev を開いて、現在のデバイスのインターフェイス構造を表示します。
uiauto.dev
uiauto.dev は uiautomator2 から独立したプロジェクトであり、レイヤー構造を表示するために使用されます。これは古いプロジェクト エディターの再構築バージョンであり、現在のプロジェクトの継続的なメンテナンスをサポートするために後で請求される可能性があります (価格は間違いなくお金の価値があります)。ご興味がございましたら、グループに参加して議論(リクエストも含む)してください。QQ グループ 536481989
シリアル番号を使用してデバイスを接続します。例: 123456f
( adb devices
から参照)
import uiautomator2 as u2
d = u2 . connect ( '123456f' ) # alias for u2.connect_usb('123456f')
print ( d . info )
env-var ANDROID_SERIAL
を介してシリアルを渡すことができます
# export ANDROID_SERIAL=123456f
d = u2 . connect ()
$device_ip
デバイスの IP アドレスを表します
デバイスを指定する必要がある場合は、 python3 -m uiautomator2 --serial bff1234 <SubCommand>
のように--serial
を渡す必要があります。 SubCommand はサブコマンド (スクリーンショット、現在のコマンドなど) です。
1.0.3 追加:
python3 -m uiautomator2
uiautomator2
と等しい
スクリーンショット: スクリーンショット
$ uiautomator2 screenshot screenshot.jpg
current: 現在のパッケージ名とアクティビティを取得します。
$ uiautomator2 current
{
" package " : " com.android.browser " ,
" activity " : " com.uc.browser.InnerUCMobile " ,
" pid " : 28478
}
アンインストール: アプリをアンインストールします
$ uiautomator2 uninstall < package-name > # 卸载一个包
$ uiautomator2 uninstall < package-name- 1> < package-name- 2> # 卸载多个包
$ uiautomator2 uninstall --all # 全部卸载
stop:アプリを停止します
$ uiautomator2 stop com.example.app # 停止一个app
$ uiautomator2 stop --all # 停止所有的app
医者:
$ uiautomator2 doctor
[I 2024-04-25 19:53:36,288 __main__:101 pid:15596] uiautomator2 is OK
Python が終了すると、UiAutomation サービスも終了します。
コードの背後にある HTTP リクエスト情報を出力します。
> >> d . debug = True
> >> d . info
12 : 32 : 47.182 $ curl - X POST - d '{"jsonrpc": "2.0", "id": "b80d3a488580be1f3e9cb3e926175310", "method": "deviceInfo", "params": {}}' 'http://127.0.0.1:54179/jsonrpc/0'
12 : 32 : 47.225 Response >> >
{ "jsonrpc" : "2.0" , "id" : "b80d3a488580be1f3e9cb3e926175310" , "result" :{ "currentPackageName" : "com.android.mms" , "displayHeight" : 1920 , "displayRotation" : 0 , "displaySizeDpX" : 360 , "displaySizeDpY" : 640 , "displayWidth" : 1080 , "productName"
: "odin" , "screenOn" : true , "sdkInt" : 25 , "naturalOrientation" : true }}
< << END
要素検索待ち時間の設定 (デフォルトは 20 秒)
d . implicitly_wait ( 10.0 ) # 也可以通过d.settings['wait_timeout'] = 10.0 修改
d ( text = "Settings" ). click () # if Settings button not show in 10s, UiObjectNotFoundError will raised
print ( "wait timeout" , d . implicitly_wait ()) # get default implicit wait
この関数はclick
、 long_click
、 drag_to
、 get_text
、 set_text
、 clear_text
などに影響します。
このパートでは、アプリ管理を実行する方法を紹介します。
URL からの APK のインストールのみサポートされています
d . app_install ( 'http://some-domain.com/some.apk' )
# 默认的这种方法是先通过atx-agent解析apk包的mainActivity,然后调用am start -n $package/$activity启动
d . app_start ( "com.example.hello_world" )
# 使用 monkey -p com.example.hello_world -c android.intent.category.LAUNCHER 1 启动
# 这种方法有个副作用,它自动会将手机的旋转锁定给关掉
d . app_start ( "com.example.hello_world" , use_monkey = True ) # start with package name
# 通过指定main activity的方式启动应用,等价于调用am start -n com.example.hello_world/.MainActivity
d . app_start ( "com.example.hello_world" , ".MainActivity" )
# equivalent to `am force-stop`, thus you could lose data
d . app_stop ( "com.example.hello_world" )
# equivalent to `pm clear`
d . app_clear ( 'com.example.hello_world' )
# stop all
d . app_stop_all ()
# stop all app except for com.examples.demo
d . app_stop_all ( excludes = [ 'com.examples.demo' ])
d . app_info ( "com.examples.demo" )
# expect output
#{
# "mainActivity": "com.github.uiautomator.MainActivity",
# "label": "ATX",
# "versionName": "1.1.7",
# "versionCode": 1001007,
# "size":1760809
#}
# save app icon
img = d . app_icon ( "com.examples.demo" )
img . save ( "icon.png" )
d . app_list_running ()
# expect output
# ["com.xxxx.xxxx", "com.github.uiautomator", "xxxx"]
pid = d . app_wait ( "com.example.android" ) # 等待应用运行, return pid(int)
if not pid :
print ( "com.example.android is not running" )
else :
print ( "com.example.android pid is %d" % pid )
d . app_wait ( "com.example.android" , front = True ) # 等待应用前台运行
d . app_wait ( "com.example.android" , timeout = 20.0 ) # 最长等待时间20s(默认)
バージョン1.2.0で追加されました
ファイルをデバイスにプッシュする
# push to a folder
d . push ( "foo.txt" , "/sdcard/" )
# push and rename
d . push ( "foo.txt" , "/sdcard/bar.txt" )
# push fileobj
with open ( "foo.txt" , 'rb' ) as f :
d . push ( f , "/sdcard/" )
# push and change file access mode
d . push ( "foo.sh" , "/data/local/tmp/" , mode = 0o755 )
デバイスからファイルをプルする
d . pull ( "/sdcard/tmp.txt" , "tmp.txt" )
# FileNotFoundError will raise if the file is not found on the device
d . pull ( "/sdcard/some-file-not-exists.txt" , "tmp.txt" )
# grant all the permissions
d . app_auto_grant_permissions ( "io.appium.android.apis" )
# open scheme
d . open_url ( "appname://appnamehost" )
# same as
# adb shell am start -a android.intent.action.VIEW -d "appname://appnamehost"
このパートでは、一般的なデバイス操作を実行する方法を紹介します。
タイムアウト保護を使用して短期間のシェル コマンドを実行します (デフォルトのタイムアウトは 60 秒)。
注: タイムアウトのサポートにはatx-agent >=0.3.3
が必要です
adb_shell
関数は非推奨です。代わりにshell
を使用してください。
簡単な使い方
output , exit_code = d . shell ( "pwd" , timeout = 60 ) # timeout 60s (Default)
# output: "/n", exit_code: 0
# Similar to command: adb shell pwd
# Since `shell` function return type is `namedtuple("ShellResponse", ("output", "exit_code"))`
# so we can do some tricks
output = d . shell ( "pwd" ). output
exit_code = d . shell ( "pwd" ). exit_code
たとえば、最初の引数にはリストを指定できます。
output , exit_code = d . shell ([ "ls" , "-l" ])
# output: "/....", exit_code: 0
これは、stderr とマージされた stdout の文字列を返します。コマンドがブロック コマンドである場合、 shell
コマンドが完了するかタイムアウトが発生するまでブロックされます。この API は、コマンドの実行中に部分的な出力を受信しません。長時間実行されるコマンドに適しています。指定されたシェル コマンドは、 adb
またはshell
の Linux 権限レベル (アプリの権限よりも高い) を持つadb shell
と同様の環境で実行されます。
長時間実行されるシェル コマンドを実行する (削除されました)
セッションはアプリのライフサイクルを表し、アプリの起動やアプリのクラッシュの検出に使用できます。
アプリの起動と終了
sess = d . session ( "com.netease.cloudmusic" ) # start 网易云音乐
sess . close () # 停止网易云音乐
sess . restart () # 冷启动网易云音乐
Python を使用しwith
アプリを起動および終了する
with d . session ( "com.netease.cloudmusic" ) as sess :
sess ( text = "Play" ). click ()
実行中のアプリにアタッチする
# launch app if not running, skip launch if already running
sess = d . session ( "com.netease.cloudmusic" , attach = True )
アプリのクラッシュを検出する
# When app is still running
sess ( text = "Music" ). click () # operation goes normal
# If app crash or quit
sess ( text = "Music" ). click () # raise SessionBrokenError
# other function calls under session will raise SessionBrokenError too
# check if session is ok.
# Warning: function name may change in the future
sess . running () # True or False
基本情報を取得する
d . info
以下は考えられる出力です。
{'currentPackageName': 'com.android.systemui',
'displayHeight': 1560,
'displayRotation': 0,
'displaySizeDpX': 360,
'displaySizeDpY': 780,
'displayWidth': 720,
'naturalOrientation': True,
'productName': 'ELE-AL00',
'screenOn': True,
'sdkInt': 29}
ウィンドウサイズを取得する
print ( d . window_size ())
# device upright output example: (1080, 1920)
# device horizontal output example: (1920, 1080)
現在のアプリ情報を取得します。一部の Android デバイスでは、出力が空になる場合があります (出力例 3を参照)。
print ( d . app_current ())
# Output example 1: {'activity': '.Client', 'package': 'com.netease.example', 'pid': 23710}
# Output example 2: {'activity': '.Client', 'package': 'com.netease.example'}
# Output example 3: {'activity': None, 'package': None}
待機アクティビティ
d . wait_activity ( ".ApiDemos" , timeout = 10 ) # default timeout 10.0 seconds
# Output: true of false
デバイスのシリアル番号を取得する
print ( d . serial )
# output example: 74aAEDR428Z9
WLAN IPを取得する
print ( d . wlan_ip )
# output example: 10.0.0.1 or None
詳細なデバイス情報を取得するd.device_info
デバイス情報
print ( d . device_info )
以下は考えられる出力です。
{'arch': 'arm64-v8a',
'brand': 'google',
'model': 'sdk_gphone64_arm64',
'sdk': 34,
'serial': 'EMULATOR34X1X19X0',
'version': 14}
セットされたクリップボードの内容の取得
ペーストボードのコンテンツを設定するか、コンテンツを取得します
クリップボード/set_clipboard
d . clipboard = 'hello-world'
# or
d . set_clipboard ( 'hello-world' , 'label' )
クリップボードの内容を取得する
クリップボードを取得するには、使用する前に IME(com.github.uiauTomator/.AdbKeyboard)
d.set_input_ime()
を呼び出す必要があります。
```python
# get clipboard content
print(d.clipboard)
```
画面のオン/オフ
d . screen_on () # turn on the screen
d . screen_off () # turn off the screen
現在の画面ステータスを取得する
d . info . get ( 'screenOn' ) # require Android >= 4.4
ハードキー/ソフトキーを押します
d . press ( "home" ) # press the home key, with key name
d . press ( "back" ) # press the back key, with key name
d . press ( 0x07 , 0x02 ) # press keycode 0x07('0') with META ALT(0x02)
現在、次のキー名がサポートされています。
すべてのキーコード定義は Android KeyEvnet で見つけることができます。
画面のロックを解除する
d . unlock ()
# This is equivalent to
# 1. press("power")
# 2. swipe from left-bottom to right-top
画面をクリックしてください
d . click ( x , y )
ダブルクリック
d . double_click ( x , y )
d . double_click ( x , y , 0.1 ) # default duration between two click is 0.1s
画面を長押しします
d . long_click ( x , y )
d . long_click ( x , y , 0.5 ) # long click 0.5s (default)
スワイプ
d . swipe ( sx , sy , ex , ey )
d . swipe ( sx , sy , ex , ey , 0.5 ) # swipe for 0.5s(default)
SwipeExt拡張機能
d . swipe_ext ( "right" ) # 手指右滑,4选1 "left", "right", "up", "down"
d . swipe_ext ( "right" , scale = 0.9 ) # 默认0.9, 滑动距离为屏幕宽度的90%
d . swipe_ext ( "right" , box = ( 0 , 0 , 100 , 100 )) # 在 (0,0) -> (100, 100) 这个区域做滑动
# 实践发现上滑或下滑的时候,从中点开始滑动成功率会高一些
d . swipe_ext ( "up" , scale = 0.8 ) # 代码会vkk
# 还可以使用Direction作为参数
from uiautomator2 import Direction
d . swipe_ext ( Direction . FORWARD ) # 页面下翻, 等价于 d.swipe_ext("up"), 只是更好理解
d . swipe_ext ( Direction . BACKWARD ) # 页面上翻
d . swipe_ext ( Direction . HORIZ_FORWARD ) # 页面水平右翻
d . swipe_ext ( Direction . HORIZ_BACKWARD ) # 页面水平左翻
ドラッグ
d . drag ( sx , sy , ex , ey )
d . drag ( sx , sy , ex , ey , 0.5 ) # swipe for 0.5s(default)
スワイプポイント
# swipe from point(x0, y0) to point(x1, y1) then to point(x2, y2)
# time will speed 0.2s bwtween two points
d . swipe_points ([( x0 , y0 ), ( x1 , y1 ), ( x2 , y2 )], 0.2 ))
主に、Jugong パターンのロックを解除するために使用されます。各ポイントの相対座標を事前に取得できます (パーセンテージはここでサポートされています)。詳細な使用方法については、この投稿を参照してください。
タッチアンドドラッグ(ベータ版)
このインターフェイスは比較的低レベルの原始的なインターフェイスであり、完璧とは言えませんが、使用可能です。注: この場所ではパーセンテージはサポートされていません
d . touch . down ( 10 , 10 ) # 模拟按下
time . sleep ( .01 ) # down 和 move 之间的延迟,自己控制
d . touch . move ( 15 , 15 ) # 模拟移动
d . touch . up ( 10 , 10 ) # 模拟抬起
注: クリック、スワイプ、ドラッグ操作では、位置のパーセント値がサポートされます。例:
d.long_click(0.5, 0.5)
画面の中央を長押しすることを意味します
デバイスの向きを取得/設定する
可能な方向は次のとおりです。
natural
またはn
left
またはl
right
またはr
upsidedown
またはu
(設定不可) # retrieve orientation. the output could be "natural" or "left" or "right" or "upsidedown"
orientation = d . orientation
# WARNING: not pass testing in my TT-M1
# set orientation and freeze rotation.
# notes: setting "upsidedown" requires Android>=4.3.
d . set_orientation ( 'l' ) # or "left"
d . set_orientation ( "l" ) # or "left"
d . set_orientation ( "r" ) # or "right"
d . set_orientation ( "n" ) # or "natural"
回転のフリーズ/フリーズ解除
# freeze rotation
d . freeze_rotation ()
# un-freeze rotation
d . freeze_rotation ( False )
スクリーンショットを撮る
# take screenshot and save to a file on the computer, require Android>=4.2.
d . screenshot ( "home.jpg" )
# get PIL.Image formatted images. Naturally, you need pillow installed first
image = d . screenshot () # default format="pillow"
image . save ( "home.jpg" ) # or home.png. Currently, only png and jpg are supported
# get opencv formatted images. Naturally, you need numpy and cv2 installed first
import cv2
image = d . screenshot ( format = 'opencv' )
cv2 . imwrite ( 'home.jpg' , image )
# get raw jpeg data
imagebin = d . screenshot ( format = 'raw' )
open ( "some.jpg" , "wb" ). write ( imagebin )
ダンプ UI 階層
# get the UI hierarchy dump content
xml = d . dump_hierarchy ()
# compressed=True: include not import nodes
# pretty: format xml
# max_depth: limit xml depth, default 50
xml = d . dump_hierarchy ( compressed = False , pretty = False , max_depth = 50 )
通知またはクイック設定を開く
d . open_notification ()
d . open_quick_settings ()
セレクターは、現在のウィンドウ内の特定の UI オブジェクトを識別する便利なメカニズムです。
# Select the object with text 'Clock' and its className is 'android.widget.TextView'
d ( text = 'Clock' , className = 'android.widget.TextView' )
セレクターは以下のパラメーターをサポートしています。詳細については、UiSelector Java ドキュメントを参照してください。
text
、 textContains
、 textMatches
、 textStartsWith
className
、 classNameMatches
description
、 descriptionContains
、 descriptionMatches
、 descriptionStartsWith
checkable
、 checked
、 clickable
、 longClickable
scrollable
、 enabled
、 focusable
、 focused
、 selected
packageName
、 packageNameMatches
resourceId
、 resourceIdMatches
index
、 instance
子供たち
# get the children or grandchildren
d ( className = "android.widget.ListView" ). child ( text = "Bluetooth" )
兄弟