مقدمة: مشغل الوسائط "المعطل" على Android 12 والإصدارات الأحدث
\nتخيل: أنت تنشر تحديثًا لتطبيق المشغل أو عميل البودكاست الخاص بك بكل فخر. تمر بضعة أيام، وتظهر تعليقات غاضبة في قسم المراجعات: "بعد التحديث، توقفت الموسيقى عن التشغيل!"، "الأزرار على الشاشة المقفلة لا تعمل!"، "التطبيق يتعطل عند محاولة تشغيل مقطع!". يبدو مألوفًا؟ على الأرجح، واجهت ذلك الخطأ الذي يعذب آلاف المطورين حول العالم:
\nMediaSessionCompat: Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent\nهذه المشكلة هي واحدة من أكثر الأسئلة شيوعًا على Stack Overflow (عشرات الآلاف من المشاهدات)، وترتبط ارتباطًا مباشرًا بالتغييرات في Android 12 (مستوى API 31). الخبر السار: الإصلاح بسيط ولن يستغرق منك أكثر من 10 دقائق. في هذه المقالة، سنشرح أسباب الخطأ، والحل الصحيح بلغة Kotlin، وأفضل الممارسات لضمان عمل تطبيقك بسلاسة مرة أخرى.
\n\nلماذا يحدث الخطأ؟ فهم PendingIntent
\nلفهم جوهر المشكلة، عليك أن تتذكر كيف يعمل MediaSessionCompat. هذا المكون يسمح لتطبيقك بالتفاعل مع عناصر التحكم في الوسائط النظامية: أزرار سماعة الرأس، شاشة القفل، لوحة الإشعارات. للقيام بذلك، يقوم بإنشاء PendingIntent - وهو نوع من "الاستدعاء المؤجل" لخدمات النظام. يستخدم النظام هذا Intent لإخبار تطبيقك: "المستخدم ضغط على تشغيل/إيقاف مؤقت/التالي".
بدءًا من Android 12 (API 31)، شددت Google متطلبات الأمان لـ PendingIntent. في السابق، كان بإمكان المطورين عدم تحديد علامة FLAG_IMMUTABLE أو FLAG_MUTABLE، وكان النظام يستخدم افتراضيًا الخيار القابل للتغيير (mutable). الآن، يجب عليك تحديد ما إذا كان النظام يمكنه تغيير محتوى Intent الخاص بك بعد إنشائه بشكل صريح. إذا لم تفعل ذلك، فسيؤدي ذلك إلى تعطل التطبيق. Android 12+ ببساطة لن يسمح بإنشاء مثل هذا PendingIntent.
FLAG_IMMUTABLE مقابل FLAG_MUTABLE: ماذا تختار؟
\n- \n
- FLAG_IMMUTABLE (موصى به): لا يمكن تغيير Intent بعد إنشائه. هذا أكثر أمانًا، حيث لا يمكن للمهاجم استبدال البيانات. استخدم هذه العلامة في 90% من الحالات، بما في ذلك
MediaSessionCompat. \n - FLAG_MUTABLE: يمكن تغيير Intent. مطلوب فقط في حالات خاصة، على سبيل المثال، إذا كنت تستخدم
NotificationCompatمع إجراءات تتطلب بيانات ديناميكية، أو عند العمل معAlarmManager. \n
بالنسبة لـ MediaSessionCompat وإشعارات الوسائط، استخدم دائمًا FLAG_IMMUTABLE. هذا يعزز أمان واستقرار تطبيقك.
الإصلاح خطوة بخطوة بلغة Kotlin
\nدعنا نرى كيف يبدو الكود النموذجي الذي يسبب الخطأ، وكيفية إصلاحه. غالبًا ما تظهر المشكلة في طريقة onCreate() الخاصة بالخدمة أو متصفح الوسائط الخاص بك.
الكود الخاطئ (سيؤدي إلى تعطل على Android 12+)
\n// الطريقة القديمة - بدون تحديد علامة\nval pendingIntent = PendingIntent.getActivity(\n this,\n 0,\n Intent(this, MainActivity::class.java),\n 0 // <-- خطأ! لا يوجد FLAG_IMMUTABLE أو FLAG_MUTABLE\n)\n\nالكود الصحيح بلغة Kotlin (الإصلاح)
\nما عليك سوى إضافة PendingIntent.FLAG_IMMUTABLE في المعامل الأخير:
val pendingIntent = PendingIntent.getActivity(\n this,\n 0,\n Intent(this, MainActivity::class.java),\n PendingIntent.FLAG_IMMUTABLE // <-- الحل!\n)\nإذا كان تطبيقك يدعم إصدارات أقدم من Android (أقل من API 31)، استخدم فحصًا شرطيًا لتجنب التعطل على الأجهزة القديمة:
\nval flags = if (Build.VERS