Posted at

Windows Application Driver (WinAppDriver) を利用してウインドウズアプリを操作する

More than 1 year has passed since last update.

Microsoft 謹製ウインドウズアプリ操作用 WebDriver の Windows Application Driver (WinAppDriver)

を利用してウインドウズアプリを操作します。

Java での実装を前提に記述していますが、他の言語でも基本的には同じです。

また、 WebDriver をある程度理解している人向けの内容です。


インストール

WebDriver をよしなにダウンロードして起動してくれる WebDriverManager は対応していないので、自前でダウンロードし、インストールする必要があります。



  1. GitHub のリリースページ から WindowsApplicationDriver.msi をダウンロードする

  2. ダウンロードした WindowsApplicationDriver.msi を実行する


起動

Selenium の ChromeDriver などのブラウザ用のドライバーはクラス生成時に自動で起動してくれますが、まだそのような実装がないため、自前でドライバを起動する必要1があります。

デフォルトのインストール先は C:\Program Files (x86)\Windows Application Driver\WinAppDriver.exe になります。

実行した際に以下のようなエラーメッセージが出た場合には、メッセージにあるように開発者モードを有効にしてからドライバを再起動する必要があります。

Developer mode is not enabled. Enable it through Settings and restart Windows Application Driver

Failed to initialize: 0x80004005

開発者モードを有効にするには デバイスを開発用に有効にする という Microsoft の記事を参考にしてください。

ドライバが正常に起動すると以下のようなメッセージが表示されます。

Windows Application Driver listening for requests at: http://127.0.0.1:4723/

Press ENTER to exit.


起動時引数

起動時引数に何も渡さずに起動すると http://127.0.0.1:4723/ でリッスンしますが、起動時引数で待ち受けるアドレスやポートを変更することができます。

WinAppDriver.exe 4727

WinAppDriver.exe 10.0.0.10 4725
WinAppDriver.exe 10.0.0.10 4723/wd/hub

IPアドレスを変更したい場合には管理者権限で起動する必要があります。


管理者権限での起動

IPアドレスを変更する際以外でも以下のような場合に管理者権限で起動する必要があります。


  • 管理者権限で実行する(している)アプリを操作する


管理者権限で実行する(している)アプリを操作する際の注意点

管理者権限で実行する(している)アプリを操作するにはアプリ起動時にUACの確認ダイアログが表示されてしまうため、確認ダイアログを無効にしないと操作できません。

UACの無効化については PowerShell:Windows 10 ユーザーアカウント制御設定編 などを参考にしてください。


操作対象アプリを起動する

Windows用ドライバインスタンス生成時に渡す Capabilities に基づいて操作対象アプリが起動されます。


  • Universal Windows Platform (UWP) アプリの場合

app にUWPアプリのIDを渡します。

DesiredCapabilities capabilities = new DesiredCapabilities();

capabilities.setCapability("app", "Microsoft.WindowsCalculator_8wekyb3d8bbwe!App");
WindowsDriver driver = new WindowsDriver(new URL("http://127.0.0.1:4723"), capabilities);


  • その他のアプリの場合

app に操作するアプリのフルパス、 appArguments にアプリの起動引数、 appWorkingDir にアプリの作業ディレクトリを渡します。

DesiredCapabilities capabilities = new DesiredCapabilities();

capabilities.setCapability("app", "C:\\Windows\\System32\\notepad.exe");
capabilities.setCapability("appArguments", "MyTestFile.txt");
capabilities.setCapability("appWorkingDir", "C:\\MyTestFolder\\");
WindowsDriver driver = new WindowsDriver(new URL("http://127.0.0.1:4723"), capabilities);


起動済みのアプリを操作する

常駐アプリなど起動済みのアプリを操作する場合、


  1. デスクトップ操作用ドライバインスタンスを生成する

  2. 起動済みアプリを表示する

  3. デスクトップ生成用ドライバインスタンスから起動済みアプリのハンドルを取得する

  4. 起動済みアプリのハンドルからアプリ操作用ドライバインスタンスを生成する

という手順が必要になります。

以下は Cortana を操作する際の例です。

// デスクトップ操作用ドライバインスタンスを生成

DesiredCapabilities desktopCapabilities = new DesiredCapabilities();
desktopCapabilities.setCapability("app", "Root");
WindowsDriver desktopSession = new WindowsDriver(new URL("http://127.0.0.1:4723"), desktopCapabilities);

// Cortana を表示
desktopSession.getKeyboard().pressKey(Keys.COMMAND + "a" + Keys.COMMAND);

// Cortana のハンドルを取得
WebElement cortanaWindow = desktopSession.findElementByName("Cortana");
String cortanaTopLevelWindowHandle = cortanaWindow.getAttribute("NativeWindowHandle");
cortanaTopLevelWindowHandle = Integer.valueOf(cortanaTopLevelWindowHandle).toHexString();

// アプリ操作用ドライバインスタンスを生成
DesiredCapabilities appCapabilities = new DesiredCapabilities();
appCapabilities.setCapability("appTopLevelWindow", cortanaTopLevelWindowHandle);
WindowsDriver cortanaSession = new WindowsDriver(new URL("http://127.0.0.1:4723"), appCapabilities);


要素の取得


要素の属性の確認方法

要素の属性を確認するには Windows SDK に含まれる inspect.exe というツールを用います。

ダウンロードは https://developer.microsoft.com/ja-jp/windows/downloads/sdk-archive から行えます。

操作方法については Inspectツールを使ってUIを調査するには?[Windows 8/Windows 8.1ストアアプリ開発] などを参考にしてください。


ロケータ

要素を取得するためのAPIと要素の属性の関係について、 公式 では以下のように説明されています。

API
属性

FindElementByAccessibilityId
AutomationId
AppNameTitle

FindElementByClassName
ClassName
TextBlock

FindElementById
RuntimeId (decimal)
42.333896.3.1

FindElementByName
Name
Calculator

FindElementByTagName
LocalizedControlType (upper camel case)
Text

FindElementByXPath
Any
//Button[0]

しかし、実際のところ FindElementByTagName については、 LocalizedControlType の値をそのまま利用しようとすると日本語環境だと inspect.exe には チェック ボックス と表示され、これをそのまま渡すとエラーになります。2


要素の操作

要素を取得できたあとは、 clicksendKeys などのメソッドを利用して操作したり、 getAttribute で各種属性の取得が行えます。


コンボボックスの選択ができない場合

コンボボックスでコンボボックスをクリック、ドロップダウン内のアイテムをクリックして選択するというような操作をしようとするとエラーは出ないが選択できないという場合があります。

WindowsElement comboBox = windowsDriver.findElementByName("コンボボックス");

comboBox.click(); // コンボボックスをクリックしてドロップダウンを表示
WindowsElement item = windowsDriver.findElementByName("アイテム");
item.click(); // 選択したいアイテムをクリック

このような場合、 GitHub の issue にあるように座標を指定してクリックしてやる必要があります。

WindowsElement comboBox = windowsDriver.findElementByName("コンボボックス");

comboBox.click(); // コンボボックスをクリックしてドロップダウンを表示
WindowsElement item = windowsDriver.findElementByName("アイテム");
windowsDriver.getMouse().click(item.getCoordinates()); // 選択したいアイテムの座標をクリック





  1. Selenium の DriverService を利用して起動させようとしたところ、起動はするがすぐに終了してしまう事象に遭遇しています。同様の問題が報告されており、現時点では別途起動する必要があります。 



  2. ControlTypeUIA_ControlTypeId を取り除くという情報もあります。