Пользовательские скрипты
Встро енные скрипты закрывают типовые сценарии. Когда нужно что-то другое — шаг в ином порядке, экран, которого они не касаются, или приложение, отличное от 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_BASE | URL сервера, например http://127.0.0.1:50809 |
TIKMATRIX_SESSION_ID | Аренда, уже удерживаемая для вас |
TIKMATRIX_SERIAL | Устройство, на которое отправлена задача |
TIKMATRIX_PACKAGE | Определённый пакет приложения |
TIKMATRIX_PLATFORM | tiktok, 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:
| Исключение | Когда |
|---|---|
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= | Текущее дерево интерфейса в 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.
Задача помечена неуспешной, хотя на телефоне всё в порядке Прочитайте журнал задачи. Ненулевой выход — включая необработанное исключение в конце успешного прогона — помечает задачу неуспешной, даже если сама автоматизация отработала.
Что дальше
- Обзор локального API — аутентификация и формат ответа
- API управления задачами — создание, запрос, повтор и остановка задач
- ИИ-ассистент — пусть модель составит и зарегистрирует скрипт за вас
- SDK и примеры на GitHub