تعطل التطبيق — إنهاء غير طبيعي حيث يتوقف البرنامج عن الاستجابة ويُغلق. في تطوير التطبيقات المحمولة، تُعتبر الأعطال المصدر الرئيسي للمراجعات السلبية وانخفاض التقييم. وفقًا لـ Firebase (2024)، يقوم المستخدمون بحذف التطبيق بعد تعطل واحد أو اثنين في 53% من الحالات. كل تعطل يقلل الاحتفاظ بنسبة 3–5%. تساعد أنظمة المراقبة مثل Crashlytics و Sentry في العثور على أسباب الأعطال وإصلاحها بسرعة قبل أن تؤثر على أعداد كبيرة من المستخدمين.
الوجبات الرئيسية
التعطل — إنهاء غير متوقع للبرنامج ناتج عن حالة استثنائية لم يعالجها الكود. في أنظمة التشغيل المحمولة، يؤدي التعطل إلى إغلاق فوري للتطبيق وظهور شاشة “التطبيق متوقف” أو العودة إلى الشاشة الرئيسية.
تنقسم الأعطال إلى فئتين رئيسيتين. الأخطاء المعالجة — تلتقط كتل try/catch الاستثناء، ويستمر التطبيق في العمل، مع احتمال فقدان بعض الوظائف. الأعطال غير المعالجة — يصعد الاستثناء إلى مستوى نظام التشغيل، ويقوم النظام بقتل العملية. النوع الثاني خطير بشكل خاص لأن المستخدم لا يستطيع حفظ البيانات.
نظام بمليوني مستخدم ونسبة تعطل 0.1% يفقد 2,000 مستخدم في كل إصدار. وفقًا لـ Google Play Console (2024)، يتم استبعاد التطبيقات التي تزيد نسبة تعطلها عن 1.5% من التوصيات وتفقد ما يصل إلى 30% من حركة المرور العضوية.
NullPointerException (NPE) — ملك الأعطال في Java/Kotlin. محاولة استدعاء دالة على كائن فارغ. في Kotlin، يكون NPE أقل شيوعًا بفضل أمان القيم الفارغة (null safety)، لكنه لا يزال ممكنًا عند استخدام عامل !! أو التفاعل مع كود Java. تقدّر Google (2024) أن NPE يمثل 25% من جميع أعطال تطبيقات Android.
IndexOutOfBoundsException — الوصول إلى عنصر قائمة بفهرس غير موجود. سبب شائع: تصل البيانات من الخادم بتنسيق غير متوقع، وتحاول واجهة المستخدم عرض موضع غير موجود. الحل — تحقق دائمًا من حجم المجموعة قبل الوصول بالفهرس.
ANR (Application Not Responding) — مشكلة خاصة بنظام Android. يتم حظر سلسلة واجهة المستخدم لأكثر من 5 ثوانٍ. الأسباب الرئيسية: طلبات الشبكة في السلسلة الرئيسية، الحسابات الثقيلة، المزامنة مع قاعدة البيانات. StrictMode في Android يساعد في اكتشاف حظر سلسلة واجهة المستخدم أثناء التطوير.
OutOfMemoryError (OOM) — تجاوز التطبيق حد الذاكرة. على الأجهزة المحمولة ذات ذاكرة وصول عشوائي 2–4 جيجابايت، يعتبر OOM مشكلة شائعة عند العمل مع الصور الكبيرة أو القوائم اللانهائية دون ترقيم الصفحات. الحل — Glide/Coil لتحميل الصور، LruCache للتخزين المؤقت، ViewHolder في RecyclerView.
استثناءات وقت التشغيل — أخطاء لا يتحقق منها المترجم أثناء البناء. تظهر فقط عند تشغيل الكود على جهاز معين ببيانات محددة. في Java، هذه هي RuntimeException وفئاتها الفرعية: NullPointerException، IllegalArgumentException، ArithmeticException.
الأخطاء القاتلة (FATAL) — ليست أخطاء وقت تشغيل، بل أعطال نظامية. Signal 11 (SIGSEGV) — انتهاك تجزئة الذاكرة في الكود الأصلي. Signal 6 (SIGABRT) — إنهاء غير طبيعي ناتج عن التطبيق نفسه عبر abort(). يصعب تشخيص هذه الأعطال لأن تتبع المكدس غالبًا لا يُظهر سياقًا واضحًا.
في iOS، الأسباب الرئيسية هي NSInvalidArgumentException (قيمة فارغة غير متوقعة في معامل) و EXC_BAD_ACCESS (الوصول إلى ذاكرة محررة). قلّص Swift عدد الأعطال مقارنة بـ Objective-C، لكن الأخطاء في وقت تشغيل ObjC ومكتبات C لا تزال تؤدي إلى الأعطال.
Firebase Crashlytics — المعيار للتطبيقات المحمولة. يجمع تلقائيًا تتبعات المكدس، ويضيف سجلات ومعرفات المستخدم وبيانات الجهاز. يُجمّع الأعطال حسب التوقيع (فئة الخطأ + السطر). التنبيهات في الوقت الفعلي — إشعارات عندما تتجاوز نسبة الأعطال حدًا معينًا (مثلاً >0.1% في الساعة).
Sentry — بديل بإمكانيات أكثر مرونة. يسمح بإنشاء سياقات مخصصة، وإضافة فتات الخبز (الأحداث السابقة)، وتكوين التصفية داخل التطبيق لاستبعاد الأخطاء غير المهمة. خرائط المصدر لـ Kotlin و Swift تسمح برؤية الكود المصدري بدلاً من الأسماء المبهمة.
أفضل الممارسات للسجلات: أرسل البيانات الوصفية الرئيسية قبل تنفيذ عملية خطيرة — بهذه الطريقة سيظهر في السجل ما كان يفعله المستخدم قبل التعطل. أضف مفاتيح مخصصة (رقم إصدار API، آخر شاشة، حجم بيانات الإدخال). هذا يحول تتبع المكدس عديم الفائدة إلى معلومات قابلة للتنفيذ.
class PaymentViewModel : ViewModel() {
fun processPayment(amount: Double) {
crashlytics.setCustomKey("last_screen", "payment")
crashlytics.setCustomKey("amount", amount)
try {
api.charge(amount)
} catch (e: Exception) {
crashlytics.recordException(e)
}
}
}
الربط الاختياري وأمان القيم الفارغة — في Kotlin استخدم `?` للأنواع القابلة للقيم الفارغة، و `let` و `?:` للمعالجة الآمنة للقيم الفارغة. في Swift — الخيارات و guard let. Kotlin الحديث (2024) أضاف تعليقات Contract: `@ContractsDsl` يسمح بتعريف أن الدالة لا تُرجع قيمة فارغة، ويتحقق المترجم من ذلك.
معالجة الأخطاء في الشبكة — يجب أن يعالج كل طلب شبكة المهلة وأخطاء التحليل وفشل الخادم. Retrofit مع نوع Result — فئة مختومة تضمن معالجة الخطأ. نمط بدون استثناء: بدلاً من try/catch، استخدم Result مختوم للمعالجة الصريحة للنجاح والخطأ.
مفاتيح الميزات — عطّل الوظائف الإشكالية عن بُعد دون إصدار نسخة جديدة. إذا كانت عملية من الخادم تسبب تعطلاً على الأجهزة القديمة، يقوم المفتاح بتعطيلها لهذه المجموعة. Firebase Remote Config يسمح بتغيير سلوك التطبيق دون النشر في المتجر.
الطرح التدريجي — أطلق نسخة جديدة إلى 5% من الجمهور وراقب نسبة الأعطال. إذا بقيت النسبة أقل من الهدف (عادة <0.1%)، وسّع إلى 25%، ثم 50%، ثم 100%. Google Play Console و App Store Connect يدعمان الطرح المتدرج للإيقاف التلقائي عند تجاوز الحد.
الخطوة 1: التصنيف — حدد الخطورة: حرج (تعطل في >1% من المستخدمين)، عالٍ (0.1–1%)، متوسط (<0.1%). للأعطال الحرجة — استجابة فورية. للباقي — عملية إصلاح الأخطاء القياسية في السباق الحالي. Google Play Console يصنف الأعطال تلقائيًا حسب عدد المستخدمين المتأثرين.
الخطوة 2: تحليل تتبع المكدس — افتح السجل في Crashlytics، واطلع على موقع التعطل الدقيق. تحقق من المفاتيح المخصصة: أي شاشة، أي بيانات، إصدار نظام التشغيل. اربط مع آخر نشر — غالبًا ما يكون التعطل ناتجًا عن تغيير حديث في الكود أثر على سيناريو استخدام غير متوقع.
الخطوة 3: إعادة الإنتاج — حاول إعادة إنتاج التعطل على جهاز أو محاكٍ بمعايير مماثلة. إذا لم تنجح، تحقق من سجل التعطل بحثًا عن أنماط: طرازات محددة (Samsung A10)، إصدارات Android (API < 26)، الإعدادات المحلية. الحل — أضف شرطًا دفاعيًا يغطي السيناريو.
الخطوة 4: الإصلاح والمراقبة — أطلق إصلاحًا عاجلاً بأولوية. بعد الإصدار، تأكد من أن نسبة الأعطال لهذا النوع تنخفض إلى الصفر. اكتب اختبار تراجع يغطي سيناريو التعطل. بدون اختبار، قد يعود نفس الخطأ في إعادة الهيكلة التالية.
الأسئلة الشائعة
نسبة التعطل الطبيعية — أقل من 0.1% لإصدارات الإنتاج. توصي Google Play بالحفاظ على نسبة التعطل أقل من 1.5%، لكن التطبيقات الرائدة (YouTube، Instagram) تحافظ على 0.01–0.05%. للإصدارات ذات الوظائف الجديدة، يُسمح بزيادة مؤقتة إلى 0.5% مع انخفاض لاحق بعد الإصلاح العاجل.
التعطل — التطبيق ينتهي بشكل غير طبيعي. ANR (Application Not Responding) — التطبيق يتجمد لأكثر من 5 ثوانٍ لكنه لا يُغلق قسرًا. يرى المستخدم حوار “التطبيق لا يستجيب” ويمكنه الانتظار أو الإغلاق. مشاكل ANR لا تقل خطورة عن الأعطال وتؤثر أيضًا على التقييم في المتجر.
الأجهزة المختلفة لها إصدارات نظام تشغيل مختلفة، وحجم ذاكرة، وإصدارات مكتبات، وحتى معالجات. مثال: تعطل على Android 6 (API 23) بسبب عدم وجود إذن وقت التشغيل قد لا يتكرر على Android 12. حلل سجل التعطل حسب الفلاتر: إصدار نظام التشغيل، طراز الجهاز، حجم ذاكرة الوصول العشوائي. سيشير هذا إلى خصوصية المشكلة.
أضف فتات الخبز المخصصة في Crashlytics: سجل الأحداث الرئيسية قبل تنفيذ العملية. إذا حدث التعطل في الخطوة 3 من الإعداد، فهذا يشير إلى مشكلة في شاشة محددة. رموز التصحيح (dSYM، ProGuard mapping) — حملها دائمًا إلى Crashlytics لرؤية أسماء الدوال الحقيقية بدلاً من المبهمة.
في الإنتاج — أبدًا. التعطل غير المعالج يضعف تجربة المستخدم. استخدم try/catch مع تسجيل الأخطاء. في وضع التصحيح، يُسمح بالتعطل لتقديم ملاحظات سريعة للمطور. التأكيدات — للتحقق من الثوابت التي لا يجب أن تُنتهك أبدًا، ولكن فقط في إصدارات التصحيح.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.