メインコンテンツまでスキップ

カスタムスクリプト

組み込みスクリプトは一般的なフローを網羅しています。それでは足りないとき——順序を変えたい、組み込みが触れない画面を操作したい、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 アシスタントに書かせる

AI アシスタントは、普通の言葉での説明からカスタムスクリプトを起草し、登録まで一度に行えます。ディスクに何かが書き込まれる前に、ファイル全体を必ず見せてくれます。

デバイスリース

1 台の端末を同時に操作できるのは 1 つだけです。リースを取ると TikMatrix は「その端末は使用中」と認識するため、

  • タスクキューが同じ画面にタスクを投入しなくなり、
  • あなたの JSON-RPC 呼び出しは組み込みスクリプトと同じようにエージェントの健全性を報告するため、ウォッチドッグからは「沈黙したエージェント」ではなく「忙しいエージェント」に見えます。

リースはプランのデバイス枠も 1 つ消費します。

リースは期限切れになります——既定 120 秒、最大 600 秒。Python ライブラリはバックグラウンドスレッドで自動更新し、with ブロックを抜けるときに解放するので、スクリプトがクラッシュしても数秒で端末が解放されます(アプリを再起動するまで握りっぱなし、にはなりません)。API を直接叩く場合はハートビートを自分で送ってください。

生きているリースの一覧と強制解放は 設定 → Developer API → アクティブなデバイスセッション で行えます。

プラットフォームモード

登録済みスクリプトは対象を宣言します。

Generic — 端末はそのまま渡されます。アプリは起動されず、アカウント切り替えも入力方式チェックも行われず、終了後に何かを閉じることもありません。TikTok / Instagram 以外を自動化するときに使います。

TikTok / Instagram — プログラム開始前にアプリを開いてアカウントを切り替え、終了時にアプリを閉じます。組み込みスクリプトとまったく同じ扱いです。解決されたパッケージは TIKMATRIX_PACKAGE で分かります。組み込みスクリプトにない手順を足したいときに使います。

環境変数

マネージドスクリプトが受け取るもの:

変数意味
TIKMATRIX_API_BASEサーバー URL。例: http://127.0.0.1:50809
TIKMATRIX_SESSION_IDすでに取得済みのリース
TIKMATRIX_SERIALこのタスクが投入された端末
TIKMATRIX_PACKAGE解決されたアプリのパッケージ名
TIKMATRIX_PLATFORMtiktok / instagram / 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=)一致ノード。各要素に boundscenter
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 のサブクラスです。

例外発生条件
DeviceBusyErrorHTTP 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/jsonrpcUIAutomator2 メソッドを呼ぶ
POST/api/v1/rpc/adbADB コマンドを実行
GET/api/v1/rpc/hierarchy?serial=現在の UI ツリー(XML)
GET/api/v1/rpc/screenshot?serial=現在の画面(PNG)

JSON レスポンスはローカル API 共通のラッパー {"code": 0, "message": "success", "data": ...} を使い、失敗時は code が非ゼロになります。hierarchyscreenshot は生のボディを返します。

# 端末をリース
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 で照合するほうが安定します。

タスクは失敗なのに端末は正常に見える タスクログを読んでください。非ゼロ終了は——処理自体は成功した後に投げられた未捕捉例外であっても——タスクを失敗扱いにします。

次のステップ