توفّر Media3 تحسينات جديدة على مستوى الأداء والسلوك والبنية في جميع مكتباتها. على الرغم من أنّ هذه التغييرات يتم اختبارها والتحقّق منها بدقة قبل إصدارها، تتضمّن Media3 بنية أساسية مركزية لعلامات الميزات (androidx.media3.common.Flags) تتمحور حول وضع Canary لمنح التطبيقات إمكانية التحكّم في كيفية اعتماد السلوكيات الجديدة وموعدها.
توضّح هذه الصفحة آلية عمل وضع Canary وعلامات الميزات، وكيفية استخدامها في تطبيقك لتقليل مخاطر الترقية في جميع الإصدارات، وتنفيذ عمليات طرح خاضعة للرقابة، وضبط عمليات العودة إلى الإصدارات السابقة في حالات الطوارئ.
نظرة عامة
يجمع وضع Canary تحسينات المكتبة التي تم التحقّق منها والتي تم تقديمها حديثًا ضمن مفتاح تبديل عام وموحّد:
- مفعَّل تلقائيًا: في إصدارات Media3 العادية، يكون وضع Canary مفعَّلاً تلقائيًا (
true). يضمن ذلك استفادة تطبيقك تلقائيًا من تحسينات الأداء الآمنة والتحسينات والإمكانات الجديدة. - إمكانية الإيقاف والعودة إلى الإصدار السابق: يمكن للتطبيقات إيقاف وضع Canary على مستوى العالم أو إلغاء علامات ميزات معيّنة بشكل فردي أثناء التشغيل.
- بساطة مطلقة في الربط: تتم إدارة العلامات من خلال فئة
Flagsالمركزية في وحدةcommon، ما يلغي الحاجة إلى أدوات ضبط مخصّصة أو عناصر ضبط في المكوّنات المختلفة.
ما هي مزايا استخدام ميزة "الإشارات" في تطبيقك؟
على الرغم من أنّ وضع Canary يكون مفعَّلاً تلقائيًا، فإنّ دمج Flags مع إعدادات تطبيقك أو إطار عمل التجربة يوفّر العديد من المزايا:
1. الحدّ من مخاطر ترقية الإصدار
قد تؤدي ترقية إصدارات المكتبة الرئيسية أو الثانوية في مرحلة الإنتاج إلى حدوث تفاعلات غير متوقعة على أجهزة معيّنة تابعة للمصنّع الأصلي للجهاز أو مسارات وسائط مخصّصة. عند تحديث Media3، يمكنك استخدام وضع Canary والإعداد عن بُعد لضمان عملية ترقية أكثر أمانًا عبر الإصدارات:
- طرح التحديث مع إيقاف وضع Canary: يؤدي طرح إصدار جديد من Media3 مع إيقاف وضع Canary إلى الحفاظ على مجموعة الخصائص في الإصدار السابق (مع تفعيل Canary)، ما يتيح لك التحقّق من استقرار المكتبة الأساسية وإصلاح الأخطاء العامة في مرحلة الإنتاج قبل اعتماد سلوكيات جديدة.
- تفعيل وضع Canary تدريجيًا: استخدِم ميزة "الإعداد عن بُعد" لتفعيل وضع Canary على مراحل في مجموعات المستخدمين (على سبيل المثال، 5% ← 25% ← 100%) أو نفِّذ تجارب A/B لقياس تأثير المقاييس.
- التراجع عن التغييرات إذا لزم الأمر: في حال حدوث تراجع في الأداء على أجهزة معيّنة، يمكنك إيقاف وضع Canary أو معرّف العلامة المحدّد عن بُعد بدون الحاجة إلى إصدار تطبيق طارئ.
- الاعتماد كإعداد تلقائي: بعد التحقّق من الميزات، يمكنك ترك وضع Canary مفعَّلاً تلقائيًا حتى الترقية إلى الإصدار التالي، حيث تصبح ميزات Canary التي تم التحقّق منها سابقًا دائمة.
Kotlin
// Enable or disable Canary mode globally (defaults to true). Flags.setCanaryModeEnabled(false)
Java
// Enable or disable Canary mode globally (defaults to true). Flags.setCanaryModeEnabled(false);
2. الإصدارات المرحلية الخاضعة للتحكّم واختبارات A/B
بدلاً من تعريض جميع المستخدمين لسلوكيات المكتبة الجديدة دفعة واحدة، يمكنك ربط Flags بنظام إعداد عن بُعد أو نظام تجريبي.
يمكنك تفعيل وضع Canary على مراحل (مثلاً، 5% من المستخدمين ← 25% ← 100%) أو إجراء تجارب A/B لقياس تأثير التحسينات الجديدة على مقاييس التشغيل الأساسية، مثل وقت الاستجابة لبدء التشغيل ومعدّل إعادة التخزين المؤقت وأخطاء التشغيل.
3- ميزة "إيقاف التشغيل عن بُعد" و"العودة السريعة إلى الإصدار السابق"
في حال حدوث تراجع في مرحلة الإنتاج على طراز جهاز معيّن أو إصدار نظام تشغيل معيّن، يمكنك إيقاف وضع Canary عن بُعد (أو رقم تعريف العلامة المحدّدة المسؤولة) باستخدام الإعدادات من جهة الخادم. يؤدي ذلك إلى إعادة المكتبة فورًا إلى سلوكها الاحتياطي القديم والمستقر للمستخدمين المتأثرين بدون الحاجة إلى إصدار عاجل أو إصدار ثنائي للتطبيق.
ضبط وضع Canary والعلامات
توفّر واجهة برمجة التطبيقات Flags طرقًا للتحكّم في وضع Canary العام
وعمليات إلغاء العلامات الفردية.
وضع Canary العام
لتفعيل أو إيقاف جميع التحسينات التي يغطيها "وضع Canary"، اتّبِع الخطوات التالية:
Kotlin
// Enable or disable Canary mode globally (defaults to true). Flags.setCanaryModeEnabled(false)
Java
// Enable or disable Canary mode globally (defaults to true). Flags.setCanaryModeEnabled(false);
تجاوز العلامات الفردية
يمكنك أيضًا تفعيل أو إيقاف علامات معيّنة بشكل صريح وبشكل مستقل عن إعداد وضع Canary العام:
Kotlin
// Explicitly enable an experimental flag. Flags.enableFlag(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION) // Explicitly disable a flag. Flags.disableFlag(Flags.FLAG_DYNAMIC_SCHEDULING)
Java
// Explicitly enable an experimental flag. Flags.enableFlag(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION); // Explicitly disable a flag. Flags.disableFlag(Flags.FLAG_DYNAMIC_SCHEDULING);
تحظى عمليات الإلغاء الصريحة دائمًا بالأولوية على الإعداد التلقائي العام لوضع Canary.
جارٍ التحقّق من حالة الإبلاغ
للتحقّق مما إذا كان وضع Canary أو علامة معيّنة نشطَين في الرمز البرمجي:
Kotlin
// Query whether Canary mode is active globally. val isCanaryActive = Flags.isCanaryModeEnabled() // Query whether a specific flag is active. val isFeatureActive = Flags.isEnabled(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION)
Java
// Query whether Canary mode is active globally. boolean isCanaryActive = Flags.isCanaryModeEnabled(); // Query whether a specific flag is active. boolean isFeatureActive = Flags.isEnabled(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION);
ترتيب حلّ المشاكل المتعلّقة بالعلامات
عندما تتحقّق Media3 من تفعيل ميزة معيّنة في وقت التشغيل، يتم تحديد الحالة بالترتيب التالي:
- التجاوز الصريح لوقت التشغيل: إذا تم استدعاء
enableFlagأوdisableFlagلرقم تعريف العلامة، يتم عرض قيمة التجاوز هذه. - حالة المكتبة الثابتة: إذا تم إيقاف الميزة التجريبية بشكل ثابت (على سبيل المثال، ميزة في مرحلة التطوير المبكر لم تصبح جاهزة بعد لوضع Canary) أو تم تفعيلها بشكل ثابت (ميزة تم نقلها من وضع Canary مع الاحتفاظ بخيار الإيقاف المؤقت الاحتياطي)، يتم عرض هذه القيمة الثابتة.
- حالة وضع Canary: في الحالات الأخرى، يتّبع الإعداد العام لوضع Canary (يتم تفعيله إذا كان وضع Canary مضبوطًا على
true، ويتم إيقافه إذا كان مضبوطًا علىfalse).
متطلبات الإعداد
اضبط العلامات قبل إنشاء أي مكوّنات في Media3 (مثل
ExoPlayer أو Transformer أو MediaSession):
- الإعداد المبكر: يمكنك ضبط
Flagsأثناء بدء تشغيل التطبيق (على سبيل المثال، داخلApplication.onCreate) أو قبل بدء تشغيل طبقة الوسائط في تطبيقك. - أمان سلاسل المحادثات: تقرأ مكوّنات Media3 العلامات أثناء إنشاء مثيل لها وتنشر هذه القيم في سلاسل المحادثات الداخلية للتشغيل والمعالجة. يجب التأكّد من ضبط العلامات قبل إنشاء مكوّنات Media3. لا يمكن تعديل علامات أثناء تشغيل المشغّلات أو المحوّلات بشكل نشط.
الدمج مع الإعداد عن بُعد
ننصحك باستخدام بنية تعرض ثلاث مَعلمات في منصة الإعداد عن بُعد:
-
media3_canary_mode_enabled(قيمة منطقية): زر تبديل عام لوضع Canary (القيمة التلقائية هيtrue) -
media3_force_enable_flags(قائمة أعداد صحيحة): معرّفات علامات معيّنة يتم فرض تفعيلها للتجارب المستهدَفة. -
media3_force_disable_flags(قائمة أعداد صحيحة): معرّفات علامات معيّنة يتم إيقافها نهائيًا في حال اكتشاف مشكلة
طبِّق هذه القيم أثناء بدء التشغيل قبل إنشاء نُسخ من المشغّل:
Kotlin
fun initializeMedia3Flags( canaryModeEnabled: Boolean, forceEnabledFlags: List<Int>, forceDisabledFlags: List<Int>, ) { // 1. Set global Canary mode state. Flags.setCanaryModeEnabled(canaryModeEnabled) // 2. Apply explicit force-enable overrides. for (flagId in forceEnabledFlags) { Flags.enableFlag(flagId) } // 3. Apply explicit force-disable overrides (remote kill switch). for (flagId in forceDisabledFlags) { Flags.disableFlag(flagId) } }
Java
public static void initializeMedia3Flags( boolean canaryModeEnabled, List<Integer> forceEnabledFlags, List<Integer> forceDisabledFlags) { // 1. Set global Canary mode state. Flags.setCanaryModeEnabled(canaryModeEnabled); // 2. Apply explicit force-enable overrides. for (int flagId : forceEnabledFlags) { Flags.enableFlag(flagId); } // 3. Apply explicit force-disable overrides (remote kill switch). for (int flagId : forceDisabledFlags) { Flags.disableFlag(flagId); } }
الاختبار باستخدام العلامات
عند كتابة اختبارات الوحدة أو اختبارات Robolectric للمسارات البرمجية المتأثرة بعلامات الميزات، استخدِم androidx.media3.test.utils.Media3FlagsRule (المتوفّر في وحدة media3-test-utils) لضمان عدم تداخل الاختبارات مع الحالة الثابتة لبعضها البعض.
التنظيف التلقائي باستخدام Media3FlagsRule
تضمن إضافة Media3FlagsRule إعادة ضبط جميع عمليات إلغاء العلامات وتعديلات وضع Canary تلقائيًا بعد كل اختبار:
Kotlin
class MyPlayerTest { @get:Rule val flagsRule = Media3FlagsRule(this) @Test fun playback_withFeatureFlagEnabled() { Flags.enableFlag(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION) // Run test with the flag enabled... } }
Java
public static class MyPlayerTest { @Rule public final Media3FlagsRule flagsRule = new Media3FlagsRule(this); @Test public void playback_withFeatureFlagEnabled() { Flags.enableFlag(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION); // Run test with the flag enabled... } }
الاختبار المستند إلى معلَمات
يمكنك دمج التعليقات التوضيحية Media3FlagsRule مع @BindFlag و@BindCanaryMode لإجراء اختبارات ذات مَعلمات على مستوى حالات العلامات:
Kotlin
class MyParameterizedPlayerTest { @BindCanaryMode var canaryMode: Boolean = false @BindFlag(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION) var perStreamProgression: Boolean = false @get:Rule val flagsRule = Media3FlagsRule(this) @Test fun playback() { // Flags are automatically set for each test parameter combination. } }
Java
public static class MyParameterizedPlayerTest { @BindCanaryMode public boolean canaryMode; @BindFlag(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION) public boolean perStreamProgression; @Rule public final Media3FlagsRule flagsRule = new Media3FlagsRule(this); @Test public void playback() { // Flags are automatically set for each test parameter combination. } }
بيانات التشخيص والتسجيل
توفّر Media3 أدوات تشخيص للتحقّق من العلامات النشطة وحالات وضع Canary أثناء بدء التشغيل وفي وقت التشغيل.
سجلّات الإعداد
عند إعداد مثيل ExoPlayer، تتم طباعة حالة Canary النشطة وأي عمليات إلغاء صريحة في logcat إلى جانب إصدار المكتبة:
ExoPlayerImpl: Init 59a18ab [AndroidXMedia3/1.10.1] [flame, Pixel 4, Google, 33] [Canary:ON]
إذا كانت عمليات الإلغاء نشطة، يتم إدراج الانحرافات عن الحالة التلقائية فقط:
ExoPlayerImpl: Init 59a18ab [AndroidXMedia3/1.10.1] [flame, Pixel 4, Google, 33] [Canary:ON, Overrides: enabled=[1], disabled=[3]]
الفحص الآلي
يمكنك استرداد سلسلة بيانات التشخيص المنسَّقة أو قوائم إلغاء طلبات البحث برمجيًا (على سبيل المثال، لتضمين حالة العلامة في تقارير الأعطال أو الإحصاءات الخاصة بتطبيقك):
Kotlin
// Get formatted string representing active Canary state and overrides. val flagLogString = Flags.getLogString() // Query explicit override IDs if needed. val enabledFlags = Flags.getEnabledOverrides() val disabledFlags = Flags.getDisabledOverrides()
Java
// Get formatted string representing active Canary state and overrides. String flagLogString = Flags.getLogString(); // Query explicit override IDs if needed. int[] enabledFlags = Flags.getEnabledOverrides(); int[] disabledFlags = Flags.getDisabledOverrides();
مراحل نشاط الإبلاغ
تم تصميم العلامات في Media3 لتكون مؤقتة:
- التطوير: تتم إضافة تحسين أو ميزة جديدة خلف رقم تعريف علامة في
Flags.java. - وضع Canary: بعد التحقّق من الميزة والتأكّد من جاهزيتها للاستخدام العام، يتم تفعيلها في وضع Canary في جميع الإصدارات.
- الترقية والتنظيف: بعد فترة اختبار تثبت استقرار الميزة في بيئة الإنتاج، تتم ترقيتها لتصبح مفعَّلة بشكل دائم في المكتبة، وتتم إزالة الثابت الخاص بالعلامة ومسارات الرموز الاحتياطية وعمليات التحقّق الشرطية.
إذا واجهت مشكلة في علامة ميزة، يُرجى إرسال تقرير على أداة تتبُّع المشاكل في AndroidX Media3 على GitHub ليتمكّن الفريق من معالجتها قبل الترقية الدائمة.