Eigene Skripte
Die eingebauten Skripte decken die üblichen Abläufe ab. Wenn Sie etwas brauchen, das sie nicht bieten — einen Schritt in anderer Reihenfolge, einen Bildschirm, den sie nie berühren, oder eine App, die weder TikTok noch Instagram ist — können Sie es selbst in einer beliebigen Sprache schreiben und sich von TikMatrix das Telefon überlassen lassen.
Voraussetzungen
Eigene Skripte erfordern einen Pro-, Team- oder Business-Tarif. Der Starter-Tarif hat keinen Zugriff.
Die Gerätezahl Ihres Tarifs ist zugleich das Nebenläufigkeitslimit: Ein Pro-Tarif (20 Geräte) kann 20 Telefone gleichzeitig steuern — ob über eingebaute Aufgaben, eigene Skripte oder eine Mischung aus beidem.
Zwei Wege, ein Skript auszuführen
Eigenständig
Sie starten Ihr Programm selbst. TikMatrix leiht Ihnen nur die Geräte.
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())
Gut für einmalige Aufgaben, Datenerfassung und alles, was Sie aus Ihrem eigenen Scheduler heraus starten wollen.
Verwaltet
Sie registrieren das Programm in TikMatrix, und es wird zu einer Aufgabe wie jede andere. Es bekommt die Aufgabenwarteschlange, die tarifabhängige Nebenläufigkeit, automatische Wiederholungen, das Aufgabenprotokoll und Zeitplanvorlagen. TikMatrix least das Gerät, bevor es Ihr Programm startet, und übergibt die Lease-ID über die Umgebung.
from tikmatrix import TikMatrix
with TikMatrix.from_env() as d: # Gerät ist bereits geleast
d.click(text="Log in")
print("done") # diese Zeile landet im Aufgabenprotokoll
Gut für alles, was wiederholt, zeitgesteuert oder auf vielen Geräten laufen soll.
Was wählen?
| Eigenständig | Verwaltet | |
|---|---|---|
| Wer startet | Sie | Die Aufgabenwarteschlange von TikMatrix |
| Geräte-Lease | Sie holen sie | Beim Start bereits vorhanden |
| Wiederholungen, Zeitpläne, Protokoll | Selbst bauen | Enthalten |
| Ausführung auf vielen Geräten | Schleife selbst schreiben | Eine Aufgabe pro Gerät, parallel verteilt |
| Am besten für | Erkundung, Crawler, einmalige Aufgaben | Alles, was Sie wiederholen wollen |
Sie können eigenständig anfangen, während Sie den Ablauf zurechtbiegen, und dieselbe Datei dann als verwaltetes Skript registrieren — die einzige Zeile, die sich ändert, ist TikMatrix.from_env().
Erste Schritte
1. Client-Bibliothek installieren
pip install requests
Kopieren Sie dann tikmatrix.py aus dem SDK-Verzeichnis neben Ihr Skript. Die Bibliothek ist eine einzelne Datei ohne weitere Abhängigkeiten.
Sie müssen sie nicht verwenden — die API ist schlichtes JSON über HTTP, und die rohen Endpunkte sind unten dokumentiert.
2. Skript schreiben
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")
Führen Sie es bei geöffnetem TikMatrix und angeschlossenem Telefon aus. Wenn ein Wörterbuch mit Geräteinformationen ausgegeben wird, ist alles verdrahtet.
3. Registrieren (nur verwalteter Modus)
Gehen Sie zu Geräte → Eigene Skripte → Skript hinzufügen:
| Feld | Bedeutung |
|---|---|
| Name | Erscheint in der Skriptliste und im Aufgabenprotokoll |
| Befehl | Die auszuführende Programmzeile, z. B. python C:/scripts/my_flow.py |
| Arbeitsverzeichnis | Optional. Wo das Programm startet |
| Plattform | Siehe Plattformmodi unten |
| Zeitlimit | Sekunden, bis das Skript beendet und die Aufgabe als fehlgeschlagen markiert wird. Standard 1800 |
| Zusätzliche Umgebungsvariablen | Optionales JSON-Objekt, das in die Programmumgebung eingemischt wird |
| Aktiviert | Ein Skript abschalten, ohne es zu löschen. Ein deaktiviertes Skript kann nicht verteilt werden |
Drücken Sie dann ▶ in der Skriptzeile und wählen Sie Ihre Geräte — genau wie bei einem eingebauten Skript.
Der KI-Assistent kann aus einer Beschreibung in normaler Sprache ein eigenes Skript entwerfen und es in einem Schritt registrieren. Er zeigt Ihnen die ganze Datei, bevor irgendetwas auf die Festplatte geschrieben wird.
Geräte-Leases
Ein Telefon kann immer nur von einer Sache gesteuert werden. Es zu leasen sagt TikMatrix, dass das Gerät belegt ist, sodass:
- die Aufgabenwarteschlange keine Aufgabe auf denselben Bildschirm schickt, und
- Ihre JSON-RPC-Aufrufe den Agent-Zustand genauso melden wie ein eingebautes Skript, sodass der Watchdog einen beschäftigten statt eines stummen Agents sieht.
Eine Lease belegt außerdem einen Geräteplatz Ihres Tarifs.
Leases laufen ab — standardmäßig nach 120 Sekunden, maximal nach 600. Die Python-Bibliothek erneuert Ihre in einem Hintergrund-Thread und gibt sie beim Verlassen des with-Blocks frei, sodass ein abgestürztes Skript sein Gerät binnen Sekunden freigibt, statt es bis zum Neustart der App zu blockieren. Wenn Sie die API direkt ansprechen, müssen Sie die Heartbeats selbst senden.
Alle aktiven Leases sehen — und zwangsweise freigeben — können Sie unter Einstellungen → Developer API → Aktive Gerätesitzungen.
Plattformmodi
Ein registriertes Skript gibt an, worauf es zielt:
Generic — das Gerät wird unangetastet übergeben. Es wird keine App gestartet, kein Konto gewechselt, keine Eingabemethode geprüft, und hinterher wird nichts geschlossen. Verwenden Sie dies, um alles zu automatisieren, was nicht TikTok oder Instagram ist.
TikTok / Instagram — die App wird geöffnet und das Konto gewechselt, bevor Ihr Programm startet, und die App wird am Ende geschlossen — genau wie bei einem eingebauten Skript. TIKMATRIX_PACKAGE sagt Ihnen, welches Paket aufgelöst wurde. Verwenden Sie dies, um einen Schritt zu ergänzen, den die eingebauten Skripte nicht abdecken.
Umgebungsvariablen
Ein verwaltetes Skript erhält:
| Variable | Bedeutung |
|---|---|
TIKMATRIX_API_BASE | Server-URL, z. B. http://127.0.0.1:50809 |
TIKMATRIX_SESSION_ID | Die bereits für Sie gehaltene Lease |
TIKMATRIX_SERIAL | Das Gerät, an das diese Aufgabe verteilt wurde |
TIKMATRIX_PACKAGE | Aufgelöstes App-Paket |
TIKMATRIX_PLATFORM | tiktok, instagram oder generic |
TikMatrix.from_env() liest all das für Sie.
Eigenständige Skripte bekommen nichts davon — leasen Sie ein Gerät explizit.
Was Sie unter Zusätzliche Umgebungsvariablen eintragen, wird darüber gemischt. Das ist der übliche Weg, einem registrierten Skript laufabhängige Einstellungen zu geben, ohne die Datei zu ändern.
Referenz der Python-Bibliothek
TikMatrix — die Verbindung
| Aufruf | Was er tut |
|---|---|
TikMatrix(base_url=None, timeout=30.0) | Verbindet. Fällt zurück auf TIKMATRIX_API_BASE, dann http://127.0.0.1:50809 |
client.devices() | Online-Geräte, jeweils mit serial, real_serial und busy |
client.sessions() | Alle aktiven Leases, auch die anderer Prozesse |
client.device(serial, label=..., ttl_secs=120) | Least ein Gerät und liefert ein Device |
TikMatrix.from_env() | Übernimmt das Gerät, mit dem ein verwaltetes Skript gestartet wurde |
Device — das Telefon
| Aufruf | Was er tut |
|---|---|
d.info() | UIAutomator2-Geräteinformationen |
d.window_size() | (Breite, Höhe) |
d.screenshot(path=None) | PNG-Bytes, optional nach path geschrieben |
d.hierarchy() | Der aktuelle UI-Baum als XML |
d.find(text=, resource_id=, description=, class_name=) | Passende Knoten, jeweils mit bounds und center |
d.exists(**criteria) | Ob irgendetwas passt |
d.wait_for(timeout=10.0, interval=1.0, **criteria) | Wartet aufs Erscheinen und liefert es zurück |
d.click(timeout=10.0, **criteria) | Wartet auf ein Element und tippt auf dessen Mitte |
d.click_xy(x, y) | Tippt auf eine Koordinate |
d.swipe(sx, sy, ex, ey, steps=20) | Wischt |
d.press(key) | back, home, recent, enter, … |
d.input_text(text) | Tippt über die mitgelieferte Schnelleingabe ins fokussierte Feld |
d.jsonrpc(method, params=None, timeout=10) | Beliebige UIAutomator2-Methode |
d.adb(*args, timeout_ms=None) | Führt einen ADB-Befehl aus |
d.release() | Gibt die Lease frei. with erledigt das für Sie |
find sucht im ausgelesenen UI-Baum. Wenn ein Selektor danebengeht, können Sie also print(d.hierarchy()) aufrufen und genau sehen, worin gesucht wurde. Der Element-Inspektor in der Geräteansicht zeigt denselben Baum visuell — meist der schnellste Weg, eine resource-id zu finden.
input_text benötigt ADBEs sendet einen Broadcast an die mitgelieferte Eingabemethode, was über adb shell läuft. Aktivieren Sie den ADB-Zugriff, bevor Sie es verwenden, sonst schlägt es mit 403 fehl.
Fehler
Die Bibliothek wirft zwei Ausnahmen, beide Unterklassen von RuntimeError:
| Ausnahme | Wann |
|---|---|
DeviceBusyError | HTTP 409 — das Gerät ist bereits geleast, oder Ihr Tarif hat keinen freien Geräteplatz |
TikMatrixError | Alles andere: zu niedriger Tarif, abgelaufene Lease, ADB deaktiviert, Selektor hat nie gepasst |
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("dieses Telefon hat gerade jemand anderes — nehmen Sie ein anderes")
except TikMatrixError as exc:
print("fehlgeschlagen:", exc)
In einem verwalteten Skript ist es meist richtig, die Ausnahme durchzulassen: Der Exit-Code ungleich null markiert die Aufgabe als fehlgeschlagen, und der Traceback landet im Aufgabenprotokoll.
HTTP-Endpunkte
Geräteoperationen benötigen einen x-session-id-Header, der eine aktive Lease benennt. Es gibt keinen API-Schlüssel: Wie der Rest der lokalen API sind diese Endpunkte nicht authentifiziert — die Zugangskontrolle besteht darin, die Maschine im Netz überhaupt zu erreichen. Sie senden keine CORS-Header, rufen Sie sie also aus einem Programm auf (curl, Python, beliebiger serverseitiger Code) statt aus einer Seite im Browser.
| Methode | Pfad | Zweck |
|---|---|---|
GET | /api/v1/rpc/devices | Online-Geräte auflisten und ob sie belegt sind |
POST | /api/v1/rpc/session | Gerät leasen → session_id |
POST | /api/v1/rpc/session/{id}/heartbeat | Lease verlängern |
DELETE | /api/v1/rpc/session/{id} | Lease freigeben |
GET | /api/v1/rpc/session | Aktive Leases auflisten |
POST | /api/v1/rpc/jsonrpc | Eine UIAutomator2-Methode aufrufen |
POST | /api/v1/rpc/adb | Einen ADB-Befehl ausführen |
GET | /api/v1/rpc/hierarchy?serial= | Aktueller UI-Baum als XML |
GET | /api/v1/rpc/screenshot?serial= | Aktueller Bildschirm als PNG |
JSON-Antworten verwenden dieselbe Hülle wie der Rest der lokalen API — {"code": 0, "message": "success", "data": ...}, mit code ungleich null im Fehlerfall. hierarchy und screenshot liefern stattdessen den rohen Body.
Beispiel
# Gerät leasen
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", ...}}
# Steuern
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":[]}'
# Während der Arbeit am Leben halten
curl -X POST http://127.0.0.1:50809/api/v1/rpc/session/ff3ae079-.../heartbeat \
-H "Content-Type: application/json" \
-d '{"ttl_secs":120}'
# Zurückgeben
curl -X DELETE http://127.0.0.1:50809/api/v1/rpc/session/ff3ae079-...
Fehler
| Status | Bedeutung |
|---|---|
| 403 | Tarif unter Pro, keine Lease, Lease abgelaufen oder ADB-Zugriff deaktiviert |
| 409 | Gerät bereits geleast, oder Ihr Tarif hat keinen freien Geräteplatz |
In einer anderen Sprache schreiben
Nichts hiervon ist Python-spezifisch. Jede Laufzeitumgebung, die eine HTTP-Anfrage stellen kann, funktioniert — der Vertrag des verwalteten Modus lautet nur: „lies drei Umgebungsvariablen, beende mit 0 bei Erfolg".
// my_flow.js — registrieren mit: 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"));
Wenn der Interpreter nicht im PATH liegt, geben Sie den vollen Pfad im Feld Befehl an, z. B. C:/Program Files/nodejs/node.exe C:/scripts/my_flow.js.
Ein eigenes Skript über die API auslösen
Registrierte Skripte lassen sich auch über die Aufgaben-API starten, sodass ein Skript Folgearbeiten einreihen kann:
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 ist die ID des von Ihnen registrierten Skripts.
ADB-Zugriff
/api/v1/rpc/adb gibt Ihren Skripten eine Geräte-Shell — nötig zum Übertragen von Medien, Installieren von APKs und Ändern von Systemeinstellungen. Weil das eine vollwertige Shell auf einem Endpunkt ohne API-Schlüssel ist, wird sie deaktiviert ausgeliefert. Aktivieren Sie sie unter Einstellungen → Developer API → ADB-Befehle erlauben, sobald Sie ein Skript haben, das sie braucht; UI-Automatisierung über /rpc/jsonrpc funktioniert auch ohne.
Solange sie aus ist, antwortet /api/v1/rpc/adb mit 403, und der Rest der API arbeitet normal weiter. Jeder ADB-Befehl, den ein Skript ausführt, wird in Ihre Protokolldatei geschrieben.
Skripte schreiben, die weiter funktionieren
- Warten Sie auf den Bildschirm, statt dafür zu schlafen.
d.wait_for(...)kehrt zurück, sobald das Element da ist; ein festes Sleep ist entweder langsamer als nötig oder an einem schlechten Tag zu kurz. - Prüfen Sie, bevor Sie tippen. Ein
d.exists(...)auf einen Einwilligungsdialog oder ein „Nicht jetzt" kostet einen Baumabzug und rettet einen Lauf, der sonst ins Leere getippt hätte. - Geben Sie aus, was Sie getan haben. Im verwalteten Modus ist stdout das Aufgabenprotokoll und damit die einzige Spur eines Laufs, den niemand beobachtet hat.
- Machen Sie einen erneuten Lauf sicher. Eine Wiederholung führt das ganze Programm erneut aus; ein Skript, das postet, sollte prüfen, ob es bereits gepostet hat, statt anzunehmen, es beginne bei null.
- Ein Skript, eine Aufgabe. Nebenläufigkeit gilt pro Gerät: Zehn kleine Aufgaben auf zehn Telefonen sind weit schneller fertig als ein Skript, das zehn Telefone in einer Schleife abarbeitet.
Hinweise und Grenzen
- Der Befehl wird direkt ausgeführt, nicht über eine Shell;
&&und|gelten daher als Argumente, nicht als Operatoren. Registrieren Siecmd /c "..."(Windows) odersh -c "..."(macOS), wenn Sie Shell-Verhalten wollen. - Setzen Sie Pfade mit Leerzeichen in Anführungszeichen:
"C:/Program Files/Python/python.exe" my_script.py. - Ein Skript, das sein Zeitlimit überschreitet, wird beendet und die Aufgabe als fehlgeschlagen markiert.
- Ein Exit-Code ungleich null markiert die Aufgabe als fehlgeschlagen; alles, was das Skript auf stdout und stderr schreibt, landet im Aufgabenprotokoll.
- Skripte laufen mit denselben Rechten wie TikMatrix selbst. Registrieren Sie nur Programme, die Sie geschrieben haben oder denen Sie vertrauen.
Fehlerbehebung
API access requires Pro or higher plan (403)
Die Lizenz auf dieser Maschine ist Starter oder inaktiv. Prüfen Sie Einstellungen → Lizenz.
Verbindung auf 127.0.0.1:50809 abgelehnt
TikMatrix läuft nicht oder unter einem anderen Benutzer. Den Server gibt es nur, solange die App geöffnet ist.
409 bei jedem Lease-Versuch Entweder ist das Telefon tatsächlich belegt — nachsehen unter Einstellungen → Developer API → Aktive Gerätesitzungen — oder alle Geräteplätze Ihres Tarifs sind schon von laufenden Aufgaben belegt.
Die Lease läuft mitten in einem langen Schritt ab
Der Standard-TTL beträgt 120 s und die Bibliothek erneuert ihn im Hintergrund; das bedeutet also meist, dass das Skript seinen Haupt-Thread länger als den TTL blockiert hat. Erhöhen Sie ttl_secs (bis 600) oder verlagern Sie die lange Arbeit aus diesem Thread.
d.adb(...) schlägt mit 403 fehl
Der ADB-Zugriff ist aus. Schalten Sie ihn unter Einstellungen → Developer API → ADB-Befehle erlauben ein.
Ein Selektor passt nie
print(d.hierarchy()) zeigt genau den Baum, den find durchsucht hat. Text wird exakt verglichen; ein zusätzliches Leerzeichen oder eine übersetzte Beschriftung ist die übliche Ursache. Über resource_id zu suchen ist stabiler als über text.
Die Aufgabe gilt als fehlgeschlagen, das Telefon sieht aber gut aus Lesen Sie das Aufgabenprotokoll. Ein Exit-Code ungleich null — auch eine unbehandelte Ausnahme am Ende eines erfolgreichen Laufs — lässt die Aufgabe scheitern, selbst wenn die Automatisierung funktioniert hat.
Nächste Schritte
- Überblick lokale API — Authentifizierung und Antwortformat
- Aufgaben-API — Aufgaben anlegen, abfragen, wiederholen und stoppen
- KI-Assistent — ein Modell ein Skript entwerfen und registrieren lassen
- SDK und Beispiele auf GitHub