النصوص البرمجية المخصصة
تغطي النصوص المدمجة المسارات الشائعة. وعندما تحتاج إلى شيء لا توفره — خطوة بترتيب مختلف، أو شاشة لا تلمسها أبدًا، أو تطبيق ليس 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 بجانب نصك البرمجي. المكتبة م لف واحد بلا اعتماديات أخرى.
لست مضطرًا لاستخدامها — الواجهة مجرد 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 كحد أقصى. تجدّد مكتبة بايثون حجزك في خيط خلفي وتحرّره عند انتهاء كتلة with، فينعتق الجهاز خلال ثوانٍ إذا انهار النص بدل بقائه محجوزًا حتى تعيد تشغيل التطبيق. وإن كنت تستدعي الواجهة مباشرة فعليك إرسال نبضات الحياة بنفسك.
يمكنك رؤية كل الحجوزات النشطة — وتحرير أي منها قسرًا — من الإعدادات ← Developer API ← جلسات الأجهزة النشطة.
أوضاع المنصة
يعلن النص المسجّل عن هدفه:
Generic — يُسلَّم الجهاز كما هو. لا يُفتح أي تطبيق، ولا تبديل حسابات، ولا فحص لطريقة الإدخال، ولا يُغلق شيء بعد الانتهاء. استخدمه لأتمتة أي تطبيق لا يوجد برنامج TikMatrix مدمج له.
TikTok / Instagram / Threads — يُفتح التطبيق ويُجعل الحساب الصحيح نشطًا قبل بدء برنامجك، ويُغلق التطبيق عند الانتهاء، تمامًا كما مع نص مدمج. ويخبرك TIKMATRIX_PACKAGE بالحزمة التي جرى تحديدها. استخدمه لإضافة خطوة لا تغطيها النصوص المدمجة.
على Threads يتم التبديل من خلال الإعدادات → تبديل الحسابات في التطبيق، وتتم قراءة المقبض على صفحة الملف الشخصي بعد ذلك. تفشل المهمة التي تسمي حسابًا لم يتم تسجيل الدخول إليه على الجهاز، بدلًا من التشغيل كمن يصادف أن يكون نشطًا.
متغيرات البيئة
يستقبل النص المُدار:
| المتغير | المعنى |
|---|---|
TIKMATRIX_API_BASE | عنوان الخادم، مثل http://127.0.0.1:50809 |
TIKMATRIX_SESSION_ID | الحجز المحفوظ لك بالفعل |
TIKMATRIX_SERIAL | الجهاز الذي أُرس لت إليه هذه المهمة |
TIKMATRIX_PACKAGE | حزمة التطبيق المحدَّدة |
TIKMATRIX_PLATFORM | tiktok أو instagram أو threads أو generic |
تقرأ TikMatrix.from_env() كل ذلك نيابة عنك.
النصوص المستقلة لا تحصل على أي منها — احجز جهازًا صراحةً بدلًا من ذلك.
وكل ما تضعه في متغيرات بيئة إضافية يُدمج فوق ذلك، وهي الطريقة المعتادة لتمرير إعدادات خاصة بكل تشغيل إلى نص مسجّل واحد دون تعديل الملف.
مرجع مكتبة بايثون
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: فكما هي حال بقية الواجهة المحلية، هذه النقاط غير مصادَق عليها — والقدرة على الوصول إلى الجهاز عبر الشبكة هي ضابط الوصول. وهي لا ترسل أي ترويسات CORS، لذا استدعِها من برنامج (curl أو بايثون أو أي كود من جهة الخادم) لا من صفحة في المتصفح.
| الطريقة | المسار | الغرض |
|---|---|---|
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 الغلاف نفسه المستخدم في بقية الواجهة المحلية — {"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 | الجهاز محجوز بالفعل، أو لا مقعد جهاز شاغر في خطتك |
الكتابة بلغة أخرى
لا شيء هنا خاص ببايثون. تصلح أي بيئة تشغيل قادرة على إرسال طلب 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.
تشغيل نص مخصص من الواجهة البرمجية
يمكن أيضًا تشغيل النصوص المسجّلة عبر واجهة إدارة المهام، فيستطيع نص واحد أن يضع عملًا لاحقًا في الطابور:
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 وتبقى بقية الواجهة تعمل. ويُكتب كل أمر ADB ينفّذه أي نص في ملف السجل لديك.
كتابة نصوص تستمر في العمل
- انتظر الشاشة ولا تنم من أجلها. يعود
d.wait_for(...)فور ظهور العنصر؛ أما النوم الثابت فإما أبطأ من اللازم أو أقصر من اللازم في يوم سيئ. - تحقّق قبل النقر. استدعاء
d.exists(...)على نافذة موافقة أو تنبيه «ليس الآن» يكلّف استخراج شجرة واحدة وينقذ تشغيلة كانت ستنقر في الفراغ. - اطبع ما فعلته. في الوضع المُدار يكون stdout هو سجل المهمة، وهو الأثر الوحيد لتشغيلة لم يراقبها أحد.
- اجعل إعادة التشغيل آمنة. إعادة المحاولة تعيد تنفيذ البرنامج كاملًا، لذا ينبغي للنص الذي ينشر أن يتحقق مما إذا كان قد نشر بالفعل بدل افتراض أنه يبدأ م ن الصفر.
- نص واحد لمهمة واحدة. التزامن محسوب لكل جهاز، فعشر مهام صغيرة على عشرة هواتف تنتهي أسرع بكثير من نص واحد يدور على عشرة هواتف.
ملاحظات وحدود
- يُنفَّذ الأمر مباشرةً لا عبر صدفة، لذا يُعامَل
&&و|كوسيطات لا كمعاملات. سجّلcmd /c "..."(ويندوز) أوsh -c "..."(ماك) إن أردت سلوك الصدفة. - ضع المسارات التي تحوي مسافات بين علامتي اقتباس:
"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 ← جلسات الأجهزة النشطة — أو أن كل مقاعد الأجهزة في خطتك مشغولة بمهام قيد التنفيذ.
ينتهي الحجز في منتصف خطوة طويلة
المهلة الافتراضية 120 ثانية والمكتبة تجدّدها في الخلفية، لذا يعني هذا غالبًا أن النص حجب خيطه الرئيسي مدة أطول من المهلة. ارفع ttl_secs (حتى 600)، أو انقل العمل الطويل خارج ذلك الخيط.
d.adb(...) يفشل بالرمز 403
وصول ADB معطّل. فعّله من الإعدادات ← Developer API ← السماح بأوامر ADB.
محدِّد لا يطابق أبدًا
يعرض print(d.hierarchy()) الشجرة التي بحث فيها find بالضبط. والنص يُطابَق حرفيًا، لذا فالسبب المعتاد مسافة زائدة أو تسمية مترجَمة؛ والمطابقة عبر resource_id أثبت من المطابقة عبر text.
المهمة معلَّمة كفاشلة لكن الهاتف يبدو سليمًا اقرأ سجل المهمة. فالخروج بقيمة غير صفرية — بما في ذلك استثناء غير مُلتقَط في نهاية تشغيلة ناجحة — يُفشل المهمة حتى لو نجحت الأتمتة نفسها.
الخطوات التالية
- نظرة عامة على الواجهة المحلية — المصادقة وصيغة الاستجابة
- واجهة إدارة المهام — إنشاء المهام والاستعلام عنها وإعادتها وإيقافها
- المساعد الذكي — دع نموذجًا يصوغ نصًا ويسجّله نيابة عنك
- SDK والأمثلة على GitHub