基礎知識

本章では、Android自動化に関する基礎知識を紹介します。必ず本章をお読みください。後ほど再び説明することはありません。Android自動化は、通常のWeb自動化とは大きく異なりますが、多くの共通点もあります。通常のWeb自動化では、F12開発者ツールを使ってWebページのレイアウトや要素IDなどを簡単に確認し、XPathで要素を取得してクリックや待機などの操作を行えます。Android環境でも同様に、セレクターと呼ばれるものを使って要素を選択し、クリックや判定などの操作が可能です。したがって、入門が難しいと心配する必要はありません。

モバイル自動化とWeb自動化の共通点と相違点

モバイル自動化とWeb自動化には多くの共通点があり、もちろん少なくない相違点もあります。Seleniumを例に考えてみましょう。通常、SeleniumでWebを制御するには3つのものが必要です。第一にブラウザ、第二にWebDriver、第三にSeleniumです。モバイルでも同様で、スマートフォンがブラウザに相当し、FIRERPAがWebDriverに相当し、FIRERPAのPythonクライアントライブラリであるlamdaがSeleniumに相当します。そして、いずれもユーザー操作をシミュレートし、テスト、データ収集、またはタスクの自動実行を実現するという目標は共通しています。どちらもスクリプトにより駆動し、要素の特定、クリック、スクリーンショット、判定などの操作を行います。このように考えると、両者はかなりよく似ています。

しかし、異なる点もあります。第一に、モバイル自動化ではスマートフォンとパソコンの両方が必要ですが、Web自動化はご自身のパソコン上で完結します。第二に、使用するツールセットが異なります。WebではSelenium、Puppeteer、Playwrightなどが一般的ですが、モバイルでは通常FIRERPA、AutoJS、Appium、uiautomator2などが使われます。

Webでは、要素の位置特定は主にHTMLのDOM構造に基づくXPathやCSSセレクターを用い、要素の階層は比較的直感的です。一方、モバイルでは一般的にセレクターを使います。もちろん、Androidアプリの画面もXMLレイアウトを使用しているため、XML経由でXPath選択を行うことも可能です。通常、Web自動化では互換性の問題にあまり悩まされません。ほとんどの場合、ブラウザのバージョンを固定し、起動時の解像度を指定することでデバイス差分に起因する互換性の問題を解決できます。しかし、Androidの場合は、ブランド、モデル、画面サイズ、システムバージョンなどの違いが自動化コードの互換性に影響を与える可能性があります。とはいえ、影響は限定的ですので、あまり心配する必要はありません。

各種自動化ツールの違い

前述のとおり、例に挙げたAndroid向けの主要な自動化ツール間にも大きな違いがあります。まず立場を明らかにします。FIRERPAは、すべての自動化ツールの中で最も安定しており、機能が最も充実し、最も強力で、プロジェクト管理やアプリケーションにも最適です。

注釈

当社の立場は偏見ではなく、6年にわたる絶え間ない探求と改善に基づいています。皆様がこれから進む道、陥るかもしれない落とし穴のほとんどを、私たちはすでに経験してきました。

:

一般的なAutoJSとその派生製品は「自己完結型」に分類され、デバイスにAPKをインストールし、JavaScriptでスクリプトを記述して操作を行います。AutoJSは通常、自動操作のみを実行でき、初心者や趣味での利用に適しており、参入障壁は低いです。しかし、その設計自体は大規模なスクリプト制御、管理、更新には向いておらず、非中央集権的かつ無管理の状態にあり、精密な大規模制御は不可能です。

:

自動化の基本フロー

通常、最初に方針を事前検討する必要があります。単純な自動化だけを行うのか、あるいは自動化と同時にアプリの実行データを取得するのか、という点です。データ取得の手法としては、大きく二つあります。一つは、中間者(MITM)によるHTTP/S通信の傍受、もう一つはフック(Hook)によるデータ取得です。中間者方式は比較的簡単で、一般利用に適しますが、一部のアプリでは無効な場合があります。フック方式は多くのリバースエンジニアリング知識を必要とし、習得が難しく初心者には不向きで、境界的なケース向けです。

中間者データ取得

中間者方式は比較的簡単です。ドキュメントから 中間者証明書のインストールプロキシの設定 に関する内容を探し、mitmproxyと組み合わせるだけで実現できます。不明な場合は、公式のstartmitm.pyスクリプトも参考にしてください。そこにはすべてのロジックが記述されており、そのままコピーまたは再利用できます。

フックデータ取得

フック方式は、初級以上のリバースエンジニアリング能力が必要です。これまでに経験がない場合は、ひとまず後回しにしても構いません。概して、フック方式はFridaスクリプトを作成し、関連する関数呼び出しをフックして、引数や戻り値を取得して報告し、アプリに注入するといった流れをとります。Fridaによるデータレポート の章で、簡単なデモと使い方をご確認いただけます。

自動化コード

自動化コードも不可欠です。なぜなら、自動化を通じて関連するロジックをトリガーする必要があるからです。自動化コードを作成する際の典型的な流れは次のとおりです。まず、FIRERPAのリモートデスクトップを開くと、以下のような画面が表示されます。

リモートデスクトップ

次に、操作したいアプリを開き、リモートデスクトップ右上の「目のアイコン」をクリックすると、以下のような画面が表示されます。ここで操作したい要素を選択し、クリックすると要素の情報が確認できます。

豆知識

もちろんコードで開くことも可能です。これらはすべて後ほど説明します。

要素の選択

右側に、textやresourceIdなどの要素情報が表示されます。この要素をクリックしたいと仮定すると、以下のようなコードを書きます。これは「textが'同意'である要素をクリックする」という意味です。

d(text="同意").click()

注釈

これはあくまで一例です。セレクターの書き方は多数あり、ここでは最もシンプルな方法を紹介しています。

さて、最もシンプルな書き方は理解できましたね。ここで、if/elseなどの制御ロジックとexistsなどのインターフェースを組み合わせれば、一連の自動化フローを構築できます。ほら、それほど難しくはないでしょう。

画面レイアウトのインスペクション

通常、自動化コードを作成する際には、画面レイアウトのインスペクションが欠かせません。これはセレクターの条件を取得する唯一の手段です。まず、ブラウザでデバイスのリモートデスクトップを開きます。次に、リモートデスクトップ右上の目のアイコンをクリックしてレイアウトインスペクションに入ります。左側の画面上の点線枠をクリックすると、対応する要素情報が表示され、その属性をセレクターのパラメータとして使用できます。目のアイコンをもう一度クリックすると、レイアウトインスペクションが閉じます。なお、レイアウトインスペクションは画面の変化に合わせて自動的には更新されません。インスペクションに入った瞬間の画面レイアウトのまま固定されます。更新するには、ショートカットキー Ctrl + R を手動で押してください。

要素のインスペクション

ヒント

レイアウトインスペクション画面でTabキーを押すと、すべての要素を順番に表示して確認することもできます。

画面セレクター

画面セレクター(Selector)はAndroidの要素を操作するために使用します。XPathルールのようなものだと理解してください。メカニズムは異なりますが、用途は似ています。FIRERPAでは、セレクタークラスは Selector ですが、ほとんどの場合、それを直接意識する必要はありません。上記ですでにその使い方をご覧いただきました。完全なSelectorは、以下のようなオプションパラメータで構成されます。

マッチタイプ説明
textテキスト完全一致
textContainsテキスト部分一致
textStartsWithテキスト前方一致
classNameクラス名一致
description説明完全一致
descriptionContains説明部分一致
descriptionStartsWith説明前方一致
clickableクリック可能
longClickable長押し可能
scrollableスクロール可能
resourceIdリソースID一致

多くの場合、resourceId、text、description、textContainsなどがパラメータとして使用されます。要素に正常なresourceIdが存在する場合は、それを優先的にSelectorとして使うべきです。たとえば d(resourceId="com.xxx:id/mobile_signal") のようにします。そうでなければ d(text="クリックして入る") や、もう少し曖昧な d(textContains="クリック") などが使えます。descriptionもtextと同様ですが、利用機会は少なめです。

ヒント

Selectorは、先述した画面レイアウトインスペクション機能によって得られた主要なパラメータを組み合わせて作成します。

画面座標の定義

自動化の過程では、正確な座標や領域の座標を使って操作しなければならない場面に遭遇することがあります。座標の概念にまだ慣れていない方もいらっしゃるかもしれませんので、ここでAndroidの画面座標の知識を紹介します。画面は画像と同様に解像度を持ちます。Androidの画面では、横画面、縦画面、自動回転に関わらず、常に左上隅を原点(0,0)とし、右方向をX軸正方向、下方向をY軸正方向とする座標系が形成されます。図を参照してください。

画面座標

上図からわかるように、画面左上隅の座標は(0,0)、右上隅は(1080,0)、左下隅は(0,1920)、右下隅は(1080,1920)です。この情報に基づいて、画面上の任意の点の座標を換算できます。

注釈

画面の本来の向きが縦でも横でも、あるいは自動回転でも、現在の向きの左上隅を常に原点とします。

画面上の点

FIRERPAでは、クリックやスクリーンショットなどの操作で、領域や座標の情報を指定する必要がある場合があります。一般的な座標点については、以下のような定義を使います。これは画面上の座標(100,100)の点を表します。

Point(x=100, y=100)

領域の定義

領域とは、画面上の矩形領域のことで、その定義はやや複雑ですので注意深く読んでください。画面上の領域を Bound で表し、topleftbottomright の4つのパラメータを指定します。混乱するかもしれませんが、しっかり理解してください。top は矩形の上端から画面上端までのピクセル距離、left は矩形の左端から画面左端までのピクセル距離、right は矩形の右端から画面左端までの距離、bottom は矩形の下端から画面上端までの距離です。つまり、すべての距離は画面左上隅の原点を基準としたX/Y軸方向の距離です。理解を助けるため、下図を参照してください。スマートフォンの画面は1080x1920のままで、現在は縦向きです。

画面領域

画面が4等分されていると仮定し、図に示された左上と右下の2つの領域の定義を求めてみましょう。ルールに従うと、領域1:矩形上端から画面上端までの距離は0ピクセル、左端から画面左端までは0ピクセル、下端から画面上端までは960ピクセル(1920÷2)、右端から画面左端までは540ピクセル(1080÷2)。したがって、その定義は

Bound(top=0, left=0, right=540, bottom=960)

となります。

同様に、領域2:矩形上端から画面上端までは960ピクセル、左端から画面左端までは540ピクセル、右端から画面左端までは1080ピクセル、下端から画面上端までは1920ピクセル。その定義は

Bound(top=960, left=540, right=1080, bottom=1920)

です。

Androidアプリのデータ

すべてのAndroidアプリは、デバイス上に専用のデータディレクトリを持っています。通常、アプリデータは /data ディレクトリ以下に保存されます。d.application("com.example").info() インターフェースを呼び出すことで、アプリのデータディレクトリを取得できます。多くの場合、cd /data/user/0/com.example.test で直接ユーザーディレクトリに移動することも可能です。/data 以外にも、一部のアプリは /sdcard/Android ディレクトリにマルチメディアなどの他のファイルを保存します。

SMSデータベースの確認

端末で受信したSMSの保存場所を確認したいというケースがあるかもしれません。これは非常に簡単で、エクステンションを作成すれば内容を直接読み取り、HTTPインターフェース経由でリアルタイムに取得することも可能です! ここでは一般的なAndroidの考え方に沿って説明しますが、状況が異なる場合はご自身で応用してください。Androidでは、SMSアプリのパッケージ名は通常 com.android.mms です。したがって、ディレクトリを /data/user/0/com.android.mms に切り替えます。以下の操作を実行すると、databases ディレクトリ以下にいくつかのデータベースがあり、その中の mmssms.db が目的のファイルであることがわかります。

 λ 10:12 /data/user/0/com.android.mms ➥ ls -la
total 82
drwx------    7 u0_a78   u0_a78        3452 Jan  2  2021 .
drwxrwx--x  381 system   system       53248 May  2 16:46 ..
drwxrws--x    3 u0_a78   u0_a78_c      3452 Jan  2  2021 cache
drwxrws--x    2 u0_a78   u0_a78_c      3452 Jan  2  2021 code_cache
drwxrwx--x    2 u0_a78   u0_a78        3452 Jan  2  2021 databases
drwxrwx--x    7 u0_a78   u0_a78       24576 Feb 26 13:43 files
drwxrwx--x    2 u0_a78   u0_a78        3452 May  4 10:12 shared_prefs
 λ 10:12 /data/user/0/com.android.mms ➥ ls -l databases/
total 504
-rw-rw----    1 u0_a78   u0_a78       24576 Jan  2  2021 dynamic_bubble
-rw-------    1 u0_a78   u0_a78           0 Jan  2  2021 dynamic_bubble-journal
-rw-rw----    1 u0_a78   u0_a78      491520 Feb 27 04:18 mmssms.db
-rw-------    1 u0_a78   u0_a78           0 Jan  2  2021 mmssms.db-journal
 λ 10:12 /data/user/0/com.android.mms ➥

読み取りは非常に簡単です。Androidの一般的なアプリのデータベースはすべてSQLiteだからです。ただし、セキュリティレベルの高いアプリではデータベースが暗号化されていることがよくあります。しかし、FIRERPAは非常に強力で、通常のSQLiteに加えて、WeChat(SqlCipher)AES-256、WeCom(企業微信)AES-128、Alibaba系SqlCrypto(AES-128)などの暗号化データベースをリアルタイムで読み取ることもサポートしています(鍵を自身で見つけることが前提です)。以下では、システムのSMS内容を読み取る簡単なデモンストレーションを行います。1つのコマンドで済みますし、エクステンションを作成して読み取ることもできます。

sqlite3 databases/mmssms.db .dump

出力は大量になるかもしれませんが、必要なデータが含まれるテーブルを素早く特定し、ご自身でSQLクエリを作成してください。この方法は98%のAndroidアプリケーションに適用可能で、残りの2%が暗号化データベースです。

暗号化データベースの確認

暗号化データベースの場合は、データベースの鍵またはその生成方法をご自身で見つける必要があります。以下では、関連アプリのデータベースの読み取り方法を簡単に紹介します。PRAGMA を用いて鍵を設定する方法のみ説明します。これが何であるかわからない場合は、まずSQLiteについて学んでください。

WeChat系 (sqlcipher)

PRAGMA cipher = "sqlcipher";
PRAGMA legacy = 1;
PRAGMA key = "database-key";

WeCom(企業微信) (wxsqlite)

PRAGMA cipher = "aes128cbc";
PRAGMA hexkey = "database-key"

Alibaba系 (sqlcrypto)

PRAGMA cipher = "sqlcrypto";
PRAGMA key = "database-key"

ヒント

注意:Androidアプリのデータベースは必ずしもdatabasesディレクトリにだけ置かれているとは限りません。

その他のデータの確認

もちろん、アプリのデータディレクトリにはデータベースだけでなく、アプリのパラメータ、設定、キャッシュ、ファイルなども含まれます。たとえばshared_prefs(XMLファイル)などです。ここでは詳細な説明はしませんので、ご自身で探索してみてください。

自動化の補助的手段

自動化業務において、すべてのアプリがセレクターでの位置特定に適しているわけではありません。ゲームなど、リアルタイムレンダリングが行われ、Androidレイヤーでのページレイアウトが存在しない画面もあります。このようなアプリでは、OCRや画像マッチングを用いて判別するしかありません。文字認識 および 画像マッチング の章を参照し、具体的なインターフェースと使い方をご確認ください。