Перейти до основного вмісту

Власні скрипти

Вбудовані скрипти охоплюють типові сценарії. Коли потрібне щось інше — крок в іншому порядку, екран, якого вони ніколи не торкаються, або застосунок, що не є 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 напряму, надсилайте сигнали життя самостійно.

Усі активні оренди можна побачити — і примусово звільнити — у Налаштування → 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, коли у вас з'явиться скрипт, якому вона потрібна; автоматизація інтерфейсу через /rpc/jsonrpc працює й без неї.

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

Як писати скрипти, що продовжують працювати

  • Чекайте на екран, а не спіть замість цього. d.wait_for(...) повертається щойно елемент з'явився; фіксована пауза або повільніша, ніж потрібно, або надто коротка в невдалий день.
  • Перевіряйте, перш ніж торкатися. 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.

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

Далі