ב-Media3 יש אופטימיזציות חדשות, שיפורים בהתנהגות ושיפורים בארכיטקטורה בכל הספריות. למרות שהשינויים האלה נבדקים ומאומתים ביסודיות לפני ההשקה, Media3 כולל תשתית ריכוזית של feature flags (androidx.media3.common.Flags) שמתמקדת במצב Canary כדי לתת לאפליקציות שליטה על האופן שבו הן מאמצות התנהגויות חדשות ומתי.
בדף הזה מוסבר איך פועלים מצב Canary ו-feature flags, ואיך אתם יכולים להשתמש בהם באפליקציה כדי לצמצם את הסיכונים בשדרוג בין גרסאות, להריץ השקות מבוקרות ולהגדיר החזרות למצב קודם במקרה חירום.
סקירה כללית
מצב Canary מקבץ שיפורים חדשים ומאומתים בספרייה, וכולל מתג גלובלי אחיד:
- מופעל כברירת מחדל: בגרסאות הרגילות של Media3, מצב Canary מופעל כברירת מחדל (
true). כך האפליקציה נהנית באופן אוטומטי משיפורים בביצועים, מאופטימיזציות ומיכולות חדשות. - יכולת ביטול וחזרה למצב הקודם: אפליקציות יכולות להשבית את מצב Canary באופן גלובלי או לשנות באופן ידני דגלי תכונות ספציפיים בזמן הריצה.
- אין צורך בחיווט מורכב: הדגלים מנוהלים דרך המחלקה המרכזית
Flagsבמודולcommon, כך שאין צורך במגדירים מותאמים אישית או באובייקטים של הגדרות אישיות ברכיבים שונים.
למה כדאי להשתמש ב-Flags באפליקציה?
מצב Canary מופעל כברירת מחדל, אבל שילוב של Flags עם ההגדרות או מסגרת הניסויים של האפליקציה מספק כמה יתרונות:
1. צמצום הסיכון בשדרוג גרסה
שדרוג של גרסאות ראשיות או משניות של ספרייה בסביבת הייצור עלול לגרום לאינטראקציות לא צפויות במכשירים ספציפיים של יצרני ציוד מקורי (OEM) או בצינורות עיבוד נתונים מותאמים אישית של מדיה. כשמעדכנים את 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
במקום לחשוף 100% מהמשתמשים להתנהגויות חדשות של הספרייה בבת אחת, אתם יכולים לחבר את Flags למערכת של הגדרת תצורה מרחוק או למערכת ניסויים.
אתם יכולים להפעיל את מצב Canary בשלבים (לדוגמה, 5% מהמשתמשים ← 25% ← 100%) או להריץ ניסויי A/B כדי למדוד את ההשפעה של אופטימיזציות חדשות על מדדי הפעלה עיקריים, כמו זמן אחזור בהפעלה, שיעור טעינה מראש של נתונים וכשלים בהפעלה.
3. מתג השבתה מרחוק והחזרה מהירה לגרסה קודמת
אם מתרחשת רגרסיה בסביבת הייצור בדגם מכשיר או בגרסת מערכת הפעלה מסוימים, אפשר להשבית מרחוק את מצב Canary (או את מזהה הדגל הספציפי שאחראי לכך) באמצעות הגדרה בצד השרת. הפעולה הזו מחזירה מיד את הספרייה להתנהגות היציבה והקודמת שלה כחלופה למשתמשים המושפעים, בלי צורך בתיקון מהיר (hotfix) של האפליקציה או בגרסה בינארית.
הגדרת מצב Canary ודגלים
Flags API מספק שיטות לשליטה במצב 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) או לפני שמפעילים את שכבת המדיה של האפליקציה. - Thread safety: רכיבי 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 לנתיבי קוד שמושפעים מ-feature flags, משתמשים ב-androidx.media3.test.utils.Media3FlagsRule (זמין במודול media3-test-utils) כדי לוודא שהבדיקות לא מזהמות את המצב הסטטי אחת של השנייה.
ניקוי אוטומטי באמצעות Media3FlagsRule
הוספת Media3FlagsRule מבטיחה שכל השינויים ב-Canary mode וביטולי הדגלים יאופסו אוטומטית אחרי כל בדיקה:
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 בכל הגרסאות.
- קידום וניקוי: אחרי תקופת הרצה שמוכיחה יציבות בסביבת הייצור, התכונה מקודמת להפעלה קבועה בספרייה, והקבוע של הדגל, נתיבי הקוד החלופיים והבדיקות המותנות מוסרים.
אם נתקלתם בבעיה ב-feature flag, דווחו עליה בIssue Tracker של AndroidX Media3 ב-GitHub כדי שהצוות יוכל לטפל בה לפני שהיא תהפוך לקבועה.