Chuyển tới nội dung chính

Script tùy chỉnh

Các script tích hợp đã bao quát những luồng thông dụng. Khi bạn cần thứ chúng không có — một bước theo thứ tự khác, một màn hình chúng không bao giờ chạm tới, hoặc một ứng dụng không phải TikTok hay Instagram — bạn có thể tự viết bằng bất kỳ ngôn ngữ nào và để TikMatrix giao chiếc điện thoại cho bạn.

Yêu cầu

Yêu cầu giấy phép

Script tùy chỉnh cần gói Pro, Team hoặc Business. Gói Starter không có quyền truy cập.

Số thiết bị trong gói của bạn cũng chính là giới hạn chạy đồng thời: gói Pro (20 thiết bị) có thể điều khiển 20 điện thoại cùng lúc, dù qua tác vụ tích hợp, script tùy chỉnh, hay kết hợp cả hai.

Hai cách chạy một script

Độc lập

Bạn tự chạy chương trình. TikMatrix chỉ cho mượn thiết bị.

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())

Phù hợp cho việc chạy một lần, thu thập dữ liệu, và mọi thứ bạn muốn khởi động từ bộ lập lịch của riêng mình.

Được quản lý

Bạn đăng ký chương trình trong TikMatrix và nó trở thành một tác vụ như mọi tác vụ khác. Nó có hàng đợi tác vụ, giới hạn đồng thời theo gói, tự động thử lại, nhật ký tác vụ và mẫu lịch chạy. TikMatrix thuê thiết bị trước khi khởi động chương trình của bạn và truyền id thuê qua biến môi trường.

from tikmatrix import TikMatrix

with TikMatrix.from_env() as d: # thiết bị đã được thuê sẵn
d.click(text="Log in")
print("done") # dòng này sẽ nằm trong nhật ký tác vụ

Phù hợp cho mọi thứ bạn muốn chạy lặp lại, theo lịch, hoặc trên nhiều thiết bị.

Chọn cái nào

Độc lậpĐược quản lý
Ai khởi độngBạnHàng đợi tác vụ của TikMatrix
Thuê thiết bịBạn tự lấyĐã có sẵn khi khởi động
Thử lại, lịch chạy, nhật kýBạn tự xâyCó sẵn
Chạy trên nhiều thiết bịBạn tự viết vòng lặpMỗi thiết bị một tác vụ, chạy song song
Tốt nhất choKhám phá, trình thu thập, việc chạy một lầnMọi thứ bạn muốn lặp lại

Bạn có thể bắt đầu ở chế độ độc lập trong lúc hoàn thiện luồng, rồi đăng ký chính tệp đó thành script được quản lý — dòng duy nhất thay đổi là TikMatrix.from_env().

Bắt đầu

1. Cài thư viện client

pip install requests

Rồi sao chép tikmatrix.py từ thư mục SDK đặt cạnh script của bạn. Thư viện chỉ là một tệp duy nhất, không có phụ thuộc nào khác.

Bạn không bắt buộc phải dùng nó — API chỉ là JSON thuần qua HTTP, và các endpoint thô được ghi rõ bên dưới.

2. Viết script của bạn

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")

Chạy nó khi TikMatrix đang mở và điện thoại đã kết nối. Nếu nó in ra một từ điển thông tin thiết bị thì mọi thứ đã thông suốt.

3. Đăng ký nó (chỉ chế độ được quản lý)

Vào Thiết bị → Script tùy chỉnh → Thêm script:

TrườngÝ nghĩa
TênHiển thị trong danh sách script và nhật ký tác vụ
LệnhDòng lệnh chương trình cần chạy, ví dụ python C:/scripts/my_flow.py
Thư mục làm việcTùy chọn. Nơi chương trình khởi động
Nền tảngXem chế độ nền tảng bên dưới
Thời gian chờSố giây trước khi script bị buộc dừng và tác vụ bị đánh dấu thất bại. Mặc định 1800
Biến môi trường bổ sungĐối tượng JSON tùy chọn, được hợp nhất vào môi trường của chương trình
BậtTắt một script mà không xóa. Script bị tắt không thể được điều phối

Sau đó nhấn ▶ trên dòng của script và chọn thiết bị, hệt như với script tích hợp.

Để trợ lý viết giúp bạn

Trợ lý AI có thể soạn một script tùy chỉnh từ mô tả bằng ngôn ngữ thường và đăng ký nó chỉ trong một bước. Nó cho bạn xem toàn bộ tệp trước khi ghi bất cứ thứ gì lên đĩa.

Thuê thiết bị

Một điện thoại chỉ có thể được điều khiển bởi một thứ tại một thời điểm. Thuê nó là báo cho TikMatrix biết thiết bị đang bận, nhờ đó:

  • hàng đợi tác vụ sẽ không đẩy tác vụ lên cùng màn hình đó, và
  • các lệnh gọi JSON-RPC của bạn báo cáo tình trạng agent y như script tích hợp, nên bộ giám sát thấy một agent đang bận thay vì một agent im lặng.

Việc thuê cũng chiếm một suất thiết bị trong gói của bạn.

Lượt thuê sẽ hết hạn — mặc định 120 giây, tối đa 600. Thư viện Python gia hạn lượt thuê của bạn trong một luồng nền và giải phóng khi khối with kết thúc, nên một script bị sập sẽ trả thiết bị trong vài giây thay vì giữ đến khi bạn khởi động lại ứng dụng. Nếu bạn gọi API trực tiếp, bạn phải tự gửi nhịp tim.

Bạn có thể xem mọi lượt thuê đang sống — và giải phóng cưỡng bức — tại Cài đặt → Developer API → Phiên thiết bị đang hoạt động.

Chế độ nền tảng

Script đã đăng ký khai báo mục tiêu của nó:

Generic — thiết bị được giao nguyên trạng. Không mở ứng dụng nào, không chuyển tài khoản, không kiểm tra bộ gõ, và không đóng gì sau khi xong. Dùng chế độ này để tự động hóa bất cứ thứ gì không phải TikTok hay Instagram.

TikTok / Instagram — ứng dụng được mở và tài khoản được chuyển trước khi chương trình của bạn bắt đầu, rồi ứng dụng được đóng khi kết thúc, hệt như với script tích hợp. TIKMATRIX_PACKAGE cho biết gói ứng dụng nào đã được xác định. Dùng chế độ này để thêm một bước mà script tích hợp không có.

Biến môi trường

Script được quản lý nhận:

BiếnÝ nghĩa
TIKMATRIX_API_BASEURL máy chủ, ví dụ http://127.0.0.1:50809
TIKMATRIX_SESSION_IDLượt thuê đã được giữ sẵn cho bạn
TIKMATRIX_SERIALThiết bị mà tác vụ này được gửi tới
TIKMATRIX_PACKAGEGói ứng dụng đã xác định
TIKMATRIX_PLATFORMtiktok, instagram hoặc generic

TikMatrix.from_env() đọc toàn bộ những thứ này giúp bạn.

Script độc lập không nhận biến nào trong số đó — hãy thuê thiết bị một cách tường minh.

Mọi thứ bạn đặt trong Biến môi trường bổ sung sẽ được hợp nhất đè lên trên, đây là cách thông dụng để truyền thiết lập riêng cho từng lần chạy vào cùng một script đã đăng ký mà không phải sửa tệp.

Tham chiếu thư viện Python

TikMatrix — kết nối

Lời gọiLàm gì
TikMatrix(base_url=None, timeout=30.0)Kết nối. Lùi về TIKMATRIX_API_BASE, rồi http://127.0.0.1:50809
client.devices()Thiết bị trực tuyến, mỗi thiết bị có serial, real_serialbusy
client.sessions()Mọi lượt thuê đang sống, kể cả của tiến trình khác
client.device(serial, label=..., ttl_secs=120)Thuê một thiết bị và trả về Device
TikMatrix.from_env()Tiếp nhận thiết bị mà script được quản lý đã khởi động cùng

Device — chiếc điện thoại

Lời gọiLàm gì
d.info()Thông tin thiết bị từ UIAutomator2
d.window_size()(rộng, cao)
d.screenshot(path=None)Byte PNG, tùy chọn ghi ra path
d.hierarchy()Cây giao diện hiện tại dưới dạng XML
d.find(text=, resource_id=, description=, class_name=)Các nút khớp, mỗi nút có boundscenter
d.exists(**criteria)Có gì khớp hay không
d.wait_for(timeout=10.0, interval=1.0, **criteria)Chờ đến khi xuất hiện rồi trả về
d.click(timeout=10.0, **criteria)Chờ phần tử rồi chạm vào tâm của nó
d.click_xy(x, y)Chạm vào tọa độ
d.swipe(sx, sy, ex, ey, steps=20)Vuốt
d.press(key)back, home, recent, enter, …
d.input_text(text)Gõ vào ô đang được chọn qua bộ gõ nhanh đi kèm
d.jsonrpc(method, params=None, timeout=10)Bất kỳ phương thức UIAutomator2 nào
d.adb(*args, timeout_ms=None)Chạy một lệnh ADB
d.release()Giải phóng lượt thuê. with làm điều này giúp bạn

find so khớp trên cây giao diện đã kết xuất, nên khi một selector trượt bạn có thể print(d.hierarchy()) và xem chính xác nó đã tìm trong gì. Trình kiểm tra phần tử ở khung thiết bị hiển thị cùng cây đó dưới dạng trực quan, thường là cách nhanh nhất để tìm resource-id.

input_text cần ADB

Nó gửi broadcast tới bộ gõ đi kèm, đi qua adb shell. Hãy bật quyền ADB trước khi dùng, nếu không nó sẽ thất bại với mã 403.

Lỗi

Thư viện ném ra hai ngoại lệ, cả hai đều là lớp con của RuntimeError:

Ngoại lệKhi nào
DeviceBusyErrorHTTP 409 — thiết bị đã được thuê, hoặc gói của bạn hết suất thiết bị
TikMatrixErrorMọi trường hợp còn lại: gói quá thấp, lượt thuê hết hạn, ADB bị tắt, selector không bao giờ khớp
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("máy đó đang có người dùng — thử máy khác")
except TikMatrixError as exc:
print("thất bại:", exc)

Trong một script được quản lý, để ngoại lệ thoát ra ngoài thường là điều đúng đắn: mã thoát khác 0 đánh dấu tác vụ thất bại và vết lỗi sẽ nằm trong nhật ký tác vụ.

Endpoint HTTP

Các thao tác trên thiết bị cần header x-session-id trỏ tới một lượt thuê đang sống. Không có khóa API: giống như phần còn lại của API cục bộ, các endpoint này không xác thực — việc tiếp cận được máy này trên mạng chính là kiểm soát truy cập. Chúng không gửi header CORS nào, nên hãy gọi từ một chương trình (curl, Python, bất kỳ mã phía máy chủ nào) chứ đừng gọi từ một trang trong trình duyệt.

Phương thứcĐường dẫnMục đích
GET/api/v1/rpc/devicesLiệt kê thiết bị trực tuyến và tình trạng bận
POST/api/v1/rpc/sessionThuê một thiết bị → session_id
POST/api/v1/rpc/session/{id}/heartbeatGia hạn lượt thuê
DELETE/api/v1/rpc/session/{id}Giải phóng lượt thuê
GET/api/v1/rpc/sessionLiệt kê các lượt thuê đang sống
POST/api/v1/rpc/jsonrpcGọi một phương thức UIAutomator2
POST/api/v1/rpc/adbChạy một lệnh ADB
GET/api/v1/rpc/hierarchy?serial=Cây giao diện hiện tại dạng XML
GET/api/v1/rpc/screenshot?serial=Màn hình hiện tại dạng PNG

Phản hồi JSON dùng cùng lớp bao như phần còn lại của API cục bộ — {"code": 0, "message": "success", "data": ...}, với code khác 0 khi thất bại. hierarchyscreenshot trả về nội dung thô.

Ví dụ

# Thuê một thiết bị
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", ...}}

# Điều khiển nó
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":[]}'

# Giữ lượt thuê sống trong khi làm việc
curl -X POST http://127.0.0.1:50809/api/v1/rpc/session/ff3ae079-.../heartbeat \
-H "Content-Type: application/json" \
-d '{"ttl_secs":120}'

# Trả lại
curl -X DELETE http://127.0.0.1:50809/api/v1/rpc/session/ff3ae079-...

Lỗi

Trạng tháiÝ nghĩa
403Gói thấp hơn Pro, không có lượt thuê, lượt thuê hết hạn, hoặc quyền ADB bị tắt
409Thiết bị đã được thuê, hoặc gói của bạn hết suất thiết bị

Viết bằng ngôn ngữ khác

Không có gì ở đây gắn riêng với Python. Bất kỳ môi trường chạy nào gửi được yêu cầu HTTP đều dùng được — hợp đồng của chế độ được quản lý chỉ là "đọc ba biến môi trường, thoát với mã 0 khi thành công".

// my_flow.js — đăng ký bằng: 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"));

Nếu trình thông dịch không nằm trong PATH, hãy ghi đường dẫn đầy đủ ở ô Lệnh, ví dụ C:/Program Files/nodejs/node.exe C:/scripts/my_flow.js.

Kích hoạt script tùy chỉnh từ API

Script đã đăng ký cũng có thể được khởi động qua API quản lý tác vụ, nhờ đó một script có thể xếp hàng công việc tiếp theo:

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 là id của script bạn đã đăng ký.

Quyền ADB

/api/v1/rpc/adb cho script của bạn một shell trên thiết bị — bạn cần nó để đẩy media, cài APK và đổi cài đặt hệ thống. Vì đó là một shell đầy đủ trên một endpoint không có khóa API, nó được xuất xưởng ở trạng thái tắt. Hãy bật ở Cài đặt → Developer API → Cho phép lệnh ADB khi bạn có script cần đến; tự động hóa giao diện qua /rpc/jsonrpc vẫn chạy được mà không cần nó.

Khi đang tắt, /api/v1/rpc/adb trả về 403 và phần còn lại của API vẫn hoạt động bình thường. Mọi lệnh ADB mà script chạy đều được ghi vào tệp nhật ký của bạn.

Viết script để nó tiếp tục chạy được

  • Hãy chờ màn hình, đừng ngủ thay cho nó. d.wait_for(...) trả về ngay khi phần tử xuất hiện; một lệnh ngủ cố định thì hoặc chậm hơn mức cần thiết, hoặc quá ngắn vào một ngày xui.
  • Kiểm tra trước khi chạm. Một lần d.exists(...) trên hộp thoại đồng ý hay lời nhắc "để sau" chỉ tốn một lần kết xuất cây, nhưng cứu được một lần chạy lẽ ra đã chạm vào chỗ trống.
  • In ra những gì bạn đã làm. Ở chế độ được quản lý, stdout chính là nhật ký tác vụ, và đó là dấu vết duy nhất của một lần chạy không ai theo dõi.
  • Làm cho việc chạy lại an toàn. Thử lại sẽ chạy lại toàn bộ chương trình, nên script đăng bài nên kiểm tra xem nó đã đăng chưa thay vì mặc định rằng nó bắt đầu từ đầu.
  • Một script một việc. Mức đồng thời tính theo thiết bị, nên mười tác vụ nhỏ trên mười điện thoại xong sớm hơn nhiều so với một script lặp qua mười điện thoại.

Ghi chú và giới hạn

  • Lệnh được thực thi trực tiếp, không qua shell, nên &&| bị coi là tham số chứ không phải toán tử. Hãy đăng ký cmd /c "..." (Windows) hoặc sh -c "..." (macOS) nếu bạn muốn hành vi của shell.
  • Đặt dấu nháy quanh đường dẫn có khoảng trắng: "C:/Program Files/Python/python.exe" my_script.py.
  • Script vượt quá thời gian chờ sẽ bị chấm dứt và tác vụ bị đánh dấu thất bại.
  • Mã thoát khác 0 đánh dấu tác vụ thất bại; mọi thứ script ghi ra stdout và stderr đều vào nhật ký tác vụ.
  • Script chạy với cùng quyền hạn như chính TikMatrix. Chỉ đăng ký những chương trình bạn tự viết hoặc tin tưởng.

Khắc phục sự cố

API access requires Pro or higher plan (403) Giấy phép trên máy này là Starter hoặc không hoạt động. Kiểm tra Cài đặt → Giấy phép.

Bị từ chối kết nối tại 127.0.0.1:50809 TikMatrix không chạy, hoặc đang chạy dưới người dùng khác. Máy chủ chỉ tồn tại khi ứng dụng đang mở.

Nhận 409 ở mọi lần thuê Hoặc điện thoại thực sự đang bận — xem Cài đặt → Developer API → Phiên thiết bị đang hoạt động — hoặc mọi suất thiết bị trong gói của bạn đã bị các tác vụ đang chạy chiếm hết.

Lượt thuê hết hạn giữa một bước dài TTL mặc định là 120 giây và thư viện gia hạn ở nền, nên điều này thường có nghĩa là script đã chặn luồng chính lâu hơn TTL. Hãy tăng ttl_secs (tối đa 600), hoặc chuyển phần việc dài ra khỏi luồng đó.

d.adb(...) thất bại với 403 Quyền ADB đang tắt. Bật ở Cài đặt → Developer API → Cho phép lệnh ADB.

Một selector không bao giờ khớp print(d.hierarchy()) hiển thị đúng cây mà find đã tìm. Văn bản được so khớp chính xác, nên thừa một khoảng trắng hay nhãn đã được bản địa hóa là nguyên nhân thường gặp; so khớp theo resource_id ổn định hơn theo text.

Tác vụ bị đánh dấu thất bại nhưng điện thoại trông vẫn ổn Hãy đọc nhật ký tác vụ. Mã thoát khác 0 — kể cả một ngoại lệ không bắt được ở cuối một lần chạy thành công — vẫn làm tác vụ thất bại dù phần tự động hóa đã chạy đúng.

Bước tiếp theo