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メンテナンスは終了しておりますので、お早めに交換してください。
これは、すでに始めている人に適したクイックリファレンス QUICK REFERENCE GUIDE です。コメントを歓迎します。
まず、开发者选项
がオンになっている 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
のように--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 は、コマンドの実行中に部分的な出力を受信しません。長時間実行されるコマンドに適しています。指定されたシェル コマンドは、Linux 権限レベルadb
またはshell
(アプリ権限よりも高い) を持つ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" )
兄弟
# get siblings
d ( text = "Google" ). sibling ( className = "android.widget.ImageView" )
テキスト、説明、またはインスタンスによる子
# get the child matching the condition className="android.widget.LinearLayout"
# and also its children or grandchildren with text "Bluetooth"
d ( className = "android.widget.ListView" , resourceId = "android:id/list" )
. child_by_text ( "Bluetooth" , className = "android.widget.LinearLayout" )
# get children by allowing scroll search
d ( className = "android.widget.ListView" , resourceId = "android:id/list" )
. child_by_text (
"Bluetooth" ,
allow_scroll_search = True ,
className = "android.widget.LinearLayout"
)
child_by_description
は、指定された説明を持つ孫を持つ子を検索します。他のパラメータはchild_by_text
と同様です。
child_by_instance
は、指定されたインスタンスにあるサブ階層内の任意の場所にある子 UI 要素を持つ子を検索します。これは、スクロールせずに表示されているビューに対して実行されます。
詳細については、以下のリンクを参照してください。
getChildByDescription
、 getChildByText
、 getChildByInstance
getChildByDescription
、 getChildByText
、 getChildByInstance
上記のメソッドは、たとえば階層の下の場合など、連鎖呼び出しをサポートします。
< node index = " 0 " text = " " resource-id = " android:id/list " class = " android.widget.ListView " ...>
< node index = " 0 " text = " WIRELESS & NETWORKS " resource-id = " " class = " android.widget.TextView " .../>
< node index = " 1 " text = " " resource-id = " " class = " android.widget.LinearLayout " ...>
< node index = " 1 " text = " " resource-id = " " class = " android.widget.RelativeLayout " ...>
< node index = " 0 " text = " Wi‑Fi " resource-id = " android:id/title " class = " android.widget.TextView " .../>
node >
< node index = " 2 " text = " ON " resource-id = " com.android.settings:id/switchWidget " class = " android.widget.Switch " .../>
node >
...
node >
TextView 'Wi‑Fi' のすぐ近くにあるスイッチ ウィジェットをクリックするには、最初にスイッチ ウィジェットを選択する必要があります。ただし、UI 階層によれば、複数のスイッチ ウィジェットが存在し、className で選択することはできません。あるいは、以下の選択戦略も役に立ちます。
d ( className = "android.widget.ListView" , resourceId = "android:id/list" )
. child_by_text ( "Wi‑Fi" , className = "android.widget.LinearLayout" )
. child ( className = "android.widget.Switch" )
. click ()
相対的な位置決め
また、相対配置メソッドを使用してビューを取得することもできます: left
、 right
、 top
、 bottom
。
d(A).left(B)
、A の左側の B を選択します。d(A).right(B)
、Aの右側のBを選択します。d(A).up(B)
、A の上の B を選択します。d(A).down(B)
、A の下の B を選択します。したがって、上記の場合、次の方法で選択することもできます。
## select "switch" on the right side of "Wi‑Fi"
d ( text = "Wi‑Fi" ). right ( className = "android.widget.Switch" ). click ()
複数のインスタンス
場合によっては、画面に同じプロパティ (テキストなど) を持つ複数のビューが含まれる場合があります。その場合は、以下のように、セレクターで「インスタンス」プロパティを使用して、条件を満たすインスタンスの 1 つを選択する必要があります。
d ( text = "Add new" , instance = 0 ) # which means the first instance with text "Add new"
さらに、uiauTomator2 はリストのような API (jQuery に似た) を提供します。
# get the count of views with text "Add new" on current screen
d ( text = "Add new" ). count
# same as count property
len ( d ( text = "Add new" ))
# get the instance via index
d ( text = "Add new" )[ 0 ]
d ( text = "Add new" )[ 1 ]
...
# iterator
for view in d ( text = "Add new" ):
view . info # ...
注: 結果リストを参照するコード ブロックでセレクターを使用する場合は、画面上の UI 要素が変更されないようにする必要があります。そうしないと、リストを反復処理するときに Element-Not-Found エラーが発生する可能性があります。
特定の UI オブジェクトが存在するかどうかを確認する
d ( text = "Settings" ). exists # True if exists, else False
d . exists ( text = "Settings" ) # alias of above property.
# advanced usage
d ( text = "Settings" ). exists ( timeout = 3 ) # wait Settings appear in 3s, same as .wait(3)
特定の UI オブジェクトの情報を取得します
d ( text = "Settings" ). info
以下は考えられる出力です。
{ u'contentDescription': u'',
u'checked': False,
u'scrollable': False,
u'text': u'Settings',
u'packageName': u'com.android.launcher',
u'selected': False,
u'enabled': True,
u'bounds': {u'top': 385,
u'right': 360,
u'bottom': 585,
u'left': 200},
u'className': u'android.widget.TextView',
u'focused': False,
u'focusable': True,
u'clickable': True,
u'chileCount': 0,
u'longClickable': True,
u'visibleBounds': {u'top': 385,
u'right': 360,
u'bottom': 585,
u'left': 200},
u'checkable': False
}
編集可能なフィールドのテキストを取得/設定/クリアします (例: EditText ウィジェット)
d ( text = "Settings" ). get_text () # get widget text
d ( text = "Settings" ). set_text ( "My text..." ) # set the text
d ( text = "Settings" ). clear_text () # clear the text
ウィジェットの中心点を取得
x , y = d ( text = "Settings" ). center ()
# x, y = d(text="Settings").center(offset=(0, 0)) # left-top x, y
ウィジェットのスクリーンショットを撮る
im = d ( text = "Settings" ). screenshot ()
im . save ( "settings.jpg" )
特定のオブジェクトをクリックして実行します
# click on the center of the specific ui object
d ( text = "Settings" ). click ()
# wait element to appear for at most 10 seconds and then click
d ( text = "Settings" ). click ( timeout = 10 )
# click with offset(x_offset, y_offset)
# click_x = x_offset * width + x_left_top
# click_y = y_offset * height + y_left_top
d ( text = "Settings" ). click ( offset = ( 0.5 , 0.5 )) # Default center
d ( text = "Settings" ). click ( offset = ( 0 , 0 )) # click left-top
d ( text = "Settings" ). click ( offset = ( 1 , 1 )) # click right-bottom
# click when exists in 10s, default timeout 0s
clicked = d ( text = 'Skip' ). click_exists ( timeout = 10.0 )
# click until element gone, return bool
is_gone = d ( text = "Skip" ). click_gone ( maxretry = 10 , interval = 1.0 ) # maxretry default 10, interval default 1.0
特定の UI オブジェクトを長押しします。
# long click on the center of the specific UI object
d ( text = "Settings" ). long_click ()
UI オブジェクトを別の点または別の UI オブジェクトに向かってドラッグします。
# notes : drag can not be used for Android<4.3.
# drag the UI object to a screen point (x, y), in 0.5 second
d ( text = "Settings" ). drag_to ( x , y , duration = 0.5 )
# drag the UI object to (the center position of) another UI object, in 0.25 second
d ( text = "Settings" ). drag_to ( text = "Clock" , duration = 0.25 )
UI オブジェクトの中心から端までスワイプします
スワイプは 4 方向をサポートします。
d ( text = "Settings" ). swipe ( "right" )
d ( text = "Settings" ). swipe ( "left" , steps = 10 )
d ( text = "Settings" ). swipe ( "up" , steps = 20 ) # 1 steps is about 5ms, so 20 steps is about 0.1s
d ( text = "Settings" ). swipe ( "down" , steps = 20 )
ある点から別の点への 2 点ジェスチャ
d ( text = "Settings" ). gesture (( sx1 , sy1 ), ( sx2 , sy2 ), ( ex1 , ey1 ), ( ex2 , ey2 ))
特定の UI オブジェクトに対する 2 点ジェスチャ
2 つのジェスチャをサポートします。
In
、端から中心までOut
、中心から端まで # notes : pinch can not be set until Android 4.3.
# from edge to center. here is "In" not "in"
d ( text = "Settings" ). pinch_in ( percent = 100 , steps = 10 )
# from center to edge
d ( text = "Settings" ). pinch_out ()
特定の UI が表示されるか消えるまで待ちます
# wait until the ui object appears
d ( text = "Settings" ). wait ( timeout = 3.0 ) # return bool
# wait until the ui object gone
d ( text = "Settings" ). wait_gone ( timeout = 1.0 )
デフォルトのタイムアウトは 20 秒です。詳細については、グローバル設定を参照してください。
特定の ui オブジェクトでフリングを実行します (スクロール可能)
考えられるプロパティ:
horiz
またはvert
forward
またはbackward
、またはtoBeginning
またはtoEnd
# fling forward(default) vertically(default)
d ( scrollable = True ). fling ()
# fling forward horizontally
d ( scrollable = True ). fling . horiz . forward ()
# fling backward vertically
d ( scrollable = True ). fling . vert . backward ()
# fling to beginning horizontally
d ( scrollable = True ). fling . horiz . toBeginning ( max_swipes = 1000 )
# fling to end vertically
d ( scrollable = True ). fling . toEnd ()
特定の ui オブジェクトでスクロールを実行します (スクロール可能)
考えられるプロパティ:
horiz
またはvert
forward
またはbackward
、またはtoBeginning
またはtoEnd
、またはto
# scroll forward(default) vertically(default)
d ( scrollable = True ). scroll ( steps = 10 )
# scroll forward horizontally
d ( scrollable = True ). scroll . horiz . forward ( steps = 100 )
# scroll backward vertically
d ( scrollable = True ). scroll . vert . backward ()
# scroll to beginning horizontally
d ( scrollable = True ). scroll . horiz . toBeginning ( steps = 100 , max_swipes = 1000 )
# scroll to end vertically
d ( scrollable = True ). scroll . toEnd ()
# scroll forward vertically until specific ui object appears
d ( scrollable = True ). scroll . to ( text = "Security" )
現在の watch_context はスレッドを使用して開始され、2 秒ごとにチェックされます。現時点では、トリガー操作は 1 つだけです。クリックです。
with d . watch_context () as ctx :
# 当同时出现 (立即下载 或 立即更新)和 取消 按钮的时候,点击取消
ctx . when ( "^立即(下载|更新)" ). when ( "取消" ). click ()
ctx . when ( "同意" ). click ()
ctx . when ( "确定" ). click ()
# 上面三行代码是立即执行完的,不会有什么等待
ctx . wait_stable () # 开启弹窗监控,并等待界面稳定(两个弹窗检查周期内没有弹窗代表稳定)
# 使用call函数来触发函数回调
# call 支持两个参数,d和el,不区分参数位置,可以不传参,如果传参变量名不能写错
# eg: 当有元素匹配仲夏之夜,点击返回按钮
ctx . when ( "仲夏之夜" ). call ( lambda d : d . press ( "back" ))
ctx . when ( "确定" ). call ( lambda el : el . click ())
# 其他操作
# 为了方便也可以使用代码中默认的弹窗监控逻辑
# 下面是目前内置的默认逻辑,可以加群at群主,增加新的逻辑,或者直接提pr
# when("继续使用").click()
# when("移入管控").when("取消").click()
# when("^立即(下载|更新)").when("取消").click()
# when("同意").click()
# when("^(好的|确定)").click()
with d . watch_context ( builtin = True ) as ctx :
# 在已有的基础上增加
ctx . when ( "@tb:id/jview_view" ). when ( '//*[@content-desc="图片"]' ). click ()
# 其他脚本逻辑
別の書き方
ctx = d . watch_context ()
ctx . when ( "设置" ). click ()
ctx . wait_stable () # 等待界面不在有弹窗了
ctx . close ()
より簡潔に記述するにはWatchContext を使用することをお勧めします。
セレクターが一致を見つけられなかった場合にいくつかのアクションを実行するためにウォッチャーを登録できます。
2.0.0 より前では、uiauTomator-jar ライブラリで提供される [Watcher]((http://developer.android.com/tools/help/uiauTomator/UiWatcher.html) メソッドが使用されていましたが、実際には、 uiautomator の接続に失敗しました。再起動後、すべてのウォッチャー設定が失われますが、これは絶対に容認できません。
したがって、現在の方法では、バックグラウンドで (スレッド ライブラリに依存して) スレッドを実行し、時々階層をダンプし、要素を照合した後に対応する操作を実行します。
使用例
登録監視
# 常用写法,注册匿名监控
d . watcher . when ( "安装" ). click ()
# 注册名为ANR的监控,当出现ANR和Force Close时,点击Force Close
d . watcher ( "ANR" ). when ( xpath = "ANR" ). when ( "Force Close" ). click ()
# 其他回调例子
d . watcher . when ( "抢红包" ). press ( "back" )
d . watcher . when ( "//*[@text = 'Out of memory']" ). call ( lambda d : d . shell ( 'am force-stop com.im.qq' ))
# 回调说明
def click_callback ( d : u2 . Device ):
d . xpath ( "确定" ). click () # 在回调中调用不会再次触发watcher
d . xpath ( "继续" ). click () # 使用d.xpath检查元素的时候,会触发watcher(目前最多触发5次)
# 开始后台监控
d . watcher . start ()
監視操作
# 移除ANR的监控
d . watcher . remove ( "ANR" )
# 移除所有的监控
d . watcher . remove ()
# 开始后台监控
d . watcher . start ()
d . watcher . start ( 2.0 ) # 默认监控间隔2.0s
# 强制运行所有监控
d . watcher . run ()
# 停止监控
d . watcher . stop ()
# 停止并移除所有的监控,常用于初始化
d . watcher . reset ()
さらに、まだ書かれていないドキュメントがたくさんあります。ソース コード watcher.py に直接アクセスすることをお勧めします。
u2 . HTTP_TIMEOUT = 60 # 默认值60s, http默认请求超时时间
他の設定のほとんどは現在d.settings
に集中しており、この設定は後で必要に応じて増減される可能性があります。
print ( d . settings )
{ 'operation_delay' : ( 0 , 0 ),
'operation_delay_methods' : [ 'click' , 'swipe' ],
'wait_timeout' : 20.0 }
# 配置点击前延时0.5s,点击后延时1s
d . settings [ 'operation_delay' ] = ( .5 , 1 )
# 修改延迟生效的方法
# 其中 double_click, long_click 都对应click
d . settings [ 'operation_delay_methods' ] = [ 'click' , 'swipe' , 'drag' , 'press' ]
d . settings [ 'wait_timeout' ] = 20.0 # 默认控件等待时间(原生操作,xpath插件的等待时间)
d . settings [ 'max_depth' ] = 50 # 默认50,限制dump_hierarchy返回的元素层级
バージョン アップグレードの場合、期限切れの構成を設定すると、「非推奨」というメッセージが表示されますが、例外はスローされません。
>>> d.settings[ ' click_before_delay ' ] = 1
[W 200514 14:55:59 settings:72] d.settings[click_before_delay] deprecated: Use operation_delay instead
uiautomator リカバリモード設定
注意していれば、実際には 2 つの APK が携帯電話にインストールされていることがわかります。そのうちの 1 つが前景 (小さな黄色い車) に表示されています。 com.github.uiautomator.test
という名前のパッケージはバックグラウンドでは表示されません。これら 2 つの APK は同じ証明書で署名されています。 非表示のアプリケーションは、実際にはすべてのテスト コードを含むテスト パッケージであり、コア テスト サービスもそれを通じて開始されます。 ただし、実行中、システムは小さな黄色い車を常に実行している必要があります (バックグラウンドで実行することもできます)。小さな黄色い車のアプリケーションが終了すると、バックグラウンドで実行されているテスト サービスもすぐに終了します。何もしなくても、アプリケーションがバックグラウンドにある場合、アプリケーションはシステムによってすぐにリサイクルされます。 (専門家が偽アプリへの依存を避ける方法についてアドバイスをくれることを願っています。理論的には可能だと思いますが、その方法はまだわかりません。)
小さな黄色い車をバックグラウンドで実行するには 2 つの方法があります。1 つは、アプリケーションを起動してバックグラウンドに置く方法です (デフォルト)。さらに、 am startservice
を通じてバックグラウンド サービスを開始することもできます。
この動作はd.settings["uiautomator_runtest_app_background"] = True
によって調整できます。 True はアプリケーションを開始することを意味し、False はサービスを開始することを意味します。
UiAutomator のタイムアウト設定 (隠しメソッド)
>> d . jsonrpc . getConfigurator ()
{ 'actionAcknowledgmentTimeout' : 500 ,
'keyInjectionDelay' : 0 ,
'scrollAcknowledgmentTimeout' : 200 ,
'waitForIdleTimeout' : 0 ,
'waitForSelectorTimeout' : 0 }
>> d . jsonrpc . setConfigurator ({ "waitForIdleTimeout" : 100 })
{ 'actionAcknowledgmentTimeout' : 500 ,
'keyInjectionDelay' : 0 ,
'scrollAcknowledgmentTimeout' : 200 ,
'waitForIdleTimeout' : 100 ,
'waitForSelectorTimeout' : 0 }
クライアント プログラムがタイムアウトに応答しないようにするために、 waitForIdleTimeout
とwaitForSelectorTimeout
が0
に変更されました。
参考: Google uiautomator コンフィギュレーター
このメソッドは通常、コントロールが不明な入力に使用されます。
# 目前采用从剪贴板粘贴的方式输入
d . send_keys ( "你好123abcEFG" )
d . send_keys ( "你好123abcEFG" , clear = True )
d . clear_text () # 清除输入框所有内容
d . send_action () # 根据输入框的需求,自动执行回车、搜索等指令, Added in version 3.1
# 也可以指定发送的输入法action, eg: d.send_action("search") 支持 go, search, send, next, done, previous
print ( d . current_ime ()) # 获取当前输入法ID
詳細参照: IME_ACTION_CODE
print ( d . last_toast ) # get last toast, if not toast return None
d . clear_toast ()
バージョン 3.2.0 で修正されました
Java uiautoamtor はデフォルトでは xpath をサポートしていないため、これは拡張機能です。速度はそれほど速くありません。
例: いずれかのノードの内容
">< android .widget.TextView index = " 2 " text = " 05:19 " resource-id = " com.netease.cloudmusic:id/qf " package = " com.netease.cloudmusic " content-desc = " " checkable = " false " checked = " false " clickable = " false " enabled = " true " focusable = " false " focused = " false " scrollable = " false " long-clickable = " false " password = " false " selected = " false " visible-to-user = " true " bounds = " [957,1602][1020,1636] " />
xpathの位置決めと使用法
一部の属性の名前は変更されているため、注意が必要です。
description -> content-desc
resourceId -> resource-id
よくある使い方
# wait exists 10s
d . xpath ( "//android.widget.TextView" ). wait ( 10.0 )
# find and click
d . xpath ( "//*[@content-desc='分享']" ). click ()
# check exists
if d . xpath ( "//android.widget.TextView[contains(@text, 'Se')]" ). exists :
print ( "exists" )
# get all text-view text, attrib and center point
for elem in d . xpath ( "//android.widget.TextView" ). all ():
print ( "Text:" , elem . text )
# Dictionary eg:
# {'index': '1', 'text': '999+', 'resource-id': 'com.netease.cloudmusic:id/qb', 'package': 'com.netease.cloudmusic', 'content-desc': '', 'checkable': 'false', 'checked': 'false', 'clickable': 'false', 'enabled': 'true', 'focusable': 'false', 'focused': 'false','scrollable': 'false', 'long-clickable': 'false', 'password': 'false', 'selected': 'false', 'visible-to-user': 'true', 'bounds': '[661,1444][718,1478]'}
print ( "Attrib:" , elem . attrib )
# Coordinate eg: (100, 200)
print ( "Position:" , elem . center ())
クリックすると、XPath のその他の一般的な使用法が表示されます
ビデオ録画 (廃止)、代わりに scrcpy を使用してください
ここでは携帯電話に付属の screenrecord コマンドは使用しません。携帯電話の写真を取得してビデオを合成する方法なので、imageio、imageio-ffmpeg、numpy などの他の依存関係をインストールする必要があります。依存関係が比較的大きいため、ミラー インストールを使用することをお勧めします。次のコマンドを実行するだけです。
pip3 install -U " uiautomator2[image] " -i https://pypi.doubanio.com/simple
使用方法
d.screenrecord('output.mp4')
time.sleep(10)
# or do something else
d.screenrecord.stop() # 停止录制后,output.mp4文件才能打开
録画時に fps (現在 20) を指定することもできます。この値は、ミニキャップ出力画像の速度よりも低いので、変更することはお勧めしません。
from uiautomator2 import enable_pretty_logging
enable_pretty_logging ()
または
logger = logging.getLogger("uiautomator2")
# setup logger
Python プログラムが終了すると、UiAutomation も終了します。 ただし、インターフェイス メソッドを通じてサービスを停止することもできます。
d . stop_uiautomator ()
https://www.cnblogs.com/insist8089/p/6898181.html
他の寄稿者
ランキング順です、追加歓迎です
マサチューセッツ工科大学