Перейти к основному содержимому

Пользовательские скрипты

Встроенные скрипты закрывают типовые сценарии. Когда нужно что-то другое — шаг в ином порядке, экран, которого они не касаются, или приложение, отличное от TikTok и Instagram, — вы можете написать это сами на любом языке, а TikMatrix передаст вам телефон.

Требования

Требование к лицензии

Пользовательские скрипты доступны на планах Pro, Team и Business. На плане Starter доступа нет.

Количество устройств в вашем плане — это одновременно и лимит параллельности: план Pro (20 устройств) может одновременно управлять 20 телефонами, будь то встроенные задачи, пользовательские скрипты или их смесь.

Два способа запуска

Автономный

Программу запускаете вы сами. 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 берёт устройство в аренду до старта вашей программы и передаёт идентификатор аренды через окружение.

from tikmatrix import TikMatrix

with TikMatrix.from_env() as d: # устройство уже арендовано
d.click(text="Log in")
print("done") # эта строка попадёт в журнал задачи

Подходит для всего, что нужно запускать регулярно, по расписанию или на многих устройствах.

Что выбрать

АвтономныйУправляемый
Кто запускаетВыОчередь задач TikMatrix
Аренда устройстваБерёте самиУже удерживается на старте программы
Повторы, расписания, журналРеализуете самиУже есть
Запуск на многих устройствахПишете цикл самиПо задаче на устройство, параллельно
Для чего лучшеИсследование, краулеры, разовые задачиВсё, что нужно повторять

Можно начать с автономного режима, отладить сценарий, а затем зарегистрировать тот же файл как управляемый скрипт — меняется только строка TikMatrix.from_env().

Начало работы

1. Установите клиентскую библиотеку

pip install requests

Затем скопируйте tikmatrix.py из каталога SDK рядом со своим скриптом. Библиотека — один файл без других зависимостей.

Использовать её необязательно: API — это обычный JSON поверх HTTP, сырые эндпоинты описаны ниже.

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-объект, добавляемый в окружение программы
ВключёнОтключить скрипт, не удаляя его. Отключённый скрипт нельзя отправить в работу

Затем нажмите ▶ в строке скрипта и выберите устройства — точно как для встроенного скрипта.

Пусть его напишет ассистент

ИИ-ассистент может составить пользовательский скрипт по описанию на обычном языке и зарегистрировать его за один шаг. Весь файл он показывает вам до того, как что-либо будет записано на диск.

Аренда устройств

Телефоном одновременно может управлять только что-то одно. Аренда сообщает TikMatrix, что устройство занято, поэтому:

  • очередь задач не отправит задачу на тот же экран, и
  • ваши JSON-RPC вызовы сообщают о состоянии агента ровно так же, как встроенный скрипт, — сторожевой таймер видит занятый агент, а не молчащий.

Аренда также занимает один слот устройства из вашего плана.

Аренда истекает — по умолчанию через 120 секунд, максимум 600. Python-библиотека продлевает её в фоновом потоке и освобождает при выходе из блока with, поэтому упавший скрипт отдаёт устройство за секунды, а не удерживает его до перезапуска приложения. Если вы обращаетесь к API напрямую, отправляйте heartbeat самостоятельно.

Все действующие аренды видны — и принудительно снимаются — в разделе Настройки → Developer API → Активные сессии устройств.

Режимы платформы

Зарегистрированный скрипт объявляет, на что он нацелен:

Generic — устройство передаётся как есть. Приложение не запускается, аккаунты не переключаются, метод ввода не проверяется, и после завершения ничего не закрывается. Используйте для автоматизации всего, что не является TikTok или Instagram.

TikTok / Instagram — приложение открывается и аккаунт переключается до старта вашей программы, а по завершении приложение закрывается — так же, как для встроенного скрипта. TIKMATRIX_PACKAGE сообщает, какой пакет был выбран. Используйте, чтобы добавить шаг, которого нет во встроенных скриптах.

Переменные окружения

Управляемый скрипт получает:

ПеременнаяЗначение
TIKMATRIX_API_BASEURL сервера, например http://127.0.0.1:50809
TIKMATRIX_SESSION_IDАренда, уже удерживаемая для вас
TIKMATRIX_SERIALУстройство, на которое отправлена задача
TIKMATRIX_PACKAGEОпределённый пакет приложения
TIKMATRIX_PLATFORMtiktok, instagram или generic

TikMatrix.from_env() читает всё это за вас.

Автономные скрипты не получают ничего из этого — берите устройство в аренду явно.

Всё, что вы указали в Дополнительных переменных окружения, накладывается сверху: это обычный способ передать одному зарегистрированному скрипту настройки конкретного запуска, не редактируя файл.

Справочник 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()Текущее дерево интерфейса в 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)Ввод в поле в фокусе через встроенный быстрый метод ввода
d.jsonrpc(method, params=None, timeout=10)Любой метод UIAutomator2
d.adb(*args, timeout_ms=None)Выполнить ADB-команду
d.release()Освободить аренду. with делает это за вас

find ищет по выгруженному дереву интерфейса, поэтому, когда селектор промахивается, можно вызвать print(d.hierarchy()) и посмотреть, по чему именно шёл поиск. Инспектор элементов в представлении устройства показывает то же дерево визуально — обычно это самый быстрый способ найти resource-id.

input_text требует ADB

Он отправляет широковещательное сообщение встроенному методу ввода через adb shell. Включите доступ к ADB перед использованием, иначе будет 403.

Ошибки

Библиотека выбрасывает два исключения, оба наследники 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/jsonrpcВызвать метод UIAutomator2
POST/api/v1/rpc/adbВыполнить ADB-команду
GET/api/v1/rpc/hierarchy?serial=Текущее дерево интерфейса в 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-запросы, — контракт управляемого режима сводится к «прочитать три переменные окружения и выйти с кодом 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 — идентификатор зарегистрированного вами скрипта.

Доступ к ADB

/api/v1/rpc/adb даёт вашим скриптам шелл на устройстве — он нужен для загрузки медиа, установки APK и изменения системных настроек. Поскольку это полноценный шелл на эндпоинте без API-ключа, он поставляется выключенным. Включите его в Настройки → Developer API → Разрешить команды ADB, когда у вас появится скрипт, которому он нужен; UI-автоматизация через /rpc/jsonrpc работает и без него.

Пока он выключен, /api/v1/rpc/adb отвечает 403, а остальной API продолжает работать. Каждая выполненная скриптом ADB-команда записывается в файл журнала.

Как писать скрипты, которые продолжают работать

  • Ждите экран, а не спите фиксированное время. d.wait_for(...) вернётся, как только элемент появится; фиксированный sleep либо медленнее, чем нужно, либо слишком короток в неудачный день.
  • Проверяйте перед нажатием. d.exists(...) на диалоге согласия или подсказке «не сейчас» стоит одной выгрузки дерева и спасает запуск, который иначе нажал бы в пустоту.
  • Печатайте, что сделали. В управляемом режиме stdout — это журнал задачи, и он единственная запись о запуске, за которым никто не следил.
  • Сделайте повторный запуск безопасным. Повтор запускает всю программу заново, поэтому скрипт, который публикует, должен проверять, не опубликовал ли он уже, а не считать, что стартует с нуля.
  • Один скрипт — одна задача. Параллельность считается по устройствам, поэтому десять небольших задач на десяти телефонах завершатся намного раньше, чем один скрипт, обходящий десять телефонов в цикле.

Замечания и ограничения

  • Команда выполняется напрямую, не через шелл, поэтому && и | считаются аргументами, а не операторами. Зарегистрируйте 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. Текст сравнивается точно, поэтому обычная причина — лишний пробел или локализованная подпись; сопоставление по resource_id устойчивее, чем по text.

Задача помечена неуспешной, хотя на телефоне всё в порядке Прочитайте журнал задачи. Ненулевой выход — включая необработанное исключение в конце успешного прогона — помечает задачу неуспешной, даже если сама автоматизация отработала.

Что дальше