30 أبريل 2025·7 دقيقة قراءة

مزامنة خلفية لتطبيقات الجوال أوفلاين-أول: تعارضات، إعادة المحاولة، تجربة المستخدم

خطّة لمزامنة الخلفية في تطبيقات الجوال "أوفلاين-أول" مع قواعد تعارض واضحة، منطق إعادة المحاولة، وواجهة بسيطة للتغييرات المعلقة لتطبيقات Kotlin و SwiftUI الأصلية.

مزامنة خلفية لتطبيقات الجوال أوفلاين-أول: تعارضات، إعادة المحاولة، تجربة المستخدم

المشكلة: المستخدمون يحررون بدون اتصال والعالم يتغير

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

لاحقًا يعود الاتصال ويحاول التطبيق اللحاق بالركب في الخلفية. هُنا قد تفاجئ مزامنة الخلفية المستخدمين.

إن لم يكن التطبيق حذرًا، قد يُرسَل نفس الإجراء مرتين (تكرارات)، أو قد يُكتب تغيير أحدث من الخادم فوق ما فعله المستخدم للتو (فقدان التعديلات). أحيانًا يظهر التطبيق حالات مربكة مثل "تم الحفظ" و"لم يتم الحفظ" في آن واحد، أو يظهر سجل ثم يختفي ثم يعود بعد المزامنة.

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

الهدف ليس جعل وضع عدم الاتصال مثاليًا. الهدف أن يجعله متوقعًا:

  • يمكن للناس الاستمرار في العمل دون الخوف من فقدان العمل.
  • تحدث المزامنة لاحقًا بدون تكرارات غامضة.
  • عندما يحتاج الأمر انتباهاً، يخبر التطبيق بوضوح بما حدث وماذا يجب فعله بعد ذلك.

هذا ينطبق سواءً كتبت التطبيق يدويًا في Kotlin/SwiftUI أو بنيته بأداة بدون كود مثل AppMaster. الجزء الصعب ليس عناصر واجهة المستخدم، بل تحديد سلوك التطبيق عندما يتغير العالم بينما المستخدم غير متصل.

نموذج بسيط لأفكار "أوفلاين-أول" (بدون مصطلحات معقدة)

تتوقع تطبيقات offline-first أن الهاتف سيفقد الشبكة أحيانًا، لكن ينبغي أن يظل التطبيق عمليًا. يجب أن تُحمّل الشاشات وتعمل الأزرار حتى عندما لا يكون الخادم متاحًا.

أربعة مصطلحات تغطي الجزء الأكبر:

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

نموذج ذهني مفيد هو فصل القراءة عن الكتابة.

القراءات عادةً بسيطة: عرض أفضل بيانات متاحة (غالبًا من التخزين المحلي)، ثم التحديث بهدوء عندما يعود الشبك.

الكتابات مختلفة. لا تعتمد على "حفظ السجل كاملًا" دفعة واحدة. هذا ينهار بمجرد أن تكون دون اتصال.

بدلًا من ذلك، سجّل ما فعله المستخدم كمدخلات صغيرة في سجل التغييرات. مثال: "ضبط الحالة إلى موافق"، "أضف تعليق X"، "غيّر الكمية من 2 إلى 3". كل مدخل يذهب إلى طابور المزامنة مع طابع زمني ومعرّف. المزامنة في الخلفية تحاول بعد ذلك توصيله.

يبقى المستخدم يعمل بينما تنتقل التغييرات من الحالة المعلقة إلى المتزامنة.

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

قرّر ما الذي يستحق دعم العمل دون اتصال فعلاً

يعطي مفهوم offline-first انطباعًا أن "كل شيء يعمل بدون اتصال"، لكن هذا الوعد يقود العديد من التطبيقات للمتاعب. اختر الأجزاء التي تستفيد فعلًا من وضع عدم الاتصال، واجعل الباقي واضحًا كـ"أونلاين فقط".

فكّر بحسب نية المستخدم: ماذا يحتاج الناس أن يفعلوه في قبو، على متن طائرة، أو في مستودع بشبكة ضعيفة؟ افتراض جيد هو دعم الإجراءات التي تنشئ أو تحدث الأعمال اليومية، ومنع الإجراءات التي تتطلب "حقيقة أحدث".

مجموعة عملية من الإجراءات الملائمة للعمل دون اتصال غالبًا تشمل إنشاء وتحرير السجلات الأساسية (ملاحظات، مهام، تفتيشات، تذاكر)، صياغة تعليقات، وإرفاق صور (مخزنة محليًا، تُرفع لاحقًا). الحذف ممكن كذلك، لكن أنسب كحذف ناعم مع نافذة تراجع حتى يؤكد الخادم.

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

حدّد توقعات حداثة البيانات. "دون اتصال" ليس ثنائيًا. عرّف مقدار قدم البيانات المسموح به: دقائق، ساعات، أو "عند فتح التطبيق التالي". ضع هذا القاعدة في واجهة المستخدم بكلمات بسيطة، مثل "آخر تحديث قبل ساعتين" و"المزامنة عند الاتصال".

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

إذا بنيت في AppMaster، يساعدك هذا القرار في نمذجة البيانات وقواعد العمل بحيث يخزن التطبيق مسودات آمنة دون اتصال بينما يبقي الإجراءات الخطرة متطلبات متصلة.

صمّم طابور المزامنة: ما الذي تحفظه لكل تغيير

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

اجعل الإجراءات صغيرة وبسيطة ومتماشية مع ما فعله المستخدم بالفعل:

  • إنشاء سجل
  • تحديث حقل/حقول محددة
  • تغيير حالة (إرسال، اعتماد، أرشفة)
  • حذف (من الأفضل كحذف ناعم حتى التأكيد)

الإجراءات الصغيرة أسهل في التتبع. إذا احتاج الدعم لمساعدة مستخدم، أسهل بكثير قراءة "غيّر الحالة من مسودة → مُرسلة" بدلاً من فحص قطعة JSON ضخمة.

لكل إجراء في الطابور، خزّن بيانات وصفية كافية لإعادة تشغيله بأمان واكتشاف التعارضات:

  • معرف السجل (ومعرف محلي مؤقت للسجلات الجديدة)
  • طابع زمني للإجراء ومعرّف الجهاز
  • النسخة المتوقعة (أو آخر وقت تحديث معروف) للسجل
  • الحمولة (الحقول المحدّثة، بالإضافة إلى القيمة القديمة إن أمكن)
  • مفتاح اللاتكرر (Idempotency key) — معرّف فريد للإجراء حتى لا تُنشأ تكرارات عند إعادة المحاولة

تلك النسخة المتوقعة هي مفتاح التعامل الصادق مع التعارضات. إذا تحرّكت نسخة الخادم، يمكنك الإيقاف وطلب قرار بدل الكتابة الصامتة فوق عمل الآخر.

بعض الإجراءات يجب تطبيقها معًا لأن المستخدم يراها خطوة واحدة. مثال: "إنشاء طلب" ثم "إضافة ثلاثة بنود" يجب أن تنجح أو تفشل كوحدة. خزّن معرّف مجموعة (أو معرّف صفقة) حتى يرسل محرك المزامنة المجموعة معًا ويلتزم بها كلها أو يبقيها كلها معلقة.

سواءً بنيت يدويًا أو في AppMaster، الهدف نفسه: كل تغيير يُسجل مرة، يُعاد تشغيله بأمان، ويمكن تفسيره عندما لا يطابق الواقع.

قواعد حل التعارضات التي يمكنك شرحها للمستخدمين

اجعل التعارضات متوقعة
أضف فحوصات للإصدارات وقواعد تعارض واضحة وقابلة للاختبار كعمليات أعمال.
ابدأ البناء

التعارضات أمر طبيعي. الهدف ليس جعلهامستحيلة، بل جعلها نادرة وآمنة وسهلة الشرح عند حدوثها.

سَمّ اللحظة التي يحدث فيها التعارض: يرسل التطبيق تغييرًا، فيرد الخادم: "هذه النسخة ليست التي بدأت تحريرها". لهذا السبب تهمّك النسخ.

احتفظ بقيمتين لكل سجل:

  • نسخة الخادم (الإصدار الحالي على الخادم)
  • النسخة المتوقعة (الإصدار الذي ظن الهاتف أنه كان يحرره)

إذا طابقت النسخة المتوقعة، اقبل التحديث وارتفع رقم إصدار الخادم. إن لم تطابق، طبّق قاعدة التعارض الخاصة بك.

اختر قاعدة لكل نوع بيانات (لا قاعدة واحدة لكل شيء)

أنواع البيانات المختلفة تحتاج قواعد مختلفة. حقل الحالة ليس مثل ملاحظة طويلة.

قواعد يفهمها المستخدمون عادةً:

  • آخر كتابة تفوز: مناسب للحقول منخفضة المخاطر مثل تفضيل العرض.
  • دمج الحقول: الأفضل عندما تكون الحقول مستقلة (الحالة مقابل الملاحظات).
  • اطلب رأي المستخدم: الأفضل للتعديلات عالية المخاطر مثل السعر، الصلاحيات، أو المبالغ الإجمالية.
  • الخادم يفوز مع نسخة محفوظة: احتفظ بقيمة الخادم، لكن خزّن تعديل المستخدم كمسودة يمكن إعادة تطبيقها.

في AppMaster، تتطابق هذه القواعد جيدًا مع المنطق البصري: تحقق من النسخ، قارن الحقول، ثم اختر المسار.

قرّر كيف تتصرف عمليات الحذف (وإلا ستفقد بيانات)

الحذف حالة معقّدة. استخدم حجرًا قبريًا (علامة "محذوف") بدلًا من إزالة السجل فورًا. ثم قرّر ماذا يحدث إذا عدّل شخص ما سجلًا حُذف في مكان آخر.

قاعدة واضحة: "الحذف يفوز، لكن يمكنك الاستعادة." مثال: مندوب مبيعات يعدّل ملاحظة عميل دون اتصال بينما يقوم مسؤول بحذف ذلك العميل. عند تشغيل المزامنة، يظهر للتطبيق: "تم حذف العميل. استعد لتطبيق ملاحظتك؟" هذا يتجنب فقدانًا صامتًا ويعطي السيطرة للمستخدم.

إعادة المحاولة وحالات الفشل: اجعلها متوقعة

عندما تفشل المزامنة، معظم المستخدمين لا يهتمون بالسبب. يهتمون إن كان عملهم آمنًا وماذا سيحدث بعد ذلك. نموذج حالات متوقع يمنع الذعر وتذاكر الدعم.

ابدأ بنموذج حالة مرئي بسيط واحتفظ به متسقًا عبر الشاشات:

  • مُدرج (Queued): محفوظ على الجهاز، ينتظر الشبكة
  • مزامنة (Syncing): يُرسل الآن
  • مُرسل (Sent): تم التأكيد من الخادم
  • فشل (Failed): لم يُرسل، سيتم إعادة المحاولة أو يحتاج انتباهًا
  • يحتاج مراجعة (Needs review): أُرسل لكن الخادم رفضه أو وضع عليه علامة

يجب أن تكون إعادة المحاولة لطيفة على البطارية والبيانات. ابدأ بمحاولات سريعة في البداية (لمعالجة سقوط الشبكة المؤقت)، ثم ابطئ. تراجع بسيط مثل: دقيقة، 5 دقائق، 15 دقيقة، ثم كل ساعة بسيط وسهل الفهم. وأعد المحاولة فقط عندما يكون ذلك منطقيًا (لا تستمر في إعادة المحاولة لتغيير غير صالح).

عامل الأخطاء بشكل مختلف، لأن الإجراء التالي يختلف:

  • دون اتصال / لا شبكة: ابقَ مُدرجًا، أعد المحاولة عند الاتصال
  • انقضاء المهلة / الخادم غير متاح: علّم كفشل، أعد المحاولة تلقائيًا بتراجعٍ زمني
  • انتهت صلاحية المصادقة: أوقف المزامنة واطلب من المستخدم تسجيل الدخول مجددًا
  • فشل التحقق (بيانات غير صالحة): يحتاج مراجعة، بيّن ما يجب إصلاحه
  • تعارض: يحتاج مراجعة، احلّطه حسب قواعد التعارض

اللاتكرارية (Idempotency) هي ما يجعل إعادة المحاولة آمنة. يجب أن يكون لكل تغيير معرّف إجراء فريد (غالبًا UUID) يُرسل مع الطلب. إذا أعاد التطبيق إرسال نفس التغيير، يجب أن يتعرّف الخادم على المعرف ويُرجع نفس النتيجة بدلًا من إنشاء تكرار.

مثال: فني يحفظ عملًا مكتملًا دون اتصال، ثم يدخل المصعد. يرسل التطبيق التحديث، يحصل على مهلة، ويُعيد المحاولة لاحقًا. مع معرف الإجراء، الإرسال الثاني آمن. بدونه قد تُنشأ أحداث "مكتمل" مكررة.

في AppMaster، عامل هذه الحالات والقواعد كحقول ومنطق أساسي في عملية المزامنة، حتى تتصرف تطبيقات Kotlin و SwiftUI بنفس الطريقة في كل مكان.

واجهة التغييرات المعلقة: ما يراه المستخدم وما يمكنه فعله

ابنِ طابور المزامنة بصريًا
نموذج طابور المزامنة وإعادة المحاولة باستخدام منطق بصري بدلًا من كود لاصق.
جرّب AppMaster

يجب أن يشعر الناس بالأمان عند استخدام التطبيق دون اتصال. واجهة "التغييرات المعلقة" الجيدة هادئة ومتوقعة: تقرّ أن العمل محفوظ على الجهاز، وتجعل الخطوة التالية واضحة.

مؤشر طفيف أفضل من لافتة تحذير. على سبيل المثال، أظهر أيقونة "مزامنة" صغيرة في العنوان، أو عبارة هادئة "3 معلّقون" على الشاشة حيث تحدث التعديلات. احفظ الألوان الصارخة للخطورة الحقيقية (مثل "لا يمكن الرفع لأنك خرجت من الحساب").

امنح المستخدم مكانًا واحدًا لفهم ما يحدث. شاشة Outbox أو التغييرات المعلقة يمكن أن تُدرج عناصر مع لغة بسيطة مثل "أُضيف تعليق إلى التذكرة 104" أو "تحديث صورة الملف الشخصي". تلك الشفافية تمنع الذعر وتقلل تذاكر الدعم.

ما الذي يمكن للمستخدمين فعله

معظم الناس يحتاجون إلى بضع إجراءات فقط، ويجب أن تكون متسقة في التطبيق:

  • إعادة المحاولة الآن
  • التعديل مجددًا (يُنشئ تغييرًا أحدث)
  • التخلّي عن التغيير المحلي
  • نسخ التفاصيل (مفيد عند الإبلاغ عن مشكلة)

اجعل تسميات الحالة بسيطة: Pending، Syncing، Failed. عند الفشل، فسّر السبب كما يتكلم الإنسان: "تعذّر الرفع. لا إنترنت." أو "مُرفض لأن هذا السجل تغيّر بواسطة شخص آخر." تجنّب رموز الأخطاء.

لا تُغلِق التطبيق كله

اقفل فقط الإجراءات التي تتطلب اتصالًا فعليًا، مثل "الدفع بواسطة Stripe" أو "دعوة مستخدم جديد". كل شيء آخر يجب أن يظل يعمل، بما في ذلك عرض البيانات الأخيرة وإنشاء المسودات.

تدفّق واقعي: فني ميداني يحرر تقرير عمل في قبو. يُظهر التطبيق "1 معلّق" ويتركه يستمر في العمل. لاحقًا يتحوّل إلى "مزامنة" ثم يختفي تلقائيًا. إذا فشل، يبقى التقرير متاحًا معنونا "فشل" مع زر "إعادة المحاولة الآن".

إذا بنيت في AppMaster، نمذج هذه الحالات كجزء من كل سجل (معلق، فشل، متزامن) حتى تعكس الواجهة ذلك في كل مكان دون شاشات استثنائية.

المصادقة والصلاحيات والأمان أثناء العمل دون اتصال

نشر الباك اند كما تريد
انشر تطبيقك حيث تحتاجه، من سحابة مُدارة إلى بنيتك التحتية الخاصة.
انشر في السحابة

وضع عدم الاتصال يغيّر نموذج الأمان لديك. يمكن للمستخدم اتخاذ إجراءات بدون اتصال، لكن الخادم يظل مصدر الحقيقة. عامل كل تغيير مُدرج كـ"مطلوب" وليس "مؤكد".

انتهاء صلاحية الدخول أثناء عدم الاتصال

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

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

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

تغييرات الصلاحيات والإجراءات الممنوعة

قد تتغير الصلاحيات أثناء عدم اتصال المستخدم. قد يصبح تعديلٌ كان مسموحًا به بالأمس ممنوعًا اليوم. عامل ذلك صراحةً:

  • أعد التحقق من الصلاحيات على الخادم لكل إجراء في الطابور
  • إذا كان محظورًا، أوقف ذلك العنصر وعرّف السبب بوضوح
  • احتفظ بتعديل المستخدم المحلي ليتمكن من نسخه أو طلب الوصول
  • تجنب إعادة المحاولة المتكررة لأخطاء "ممنوع"

مثال: وكيل دعم يحرر ملاحظة عميل دون اتصال خلال رحلة طيران. طوال الليل أُزيل دوره. عند المزامنة، يرفض الخادم التحديث. يجب أن يُظهر التطبيق "لا يمكن الرفع: لم يعد لديك صلاحية" ويحتفظ بالملاحظة كمسودة محلية.

البيانات الحساسة المخزّنة دون اتصال

خزن الحد الأدنى اللازم لعرض الشاشات وإعادة تشغيل الطابور. شفّر التخزين المحلي، تجنّب تخزين الأسرار، وحدد قواعد واضحة لتسجيل الخروج (مثال: مسح البيانات المحلية، أو الاحتفاظ بالمسودات بعد موافقة المستخدم الصريحة). إذا بنيت مع AppMaster، ابدأ بوحدة المصادقة وصمّم الطابور بحيث ينتظر دائمًا جلسة صالحة قبل إرسال التغييرات.

الأخطاء الشائعة التي تسبب فقدان العمل أو التكرارات

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

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

فخ آخر هو عاصفة إعادة المحاولة. عندما يستعيد الهاتف اتصالًا ضعيفًا، قد يبدأ التطبيق بمهاجمة الباك اند كل ثوانٍ، مستنزفًا البطارية ويخلق كتابات مكررة. يجب أن تكون إعادة المحاولات هادئة: ابطئ بعد كل فشل وأضِف قليلاً من العشوائية حتى لا تعيد آلاف الأجهزة المحاولة في نفس اللحظة.

الأخطاء التي تقود غالبًا لفقدان عمل أو تكرارات:

  • التعامل مع كل فشل كـ"شبكة": افصل بين الأخطاء الدائمة (بيانات غير صالحة، صلاحية مفقودة) والمؤقتة (مهلة).
  • إخفاء فشل المزامنة: إن لم يرَ الناس ما فشل، يعيدون العمل فينشئون سجلين.
  • إرسال نفس التغيير مرتين بدون حماية: أرفق دائمًا معرّف طلب فريد حتى يتعرف الخادم على التكرارات.
  • الدمج التلقائي لحقول النص دون إعلام أحد: إذا دمجت التعديلات تلقائيًا، دع المستخدم يراجع النتيجة عندما يهم الأمر.
  • إنشاء سجلات دون اتصال بدون معرف ثابت: استخدم معرفًا محليًا مؤقتًا وُطابقه بمعرّف الخادم بعد الرفع، حتى لا تنشأ نسخة ثانية لاحقًا.

مثال سريع: فني ميداني ينشئ "زيارة موقع" جديدة دون اتصال، ثم يحررها مرتين قبل إعادة الاتصال. إذا أعادت نداء الإنشاء نفسه مرتين وأنشأت سجلين على الخادم، قد تُربط التعديلات اللاحقة بالخطأ بالسجل الخطأ. المعرفات الثابتة و deduping على الخادم تمنع هذا.

إذا بنيت هذا في AppMaster، لا تتغير القواعد؛ الفرق هو أين تنفّذها: في منطق المزامنة، نموذج البيانات، والشاشات التي تعرض التغييرات "فشل" مقابل "مُرسلة".

سيناريو مثالي: شخصان يحرّران نفس السجل

اذهب للأصلي بدون إعادة كتابة
استخدم مخرجات Kotlin و SwiftUI الأصلية دون إعادة كتابة.
ابدأ الآن

فنية ميدانية، مايا، تُحدّث تذكرة "العمل #1842" في قبو بلا إشارة. تغيّر الحالة من "قيد التنفيذ" إلى "مكتمل" وتضيف ملاحظة: "تم استبدال الصمام، اختبرت التشغيل OK." يحفظ التطبيق فورًا ويُظهرها كمعلقة.

في الأعلى، زميلها ليو متصل ويحرر نفس العمل في نفس الوقت. يغيّر موعد الجدولة ويُعيّن العمل لفني آخر، لأن عميلًا اتصل لتحديث.

عند عودة إشارة مايا، تبدأ المزامنة في الخلفية بهدوء. هذا ما يحدث في تدفّق متوقع وودود للمستخدم:

  1. تغيير مايا ما زال في الطابور (معرف العمل، الحقول التي تغيّرت، الطابع الزمني، وإصدار السجل الذي رآه).
  2. يحاول التطبيق الرفع. يردّ الخادم: "هذا العمل تم تحديثه منذ الإصدار الذي لديك" (تعارض).
  3. تُشغّل قاعدة التعارض: الحالة والملاحظات تُدمج، أما تغييرات التعيين فتفوز إذا كانت أحدث على الخادم.
  4. يقبل الخادم نتيجة مدموجة: الحالة = "مكتمل" (من مايا)، تمت إضافة الملاحظة (من مايا)، والمعين = اختيار ليو (من ليو).
  5. يُعيد فتح العمل في تطبيق مايا مع شريط واضح: "تمت المزامنة مع تحديثات. تغيّر التعيين أثناء عدم اتصالك." زر "مراجعة" صغير يظهر ما تغيّر.

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

إن كانت هناك مشكلة تحقق (مثلاً، الحالة "مكتمل" تتطلب صورة)، لا يخمن التطبيق. يعلّم العنصر بأنه "يحتاج انتباهًا" ويخبرها بالضبط ماذا تضيف، ثم يتركها تعيد الإرسال.

منصات مثل AppMaster قد تساعد هنا لأنك تستطيع تصميم الطابور، قواعد التعارض، وحالة المسودات بصريًا، بينما تُصدر تطبيقات Kotlin و SwiftUI أصلية.

قائمة تحقق سريعة وخطوات تالية

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

قائمة تحقق قصيرة لتأكيد الأساس:

  • طابور المزامنة مخزن على الجهاز، وكل تغيير له معرف محلي ثابت بالإضافة إلى معرّف الخادم عند التوفر.
  • توجد حالات واضحة (مُدرج، مزامنة، مُرسل، فشل، يحتاج مراجعة) وتُستخدم بشكل متسق.
  • الطلبات لا تتكرر بأثر سيئ (idempotent)، وكل عملية تتضمن مفتاح لاتكرر.
  • السجلات لها نسخ (updatedAt، رقم مراجعة، أو ETag) حتى تُكشف التعارضات.
  • قواعد التعارض مكتوبة بلغة بسيطة (ماذا يفوز، ماذا يدمج، متى تسأل المستخدم).

بعد ذلك، تأكد أن التجربة بنفس قوة نموذج البيانات. يجب أن يرى المستخدم ما هو معلق، يفهم ما فشل، ويتخذ إجراءً دون الخوف من فقدان العمل.

اختبر بسيناريوهات تحاكي الحياة الواقعية:

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

نمذج التدفق كاملًا قبل تجميل الواجهة. ابنِ شاشة واحدة، نوع سجل واحد، وحالة تعارض واحدة (تعديلان لحقل واحد). أضف منطقة حالة مزامنة بسيطة، زر إعادة المحاولة للفشل، وشاشة تعارض واضحة. عندما ينجح ذلك، عدده للمزيد من الشاشات.

إذا بنيت بدون كود، AppMaster (appmaster.io) يمكنه توليد تطبيقات Kotlin و SwiftUI أصلية جنبًا إلى جنب مع الباك اند، حتى تركز على الطابور، فحوصات الإصدارات، وحالات الواجهة بدلًا من توصيل كل شيء يدويًا.

من السهل أن تبدأ
أنشئ شيئًا رائعًا

تجربة مع AppMaster مع خطة مجانية.
عندما تكون جاهزًا ، يمكنك اختيار الاشتراك المناسب.

البدء