カスタムスクリプト
組み込みスクリプトは一般的なフローを網羅しています。それでは足りないとき——順序を変えたい、組み込みが触れない画面を操作したい、TikTok や Instagram 以外のアプリを動かしたい——は、好きな言語で自分で書き、TikMatrix に端末を貸してもらえます。
必要条件
カスタムスクリプトには Pro / Team / Business プランが必要です。 Starter プランでは利用できません。
プランのデバイス数はそのまま同時実行数の上限になります。Pro プラン(20 台)なら、組み込みタスク・カスタムスクリプト・その両方のいずれであっても、同時に 20 台まで動かせます。
実行方法は 2 通り
スタンドアロン
プログラムはあなたが起動します。TikMatrix は端末を貸すだけです。
from tikmatrix import TikMatrix
client = TikMatrix()
for device in client.devices():
if device["busy"]:
continue
with client.device(device["serial"], label="my crawler") as d:
d.press("home")
print(d.info())
単発の処理、データ収集、自前のスケジューラから走らせたいものに向いています。
マネージド
プログラムを TikMatrix に登録すると、通常のタスクと同じ扱いになります。タスクキュー、プランごとの同時実行制御、自動リトライ、タスクログ、スケジュールテンプレートがそのまま使えます。TikMatrix はプログラムを起動する前に端末をリースし、リース ID を環境変数で渡します。
from tikmatrix import TikMatrix
with TikMatrix.from_env() as d: # 端末はリース済み
d.click(text="Log in")
print("done") # この行はタスクログに残る
繰り返し実行したいもの、定期実行したいもの、多数の端末で走らせたいものに向いています。
どちらを選ぶか
| スタンドアロン | マネージド | |
|---|---|---|
| 起動する主体 | あなた | TikMatrix のタスクキュー |
| 端末リース | 自分で取得 | 起動時点で取得済み |
| リトライ・スケジュール・タスクログ | 自分で作る | 標準で付いてくる |
| 多数の端末で実行 | 自分でループを書く | 端末ごとに 1 タスクを並列投入 |
| 向いている用途 | 試行錯誤、クローラ、単発処理 | 繰り返したいものすべて |
まずスタンドアロンでフローを固め、同じファイルをマネージドスクリプトとして登録する、という進め方ができます。変わるのは TikMatrix.from_env() の 1 行だけです。
はじめる
1. クライアントライブラリを入れる
pip install requests
そのうえで SDK ディレクトリの tikmatrix.py をスクリプトの隣にコピーします。ライブラリは単一ファイルで、他の依存はありません。
使わなくても構いません。API は HTTP 上のただの JSON で、生のエンドポイントは下に記載しています。
2. スクリプトを書く
from tikmatrix import TikMatrix
client = TikMatrix()
with client.device("192.168.1.5:5555") as d:
d.press("home")
d.adb("shell", "am", "start", "-a", "android.settings.SETTINGS")
d.wait_for(text="Settings", timeout=15)
d.screenshot("settings.png")
TikMatrix を開いた状態で、端末を接続して実行します。デバイス情報の辞書が表示されれば配線は完了です。
3. 登録する(マネージドのみ)
デバイス → カスタムスクリプト → スクリプトを追加 を開きます。
| 項目 | 意味 |
|---|---|
| 名前 | スクリプト一覧とタスクログに表示されます |
| コマンド | 実行するプログラム行。例: python C:/scripts/my_flow.py |
| 作業ディレクトリ | 任意。プログラムの起動位置 |
| プラットフォーム | 下のプラットフォームモードを参照 |
| タイムアウト | 何秒でスクリプトを強制終了しタスクを失敗扱いにするか。既定は 1800 |
| 追加の環境変数 | 任意の JSON オブジェクト。プログラムの環境変数にマージされます |
| 有効 | 削除せずに停止できます。無効なスクリプトは投入できません |
あとはスクリプト行の ▶ を押して端末を選ぶだけで、組み込みスクリプトとまったく同じです。
AI アシスタントは、普通の言葉での説明からカスタムスクリプトを起草し、登録まで一度に行えます。ディスクに何かが書き込まれる前に、ファイル全体を必ず見せてくれます。
デバイスリース
1 台の端末を同時に操作できるのは 1 つだけです。リースを取ると TikMatrix は「その端末は使用中」と認識するため、
- タスクキューが同じ画面にタスクを投入しなくなり、
- あなたの JSON-RPC 呼び出しは組み込みスクリプトと同じようにエージェントの健全性を報告するため、ウォッチドッグからは「沈黙したエージェント」ではなく「忙しいエージェント」に見えます。
リースはプランのデバイス枠も 1 つ消費します。
リースは期限切れになります——既定 120 秒、最大 600 秒。Python ライブラリはバックグラウンドスレッドで自動更新し、with ブロックを抜けるときに解放するので、スクリプトがクラッシュしても数秒で端末が解放されます(アプリを再起動するまで握りっぱなし、にはなりません)。API を直接叩く場合はハートビートを自分で送ってください。
生きているリースの一覧と強制解放は 設定 → Developer API → アクティブなデバイスセッション で行えます。
プラットフォームモード
登録済みスクリプトは対象を宣言します。
Generic — 端末はそのまま渡されます。アプリは起動されず、アカウント切り替えも入力方式チェックも行われず、終了後に何かを閉じることもありません。TikMatrix が自動化できないアプリを自動化するときに使います。
TikTok / Instagram / Threads — プログラム開始前にアプリを開いて正しいアカウントが有効になるようにし、終了時にアプリを閉じます。組み込みスクリプトとまったく同じ扱いです。解決されたパッケージは TIKMATRIX_PACKAGE で分かります。組み込みスクリプトにない手順を足したいときに使います。
Threads では Settings → Switch accounts シートを通じてアカウントが切り替わり、その後プロフィール ページ上のハンドルが読み取られます。デバイスにサインインしていないアカウントを指定したタスクは、現在アクティブなアカウントとして実行されるのではなく、失敗します。
環境変数
マネージドスクリプトが受け取るもの:
| 変数 | 意味 |
|---|---|
TIKMATRIX_API_BASE | サーバー URL。例: http://127.0.0.1:50809 |
TIKMATRIX_SESSION_ID | すでに取得済みのリース |
TIKMATRIX_SERIAL | このタスクが投入された端末 |
TIKMATRIX_PACKAGE | 解決されたアプリのパッケージ名 |
TIKMATRIX_PLATFORM | tiktok、instagram、threads、または generic |
TikMatrix.from_env() がこれらをまとめて読み取ります。
スタンドアロンスクリプトにはこれらは渡されません。端末は明示的にリースしてください。
追加の環境変数に入れた内容は上書きマージされます。1 つの登録済みスクリプトに、ファイルを書き換えずに実行ごとの設定を渡す一般的な方法です。
Python ライブラリリファレンス
TikMatrix — 接続
| 呼び出し | 内容 |
|---|---|
TikMatrix(base_url=None, timeout=30.0) | 接続。TIKMATRIX_API_BASE、次に http://127.0.0.1:50809 にフォールバック |
client.devices() | オンライン端末。各要素に serial / real_serial / busy |
client.sessions() | 生きているリース全件(自プロセス以外のものも含む) |
client.device(serial, label=..., ttl_secs=120) | 端末をリースして Device を返す |
TikMatrix.from_env() | マネージドスクリプト起動時の端末を引き継ぐ |
Device — 端末
| 呼び出し | 内容 |
|---|---|
d.info() | UIAutomator2 のデバイス情報 |
d.window_size() | (幅, 高さ) |
d.screenshot(path=None) | PNG バイト列。path を指定すると保存 |
d.hierarchy() | 現在の UI ツリー(XML) |
d.find(text=, resource_id=, description=, class_name=) | 一致ノード。各要素に bounds と center |
d.exists(**criteria) | 一致するものがあるか |
d.wait_for(timeout=10.0, interval=1.0, **criteria) | 出現するまで待って返す |
d.click(timeout=10.0, **criteria) | 要素を待ってから中心をタップ |
d.click_xy(x, y) | 座標をタップ |
d.swipe(sx, sy, ex, ey, steps=20) | スワイプ |
d.press(key) | back / home / recent / enter など |
d.input_text(text) | 同梱の高速入力 IME でフォーカス中の入力欄に入力 |
d.jsonrpc(method, params=None, timeout=10) | 任意の UIAutomator2 メソッド |
d.adb(*args, timeout_ms=None) | ADB コマンドを実行 |
d.release() | リースを解放。with なら自動 |
find はダンプした UI ツリーに対して照合するので、セレクタが外れたときは print(d.hierarchy()) で「実際に何を検索したか」を確認できます。デバイス画面の要素インスペクタは同じツリーを視覚的に表示するので、resource-id を探すには通常これが最速です。
input_text には ADB が必要同梱 IME へのブロードキャストを adb shell 経由で送るためです。使う前に ADB アクセスを有効にしてください。無効のままだと 403 になります。
エラー
ライブラリが送出する例外は 2 つで、どちらも RuntimeError のサブクラスです。
| 例外 | 発生条件 |
|---|---|
DeviceBusyError | HTTP 409 — 端末が既にリース済み、またはプランに空きデバイス枠がない |
TikMatrixError | それ以外すべて。プラン不足、リース期限切れ、ADB 無効、セレクタが一度も一致しなかった等 |
from tikmatrix import TikMatrix, TikMatrixError, DeviceBusyError
client = TikMatrix()
try:
with client.device("192.168.1.5:5555") as d:
d.click(text="Log in", timeout=20)
except DeviceBusyError:
print("その端末は誰かが使用中です — 別の端末にしてください")
except TikMatrixError as exc:
print("失敗:", exc)
マネージドスクリプトでは、例外をそのまま外に投げるのが正解であることが多いです。非ゼロ終了でタスクが失敗扱いになり、トレースバックがタスクログに残ります。
HTTP エンドポイント
デバイス操作には、生きているリースを指す x-session-id ヘッダーが必要です。API キーはありません。ローカル API の他の部分と同様、これらのエンドポイントは認証を行わず、ネットワーク上でこのマシンに到達できること自体がアクセス制御です。CORS ヘッダーを一切返さないので、ブラウザのページからではなくプログラム(curl、Python、任意のサーバーサイドコード)から呼び出してください。
| メソッド | パス | 用途 |
|---|---|---|
GET | /api/v1/rpc/devices | オンライン端末と使用中かどうかの一覧 |
POST | /api/v1/rpc/session | 端末をリース → session_id |
POST | /api/v1/rpc/session/{id}/heartbeat | リースを延長 |
DELETE | /api/v1/rpc/session/{id} | リースを解放 |
GET | /api/v1/rpc/session | 生きているリースの一覧 |
POST | /api/v1/rpc/jsonrpc | UIAutomator2 メソッドを呼ぶ |
POST | /api/v1/rpc/adb | ADB コマンドを実行 |
GET | /api/v1/rpc/hierarchy?serial= | 現在の UI ツリー(XML) |
GET | /api/v1/rpc/screenshot?serial= | 現在の画面(PNG) |
JSON レスポンスはローカル API 共通のラッパー {"code": 0, "message": "success", "data": ...} を使い、失敗時は code が非ゼロになります。hierarchy と screenshot は生のボディを返します。
例
# 端末をリース
curl -X POST http://127.0.0.1:50809/api/v1/rpc/session \
-H "Content-Type: application/json" \
-d '{"serial":"192.168.1.5:5555","label":"curl test","ttl_secs":120}'
# {"code":0,"message":"success","data":{"session_id":"ff3ae079-...","serial":"192.168.1.5:5555", ...}}
# 操作する
curl -X POST http://127.0.0.1:50809/api/v1/rpc/jsonrpc \
-H "x-session-id: ff3ae079-..." \
-H "Content-Type: application/json" \
-d '{"serial":"192.168.1.5:5555","method":"deviceInfo","params":[]}'
# 作業中はリースを維持
curl -X POST http://127.0.0.1:50809/api/v1/rpc/session/ff3ae079-.../heartbeat \
-H "Content-Type: application/json" \
-d '{"ttl_secs":120}'
# 返却する
curl -X DELETE http://127.0.0.1:50809/api/v1/rpc/session/ff3ae079-...
エラー
| ステータス | 意味 |
|---|---|
| 403 | プランが Pro 未満、リースなし、リース期限切れ、または ADB アクセスが無効 |
| 409 | 端末が既にリース済み、またはプランに空きデバイス枠がない |
他の言語で書く
ここに Python 固有のものは何もありません。HTTP リクエストを送れる処理系ならどれでも使えます。マネージドモードの約束事は「環境変数を 3 つ読み、成功したら 0 で終了する」だけです。
// my_flow.js — 登録コマンド: node C:/scripts/my_flow.js
const base = process.env.TIKMATRIX_API_BASE || "http://127.0.0.1:50809";
const serial = process.env.TIKMATRIX_SERIAL;
const session = process.env.TIKMATRIX_SESSION_ID;
async function jsonrpc(method, params = []) {
const res = await fetch(`${base}/api/v1/rpc/jsonrpc`, {
method: "POST",
headers: { "content-type": "application/json", "x-session-id": session },
body: JSON.stringify({ serial, method, params }),
});
const body = await res.json();
if (!res.ok || body.code !== 0) throw new Error(body.message || res.statusText);
return body.data;
}
console.log(await jsonrpc("deviceInfo"));
インタプリタが PATH にない場合は、コマンドにフルパスを書きます。例: C:/Program Files/nodejs/node.exe C:/scripts/my_flow.js
API からカスタムスクリプトを起動する
登録済みスクリプトはタスク管理 API からも起動できます。あるスクリプトが後続の作業をキューに積む、といった使い方が可能です。
curl -X POST http://127.0.0.1:50809/api/v1/task \
-H "Content-Type: application/json" \
-d '{
"serials": ["192.168.1.5:5555"],
"script_name": "custom_script",
"script_config": {
"custom_script_id": 1,
"custom_script_platform": "generic"
}
}'
custom_script_id は登録したスクリプトの ID です。
ADB アクセス
/api/v1/rpc/adb はスクリプトに端末シェルを与えます。素材のプッシュ、APK のインストール、システム設定の変更にはこれが必要です。ただし API キーのないエンドポイント上の完全なシェルであるため、既定では無効で出荷されます。必要なスクリプトができた時点で 設定 → Developer API → ADB コマンドを許可 から有効にしてください。/rpc/jsonrpc による UI 自動化は無効のままでも動きます。
無効の間、/api/v1/rpc/adb は 403 を返し、それ以外の API は通常どおり動作します。スクリプトが実行した ADB コマンドはすべてログファイルに記録されます。
壊れにくいスクリプトの書き方
- 固定時間眠らず、画面を待つ。
d.wait_for(...)は要素が現れた瞬間に返ります。固定の sleep は、必要以上に遅いか、調子の悪い日には短すぎるかのどちらかです。 - タップ前に確認する。 同意ダイアログや「後で」の類には
d.exists(...)を挟みましょう。コストはツリーのダンプ 1 回、見返りは空振りタップで壊れる実行 1 回分です。 - やったことを出力する。 マネージドモードでは stdout がタスクログであり、誰も見ていなかった実行についての唯一の記録です。
- 再実行を安全にする。 リトライはプログラム全体を最初から走らせ直します。投稿するスクリプトなら、まっさらから始まる前提ではなく「もう投稿済みか」を確認すべきです。
- 1 スクリプト 1 仕事に保つ。 同時実行は端末単位なので、10 台に小さなタスクを 10 個投げるほうが、1 つのスクリプトで 10 台をループするよりはるかに早く終わります。
注意点と制限
- コマンドはシェルを介さず直接実行されるため、
&&や|は演算子ではなく引数として扱われます。シェルの挙動が必要ならcmd /c "..."(Windows)やsh -c "..."(macOS)を登録してください。 - 空白を含むパスは引用符で囲みます:
"C:/Program Files/Python/python.exe" my_script.py - タイムアウトを超えたスクリプトは強制終了され、タスクは失敗扱いになります。
- 非ゼロ終了コードはタスクを失敗扱いにします。スクリプトが stdout / stderr に書いた内容はすべてタスクログに入ります。
- スクリプトは TikMatrix 自身と同じ権限で動きます。自分で書いたもの、または信頼できるプログラムだけを登録してください。
トラブルシューティング
API access requires Pro or higher plan(403)
このマシンのライセンスが Starter か無効です。設定 → ライセンス を確認してください。
127.0.0.1:50809 で接続拒否
TikMatrix が起動していないか、別ユーザーで動いています。サーバーはアプリが開いている間だけ存在します。
リース取得のたびに 409 端末が本当に使用中(設定 → Developer API → アクティブなデバイスセッション で確認)か、プランのデバイス枠が実行中タスクで埋まっています。
長い処理の途中でリースが切れる
既定 TTL は 120 秒で、ライブラリはバックグラウンドで更新します。つまりこれは、スクリプトがメインスレッドを TTL より長くブロックしたということです。ttl_secs を上げる(最大 600)か、重い処理をそのスレッドから外してください。
d.adb(...) が 403 になる
ADB アクセスが無効です。設定 → Developer API → ADB コマンドを許可 で有効にしてください。
セレクタが一度も一致しない
print(d.hierarchy()) で find が実際に検索したツリーを確認できます。テキストは完全一致なので、末尾の空白や画面のローカライズが原因であることが多いです。text より resource_id で照合するほうが安定します。
タスクは失敗なのに端末は正常に見える タスクログを読んでください。非ゼロ終了は——処理自体は成功した後に投げられた未捕捉例外であっても——タスクを失敗扱いにします。
次のステップ
- ローカル API 概要 — 認証とレスポンス形式
- タスク管理 API — タスクの作成・照会・リトライ・停止
- AI アシスタント — モデルにスクリプトを起草・登録させる
- GitHub 上の SDK とサンプル