للمطوّرين

أضف LeanApp إلى تطبيقك

ترسل أربع حزم SDK وواجهة REST API أحداث تطبيقك إلى LeanApp. يشرح هذا الدليل أي حزمة تستخدم، وكيف تعدّها، وما الأحداث التي ترسلها، وكيف تتحقق منها قبل إطلاق تطبيقك.

الحزم جاهزة ومختبرة في أنظمة الاختبار الآلي لدينا، لكنها غير منشورة بعد على مستودعات الحزم العامة. نسلّمها لفريقك أثناء الإعداد، وستعرض هذه الصفحة أمر التثبيت الخاص بكل حزمة عند نشرها على المستودع العام المناسب لها.

حزم SDK

حزمة لكل منصة، بأسماء الدوال نفسها والقواعد نفسها للطابور وإعادة المحاولة والجلسات.

  • JavaScript / React Native

    لم تُنشر بعد
    الحزمة
    @leanapp/analytics
    تعمل على
    متصفحات الويب، وتطبيقات React Native، والخوادم التي تعمل بـ Node.js 18 فأحدث. ولا تعتمد الحزمة على أي مكتبة أخرى، فلا تضيف مكتبات أخرى إلى تطبيقك.
    الحالة
    غير منشورة بعد؛ نوفّرها لك أثناء الإعداد.

    ما تقوم به

    • الأحداث والشاشات والمستخدمون والجلسات
    • الموافقة لكل غرض (التحليلات، والتسويق، والإشعارات، والإسناد)
    • بيانات الحملات من الروابط: معاملات utm_* ومعرّفات النقر الإعلانية
    • طابور يعمل دون اتصال: localStorage في المتصفح و AsyncStorage في React Native

    غير متوفر بعد

    • مُحيل التثبيت من Google Play في React Native
    • الحقل deep_link_url عند فتح التطبيق
    • عرض الرسائل داخل التطبيق
    • استدعاءات الروابط العميقة المؤجّلة
    اعرض الشيفرة
  • Android (Kotlin)

    لم تُنشر بعد
    الحزمة
    io.leanapp:leanapp-android
    تعمل على
    Android 5.0+ (API 21). تحتاج إلى Play Install Referrer.
    الحالة
    غير منشورة بعد؛ نوفّرها لك أثناء الإعداد.

    ما تقوم به

    • الأحداث والشاشات والمستخدمون والجلسات
    • إرسال app_installed و app_updated و app_opened تلقائيًا
    • مُحيل التثبيت من Google Play، يُقرأ مرة واحدة لكل تثبيت
    • بيانات الحملة من الرابط الذي فتح التطبيق

    غير متوفر بعد

    • الموافقة لكل غرض (يتوفر optOut / optIn فقط)
    • عرض الرسائل داخل التطبيق
    • استدعاءات الروابط العميقة المؤجّلة
    اعرض الشيفرة
  • iOS (Swift)

    لم تُنشر بعد
    الحزمة
    LeanApp (Swift Package)
    تعمل على
    iOS 13 فأحدث، وكذلك macOS 10.15 فأحدث و tvOS 13 فأحدث. ولا تعتمد على أي مكتبة أخرى، فلا يضيف تثبيتها أي مكتبات جديدة إلى بناء تطبيقك.
    الحالة
    غير منشورة بعد؛ نوفّرها لك أثناء الإعداد.

    ما تقوم به

    • الأحداث والشاشات والمستخدمون والجلسات
    • إرسال app_installed و app_updated و app_opened تلقائيًا
    • رموز إشعارات APNs
    • بيانات الحملة من الروابط العميقة والروابط العامة التي تمرّرها

    غير متوفر بعد

    • الموافقة لكل غرض (يتوفر optOut / optIn فقط)
    • قيم التحويل في SKAdNetwork / AdAttributionKit
    • عرض الرسائل داخل التطبيق
    • استدعاءات الروابط العميقة المؤجّلة
    اعرض الشيفرة
  • Flutter (Dart)

    لم تُنشر بعد
    الحزمة
    leanapp_analytics
    تعمل على
    Flutter 3.13 فأحدث (Dart 3.1 فأحدث) على Android و iOS. تعتمد على مكتبتين فقط: http لإرسال الأحداث، و shared_preferences لحفظ البيانات على الجهاز.
    الحالة
    غير منشورة بعد؛ نوفّرها لك أثناء الإعداد.

    ما تقوم به

    • الأحداث والشاشات والمستخدمون والجلسات
    • إرسال app_installed و app_updated و app_opened تلقائيًا
    • مُحيل التثبيت عبر إضافة مثل play_install_referrer
    • بيانات الحملة من الروابط التي تمرّرها

    غير متوفر بعد

    • الموافقة لكل غرض (يتوفر optOut / optIn فقط)
    • مُحيل التثبيت دون إضافة
    • عرض الرسائل داخل التطبيق
    • استدعاءات الروابط العميقة المؤجّلة
    اعرض الشيفرة

البدء السريع

من مشروع فارغ إلى أول حدث، في خمس خطوات.

  1. 01

    أنشئ مشروعك

    سجّل حسابًا وأنشئ تطبيقك. لكل مشروع ثلاث بيئات: التطوير، والاختبار، والإنتاج، وبيانات كل بيئة منفصلة، فلا تختلط بيانات الاختبار ببيانات المستخدمين الحقيقيين.

  2. 02

    احصل على مفاتيحك

    افتح الإعدادات ← التطوير والتشغيل ← SDK ومفاتيح API. لكل بيئة مفتاح SDK عام خاص بها: la_pk_dev_… و la_pk_stg_… و la_pk_live_….

  3. 03

    أضف الحزمة وهيّئها

    هيّئ الحزمة مرة واحدة وفي أبكر وقت ممكن: في Application.onCreate أو didFinishLaunching أو main(). واستخدم مفتاح التطوير أثناء بناء التطبيق.

  4. 04

    أرسل الأحداث الواردة في خطة التتبّع

    تعرض صفحة الإعدادات ← التطوير والتشغيل ← التنفيذ كل حدث يجب أن ترسله من تطبيقك، مع خصائصه ومقتطف شيفرة يمكنك نسخه لكل حدث.

  5. 05

    راقب وصولها

    تعرض صفحة الإعدادات ← التطوير والتشغيل ← مراقب الأحداث كل حدث لحظة وصوله وهل يطابق الخطة. انتقل إلى مفتاح الإنتاج عندما تصبح سليمة.

الشيفرة لكل منصة

الاستدعاءات نفسها تعمل على كل المنصات. افتح المنصة التي تستخدمها لعرض الشيفرة الخاصة بها.

JavaScript / React Native

الإضافة والتهيئة

// Not on npm yet: we share the package with you during onboarding.
import { Analytics } from "@leanapp/analytics";

Analytics.initialize({
  apiKey: "la_pk_dev_…",   // development key while you build
  appVersion: "2.4.0",
  // React Native: keep the queue across restarts and send it in the background
  // storage: asyncStorageAdapter(AsyncStorage), appState: AppState,
});

الشاشات والأحداث والمستخدمون

Analytics.screen("Home");
Analytics.track("product_viewed", { product_id: "123", price: 299, currency: "SAR" });

// After login
Analytics.identify("user_123", { plan: "plus", language: "ar" });

// Your own id as eventId, so a retry is never counted twice
Analytics.track("order_completed", { order_id: "o1", revenue: 45, currency: "SAR" }, { eventId: "order-o1" });

// On logout
Analytics.reset();

الروابط والخصوصية والإرسال

// Campaign data from the opening URL (utm_* and click ids)
Analytics.captureAttribution(window.location.href);

// Consent: hold events until the user answers, then record the answer
Analytics.initialize({ apiKey: "la_pk_dev_…", consentDefault: "pending" });
Analytics.setConsent({ analytics: true, marketing: false, push: true, attribution: true });

// Optional: send the queue now
await Analytics.flush();
Android (Kotlin)

الإضافة والتهيئة

// Not on Maven Central yet: we share the module with you during onboarding.
import io.leanapp.analytics.Analytics
import io.leanapp.analytics.AnalyticsOptions

class App : Application() {
    override fun onCreate() {
        super.onCreate()
        Analytics.initialize(this, "la_pk_dev_…", AnalyticsOptions(debug = true))
    }
}

الشاشات والأحداث والمستخدمون

Analytics.screen("Home")
Analytics.track("product_viewed", mapOf("product_id" to "123", "price" to 299, "currency" to "SAR"))

// After login
Analytics.identify("user_123", mapOf("plan" to "plus", "language" to "ar"))

// Your own id as eventId, so a retry is never counted twice
Analytics.track("order_completed", mapOf("order_id" to "o1", "revenue" to 45.0, "currency" to "SAR"), eventId = "order-o1")

// On logout
Analytics.reset()

الروابط والخصوصية والإرسال

// The link that launched the app is captured automatically.
// Links that arrive while the app is running:
override fun onNewIntent(intent: Intent) {
    super.onNewIntent(intent)
    intent.dataString?.let { Analytics.captureAttribution(it) }
}

// The user turned analytics off (optIn() turns it back on)
Analytics.optOut()

// Optional: send the queue now
Analytics.flush()
iOS (Swift)

الإضافة والتهيئة

// Not tagged as a public Swift package yet: we share it with you during onboarding.
import LeanApp

// application(_:didFinishLaunchingWithOptions:), on the main thread
var options = AnalyticsOptions()
options.debug = true
Analytics.initialize(apiKey: "la_pk_dev_…", options: options)

الشاشات والأحداث والمستخدمون

Analytics.screen("Home")
Analytics.track("product_viewed", properties: ["product_id": "123", "price": 299, "currency": "SAR"])

// After login
Analytics.identify("user_123", traits: ["plan": "plus", "language": "ar"])

// Your own id as eventId, so a retry is never counted twice
Analytics.track("order_completed", properties: ["order_id": "o1", "revenue": 45.0, "currency": "SAR"], eventId: "order-o1")

// On logout
Analytics.reset()

الروابط والخصوصية والإرسال

// Deep links and universal links
func scene(_ scene: UIScene, openURLContexts contexts: Set<UIOpenURLContext>) {
    contexts.forEach { Analytics.captureAttribution($0.url) }
}

// The user turned analytics off (optIn() turns it back on)
Analytics.optOut()

// Optional: send the queue now
Analytics.flush()
Flutter (Dart)

الإضافة والتهيئة

// Not on pub.dev yet: we share the package with you during onboarding.
import 'package:leanapp_analytics/leanapp_analytics.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Analytics.initialize(apiKey: 'la_pk_dev_…', appVersion: '2.4.0', appBuild: '240', debug: true);
  runApp(const MyApp());
}

الشاشات والأحداث والمستخدمون

Analytics.screen('Home');
Analytics.track('product_viewed', {'product_id': '123', 'price': 299, 'currency': 'SAR'});

// After login
Analytics.identify('user_123', {'plan': 'plus', 'language': 'ar'});

// Your own id as eventId, so a retry is never counted twice
Analytics.track('order_completed', {'order_id': 'o1', 'revenue': 45, 'currency': 'SAR'}, 'order-o1');

// On logout
Analytics.reset();

الروابط والخصوصية والإرسال

// Links from app_links (or your own link handling)
Analytics.captureAttribution(uri.toString());

// The user turned analytics off (optIn() turns it back on)
Analytics.optOut();

// Optional: send the queue now
await Analytics.flush();

أسماء الأحداث وخطة التتبّع

الأسماء الواضحة تجعل كل تقرير أسهل قراءة. وخطة التتبّع التي نعدّها معك تتبع هذه القواعد أصلًا.

  • استخدم صيغة snake_case: الكائن أولًا، ثم الفعل بصيغة الماضي، مثل product_viewed و order_completed.
  • يبدأ الاسم بحرف، ولا يتجاوز 100 حرف.
  • أرسل حدثًا واحدًا لكل واقعة تجارية، وضع الاختلافات في الخصائص (payment_method و source).
  • المبالغ المالية: أرسل رقمًا في revenue أو value أو price، مع رمز عملة وفق معيار ISO 4217 مثل SAR أو AED. أما الاسترداد فحدث مستقل بذاته، ولا يُرسل أبدًا على شكل إيراد سالب في حدث الطلب.
  • خصائص المستخدم تصف الشخص (المدينة، والباقة، واللغة). أما ما يتغير مع كل إجراء فمكانه خصائص الحدث.
  • الأحداث غير الواردة في خطتك تُحفظ وتظهر على أنها غير مخطّط لها، مع اقتراحات لربطها بحدث مخطّط.

أمثلة

  • product_viewedفتح المستخدم صفحة منتج
  • checkout_startedبدأ المستخدم إتمام الشراء
  • order_completedدُفع طلب، مع الإيراد والعملة
  • subscription_renewedجُدّد اشتراك (أرسله من خادمك)
  • refund_completedصُرف مبلغ مسترد (أرسله من خادمك)

المستخدمون: التعريف والخروج

تحمل الأحداث قبل تسجيل الدخول معرّفًا مجهولًا. عرّف المستخدم، فيربط LeanApp ما فعله قبل الدخول وبعده.

  • فور تسجيل الدخول أو إنشاء الحساب، استدعِ identify بمعرّف المستخدم الثابت لديك، لا ببريده أو هاتفه.
  • مرّر سمات تصف الشخص (الباقة، والمدينة، واللغة)، ثم حدّثها لاحقًا عبر setUserProperties.
  • استدعِ reset عند تسجيل الخروج، فيبدأ المستخدم التالي على الجهاز نفسه بمعرّف مجهول جديد.
  • استخدم alias لدمج معرّف الزائر في حساب حقيقي إذا كان تطبيقك يتيح الشراء دون حساب.

كيف تُرسل الأحداث

تعود الاستدعاءات فورًا ولا ترمي أخطاء بعد التهيئة: تضع الحزمة الأحداث في طابور وترسلها في الخلفية.

الإرسال على دفعات
كل 10 ثوانٍ أو عند تجمّع 20 حدثًا، وحتى 100 حدث للطلب.
دون اتصال
يُحفظ الطابور على الجهاز، بحد أقصى 1,000 حدث يُحذف أقدمها أولًا، ويبقى بعد إعادة تشغيل التطبيق. وتُحذف منه الأحداث التي مضى عليها أكثر من 7 أيام.
في الخلفية
يُرسل الطابور عند انتقال التطبيق إلى الخلفية: عند إخفاء الصفحة في المتصفح، وعبر appState في React Native، وعند توقف آخر نشاط في Android، وفي مهمة خلفية في iOS، وعند الإيقاف المؤقت في تطبيقات Flutter، فلا تنتظر الأحداث حتى يُفتح التطبيق من جديد في وقت لاحق.
إعادة المحاولة
تُعاد المحاولة عند أخطاء الشبكة والخادم بفواصل متزايدة من ثانية واحدة إلى 5 دقائق. ولكل حدث معرّف خاص به، فلا يُحتسب الحدث مرتين عند إعادة المحاولة.
مفتاح خاطئ أو ملغى
تتوقف الحزمة عن الإرسال وتحتفظ بالأحداث على الجهاز، فلا يضيع شيء أثناء إصلاح المفتاح.
الجلسات
تبدأ جلسة جديدة بعد 30 دقيقة من عدم النشاط.

الاختبار قبل الإنتاج

تحقق من كل حدث في بيئة التطوير قبل الإطلاق للمستخدمين الحقيقيين.

  1. 01ابنِ التطبيق بمفتاح التطوير (la_pk_dev_…) وفعّل سجلّ التصحيح (debug: true) لترى ما تفعله الحزمة.
  2. 02افتح الإعدادات ← التطوير والتشغيل ← مراقب الأحداث في بيئة التطوير، ثم استخدم التطبيق. سيظهر كل حدث مباشرة لحظة وصوله إلى المنصة، ومعه أي أخطاء ظهرت عند التحقق من صحته.
  3. 03أصلح ما يظهره مراقب الأحداث حتى تصبح أحداث خطتك سليمة. ويوضّح مؤشر التنفيذ ما زال ناقصًا.
  4. 04كرّر ذلك في بيئة الاختبار إن وُجدت، ثم أطلق التطبيق للمستخدمين بمفتاح الإنتاج (la_pk_live_…). ولن تظهر بيانات التطوير أبدًا في تقارير الإنتاج، فتبقى الأرقام التي يعتمد عليها فريقك في قراراته سليمة.

من خوادمك: REST API

أرسل الأحداث التي يعرفها خادمك أفضل من غيره، واقرأ البيانات من أدواتك، عبر الـ REST API.

  • استخدم المفاتيح السرية (la_sk_…) على الخوادم فقط، فحزمة JavaScript ترفضها خارج الخادم.
  • يرسل POST /v1/events حدثًا واحدًا، ويرسل POST /v1/events/batch حتى 500 حدث.
  • أرسل المدفوعات والتجديدات والمبالغ المستردة من خادمك، مع معرّف المعاملة في event_id.
  • للمفاتيح السرية صلاحيات لطلبات الخصوصية وخطة التتبّع والتقارير. اطلب منا مواصفات OpenAPI.
curl -X POST https://api.leanapp.io/v1/events \
  -H "Authorization: Bearer la_sk_live_…" \
  -H "Content-Type: application/json" \
  -d '{"type":"track","event_name":"order_completed","event_id":"o-1029",
       "user_id":"u-42","properties":{"order_id":"o-1029","revenue":120,"currency":"SAR"}}'

ملاحظات وتوصيات

  • ابنِ بمفتاح التطوير

    استخدم la_pk_dev_… أثناء البناء والاختبار، ولا تستخدم مفتاح الإنتاج إلا في إصدارات النشر، حتى لا تصل أحداث الاختبار أبدًا إلى التقارير التي يعتمد عليها فريقك.

  • استخدم صيغة snake_case لأسماء الأحداث

    اتبع خطة التتبّع حرفيًا؛ فأي خطأ إملائي في اسم الحدث ينشئ حدثًا جديدًا غير مخطّط له، وتحسبه التقارير حدثًا منفصلًا عن الحدث الذي خطّطت له في الأصل.

  • لا بيانات شخصية في الخصائص

    لا ترسل الأسماء أو عناوين البريد الإلكتروني أو أرقام الهواتف أو أرقام الهوية في خصائص الأحداث. عرّف المستخدمين بمعرّفك الداخلي بدلًا من أي بيانات شخصية.

  • عرّف المستخدم بعد تسجيل الدخول

    استدعِ identify فور تسجيل الدخول أو إنشاء الحساب، واستدعِ reset عند تسجيل الخروج، حتى لا تختلط أحداث شخصين مختلفين يستخدمان الجهاز نفسه.

  • دع الطابور يعمل

    تجمع الحزمة الأحداث وترسلها في الخلفية، فنادرًا ما تحتاج إلى التدخل بنفسك. لا تستدعِ flush إلا عند الحاجة، مثلًا قبل أن يُغلق المستخدم التطبيق إغلاقًا إجباريًا.

  • أرسل الإيرادات من الخادم

    تأكيدات الدفع مكانها خادمك لا التطبيق، وتُرسل منه بمفتاح سري مع معرّف المعاملة في event_id، فلا تُحتسب أي عملية دفع مرتين عند إعادة محاولة الإرسال.

  • حدّث الحزمة باستمرار

    اعتمد إصدارات الحزم الجديدة فور صدورها، ففيها إصلاحات وقدرات جديدة، مثل الروابط العميقة المؤجّلة عندما تبدأ الحزم باستدعاء واجهة الخادم الخاصة بها.

  • لا تضع مفتاحًا سريًا في تطبيق

    يحصل التطبيق على المفتاح العام (la_pk_…) فقط، وتبقى المفاتيح السرية على خوادمك، لأن أي شخص يحمّل تطبيقك يستطيع استخراج المفتاح منه.

هل أنت مستعد لربط تطبيقك؟

أنشئ حسابك لتحصل على مفاتيحك، أو راسلنا لنساعد مطوّريك.