מצב תאימות מכשיר

מערכת Android מפעילה מצב תאימות לאפליקציות שמצהירות על הגבלות לגבי כיוון או שינוי גודל. מצב תאימות מבטיח התנהגות מקובלת של האפליקציה במכשירים עם מסך גדול ובטלפונים מתקפלים, אבל עם שימושיות לא אופטימלית.

החלפות ברמת האפליקציה מאפשרות ליצרני מכשירים, לבעלי מכשירים וירטואליים1 ולמשתמשים לשנות את התנהגות האפליקציה כדי לשפר את הפריסה שלה או כדי למנוע שהיא תיפגע במכשירים נבחרים.

Android 16

‫Android 16 (רמת API‏ 36) מתעלמת מהגבלות על כיוון המסך, יחס הגובה-רוחב ושינוי הגודל של האפליקציה כדי לשפר את הפריסה של אפליקציות בגורמי צורה עם רוחב מינימלי של ‎600dp ומעלה.

ההגדרות הבאות לשינוי ברירת המחדל של כל אפליקציה לא פועלות באפליקציות שמטרגטות לרמת API‏ 36:

ביטול ההסכמה

האפליקציה יכולה להיות מיועדת לרמת API‏ 36, אבל לא להשתמש בהתנהגות של Android 16. במקרה כזה, ההרשאה OVERRIDE_ANY_ORIENTATION_TO_USER לא רלוונטית.

הצהרה על מאפיין במניפסט

כדי לבטל את ההסכמה להתנהגות של API ברמה 36, מגדירים את מאפיין המניפסט PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY.

כדי לבטל את ההסכמה לפעילות ספציפית, מגדירים את המאפיין ברכיב <activity>:

<activity ...>
    <property
        android:name="android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY"
        android:value="true" />
    ...
</activity>

כדי לבטל את ההסכמה לכל האפליקציה, מגדירים את המאפיין ברכיב <application>:

<application ...>
    <property
        android:name="android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY"
        android:value="true" />
    ...
</application>

מכשירים להתייחסות

יכול להיות שבמכשירים הבאים יהיה צורך בשינוי הגדרות לכל אפליקציה בנפרד, בגלל תצורות לא רגילות או תצורות שלא נתמכות היטב באפליקציות:

  • טאבלטים: האוריינטציה הטבעית של חלק מהטאבלטים, כמו Pixel Tablet, היא לרוחב. מכשיר נמצא בכיוון הטבעי שלו כשערך ההחזרה של Display#getRotation() הוא Surface.ROTATION_0. אם האפליקציות מניחות ש-ROTATION_0 הוא מצב אנכי, יכול להיות שפריסות האפליקציות ותצוגת המצלמה המקדימה לא יתאימו לתצוגת המכשיר.
  • מכשירים מתקפלים לרוחב: חלק מהמכשירים המתקפלים, כמו Pixel Fold, נמצאים במצב אנכי כשהם מקופלים, אבל במצב אופקי כשהם פתוחים. אם האפליקציות מניחות שהכיוון כשהמסך פתוח הוא לאורך, סביר להניח שיופיעו לולאות של הבהובים או בעיות בפריסה.
  • טלפונים מתקפלים: טלפונים מתקפלים פתוחים הם בדרך כלל במצב אנכי. אבל כשהטלפונים מקופלים, בדרך כלל יש להם מסך קטן במצב אופקי. האפליקציות צריכות לזהות את כיווני המסך השונים ולהתאים את עצמן אליהם.
  • מסכים חיצוניים: במכשירים נבחרים אפשר להפעיל סשן של חלונות בשולחן העבודה במסכים חיצוניים ומחוברים. אפליקציות צריכות לשלוח שאילתות למסכים חיצוניים כדי לקבל מידע כמו גודל המסך והרזולוציה. אחרת, האפליקציות עלולות להניח הנחות שגויות לגבי המסכים, מה שעלול להוביל להתנהגות שגויה של האפליקציה.
  • מסכים מובנים ברכב: הרבה מסכים מובנים ברכב הם לרוחב, אבל לא כולם. פיתוח אפליקציות לשימוש בזמן חנייה למסכי רכב דומה לפיתוח לטאבלטים.

בעיות תאימות נפוצות

הבעיות הנפוצות ביותר בתאימות של אפליקציות הן הגבלות על כיוון האפליקציה, הגבלות על שינוי הגודל ויחס הגובה-רוחב, טיפול שגוי בכיוון התצוגה המקדימה של המצלמה ושימוש לא נכון בממשקי API.

Letterboxing חפשו את המטמון

האפליקציה ממוקמת במרכז המסך או, במסכים גדולים, בצד אחד או בצד השני כדי לאפשר גישה נוחה. מסגרות (פסים בצבע אחיד או טפט מטושטש) ממלאות את האזור הלא מנוצל של המסך בצדדים או בחלק העליון והתחתון של האפליקציה.

הוספת פסים שחורים בצדדים קורית לעיתים קרובות במכשירים עם מסך גדול, כי המידות ויחס הגובה-רוחב של המסך במכשיר בדרך כלל שונים מאלה של טלפונים רגילים, שרוב האפליקציות מיועדות להם.

איור 1. אפליקציה שמוגבלת לכיוון לאורך מוצגת עם פסי שחורים בטאבלט ובמכשיר מתקפל בכיוון לרוחב.

בעיה

האפליקציה לא תומכת בכל הגדרות התצוגה כי הכיוון שלה קבוע, יחס הגובה-רוחב שלה קבוע או שאי אפשר לשנות את הגודל שלה.

הגדרות התצורה שקובעות את הכיוון של האפליקציה ואת האפשרות לשנות את הגודל שלה כוללות את ההגדרות הבאות:

  • screenOrientation: מציין כיוון קבוע לאפליקציה. אפליקציות יכולות גם להגדיר כיוון בזמן הריצה באמצעות Activity#setRequestedOrientation().

  • resizeableActivity: מציין אם המערכת יכולה לשנות את הגודל של האפליקציות כך שיתאימו לחלונות בגדלים שונים. ב-Android 11 (רמת API ‏30) ומטה, המאפיין הזה מציין אם אפליקציות תומכות במצב מרובה חלונות. ב-Android 12 (רמת API‏ 31) ואילך, ההגדרה הזו מציינת אם אפליקציות תומכות במצב מרובה חלונות במסכים קטנים (גודל חלון קומפקטי). ב-Android בגרסה 12 ומעלה, האפליקציות תומכות במצב מרובה חלונות במסכים גדולים (גודל חלון בינוני או מורחב), ללא קשר להגדרה הזו.

  • maxAspectRatio: מציין את יחס הגובה-רוחב המקסימלי שהאפליקציה תומכת בו. רק אפליקציות שהערך של resizeableActivity שלהן מוגדר כ-false יכולות להגדיר את maxAspectRatio.

  • minAspectRatio: מציין את יחס הגובה-רוחב המינימלי שהאפליקציה תומכת בו. רק אפליקציות שבהן הערך של resizeableActivity מוגדר כ-false יכולות להגדיר את minAspectRatio.

אופטימיזציה

האפליקציה צריכה לתמוך בכל גדלי המסך והכיוונים של מכשירים ושל מצב ריבוי חלונות. מסירים את כל ההגבלות על הכיוון ויחס הגובה-רוחב הקבוע מפריסות האפליקציה ומקובץ המניפסט של האפליקציה.

פתרון עקיף לבעיות תאימות

אם אפליקציה עם אוריינטציה קבועה או יחס רוחב-גובה קבוע פועלת בחלון שבו האפליקציה לא תומכת ישירות בגודל או באוריינטציה של החלון, מערכת Android מוסיפה לאפליקציה פסי שוליים כדי לשמור על רציפות.

החל מ-Android 12 (רמת API‏ 31) ועד ל-12L (רמת API‏ 32), הפלטפורמה מחילה מגוון שיפורים על אפליקציות עם תיבת מכתבים. יצרני המכשירים מטמיעים את השיפורים בממשק המשתמש. לא צריך לבצע פיתוח נוסף באפליקציה כדי ליהנות מהשיפורים.

‫Android 12 (‏API ברמה 31) כוללת את השיפורים האסתטיים הבאים, שיצרני המכשירים יכולים להגדיר:

  • פינות מעוגלות: הפינות של חלון האפליקציה נראות מעודנות יותר.
  • שקיפות של סרגל המערכת: סרגלי הסטטוס והניווט, שמוצגים כשכבת-על מעל האפליקציה, הם שקופים למחצה, כך שהסמלים בסרגלים תמיד גלויים על רקע ה-Letterbox.
  • יחס גובה-רוחב שניתן להגדרה: אפשר לשנות את יחס הגובה-רוחב של האפליקציה כדי לשפר את המראה שלה.

איור 2. אפליקציה עם פסי שחורים בצדדים ושיפורים בממשק המשתמש.

‫12L (API ברמה 32) כוללת את השיפורים הבאים בפונקציונליות:

  • מיקום שניתן להגדרה: במסכים גדולים, יצרני המכשירים יכולים למקם את האפליקציה בצד ימין או שמאל של התצוגה, כדי להקל על האינטראקציה.

  • עיצוב מחדש של לחצן ההפעלה מחדש: יצרני מכשירים יכולים לתת ללחצן ההפעלה מחדש של מצב התאימות לגודל מראה חדש כדי שהמשתמשים יוכלו לזהות אותו בקלות רבה יותר.

ב-Android 13 ‏ (API level 33) נוסף דיאלוג להדרכת המשתמשים לגבי מיקום האפליקציה עם המסגרת השחורה על המסך או הכללת המסגרת השחורה במצב מסך מפוצל:

איור 3. אפליקציה עם תיבת דו-שיח להדרכת משתמשים, שמוצגת עם פסי שחור בצדדים.

מצב תאימות לגודל

מצב תאימות לגודל הוא letterboxing ששומר על יחס הגובה-רוחב של האפליקציה וכולל אמצעי בקרה להפעלה מחדש. הפקד מאפשר למשתמשים להפעיל מחדש את האפליקציה ולצייר מחדש את התצוגה. מערכת Android מפעילה מצב תאימות לגודל עבור אפליקציות שלא ניתן לשנות את הגודל שלהן. כשפעילות עוברת למאגר תצוגה שלא תואם למידות של הפעילות, המערכת עשויה לשנות את קנה המידה של האפליקציה כדי למלא את תצוגת המכשיר לפחות במימד אחד.

שינויים בהגדרות המכשיר שיכולים להפעיל את מצב התאימות לגודל כוללים את השינויים הבאים:

  • סיבוב המכשיר
  • מכשיר מתקפל עובר למצב מקופל או לא מקופל
  • מעבר בין מצב מסך מלא למצב מסך מפוצל

בעיה

מצב התאמה לגודל חל בדרך כלל על פעילויות שמוגבלות בכיוון או ביחס הגובה-רוחב שלהן, ומוגדרות (או נקבעות על ידי המערכת) כפעילויות שלא ניתן לשנות את הגודל שלהן.

האפליקציה שלכם נחשבת ככזו שאפשר לשנות את הגודל שלה – והיא לא תועבר למצב תאימות לגודל – אם היא עומדת באחד מהקריטריונים הבאים:

אם האפליקציה לא עומדת באף אחד מהתנאים, היא נחשבת כלא ניתנת לשינוי גודל, ויכול להיות שהיא תופעל במצב תאימות לגודל.

אופטימיזציה

האפליקציה צריכה לתמוך בכל גדלי המסכים. כדי לשנות את גודל האפליקציה, צריך להגדיר את המאפיין android:resizeableActivity של האלמנט <activity> או <application> לערך true במניפסט האפליקציה. מעצבים פריסות רספונסיביות או אדפטיביות לאפליקציה. מידע נוסף זמין במאמרים בנושא תמיכה בגדלים שונים של מסכים ותמיכה במצב ריבוי חלונות.

פתרון עקיף לבעיות תאימות

מערכת Android מעבירה אפליקציה למצב תאימות לגודל כשהיא קובעת שאפשר לשפר את התצוגה של האפליקציה עם הפסים השחורים על ידי שינוי קנה המידה שלה כך שתמלא את חלון התצוגה לפחות בממד אחד. במערכת מוצג אמצעי בקרה להפעלה מחדש, שיוצר מחדש את תהליך האפליקציה, יוצר מחדש את הפעילות ומצייר מחדש את התצוגה. כדאי לעיין גם בסקירה כללית על תהליכים ושרשורים.

מצב תאימות לתצוגה

מצב התאימות לתצוגה מונע הפעלה מחדש של אפליקציה כשהיא עוברת בין מסכים שונים, מה שיכול להפעיל שינוי בהגדרות כמו מצב צבע, זמינות של מסך מגע או שינוי בצפיפות המסך.

מצב התאימות של התצוגה מופעל כברירת מחדל במשחקים (על סמך הדגל android:appCategory) כדי לשפר את היציבות וההמשכיות. בניגוד למצב תאימות לגודל, מצב תאימות לתצוגה לא מקפיא את ההגדרה של האפליקציה. האפליקציה עדיין יכולה לקבל את כל עדכוני ההגדרות דרך ממשקי API כמו הקריאה החוזרת (callback) של onConfigurationChanged(), אבל היא לא תופעל מחדש באופן שישבש את הפעילות. המשמעות היא שמשחקים שתומכים כראוי בממשקי API כמו onConfigurationChanged()‎ עדיין יכולים לעדכן את ממשק המשתמש שלהם בצורה רספונסיבית, גם אם הם במצב תאימות לתצוגה.

כדי לבטל את ההסכמה לשימוש במצב תאימות לתצוגה ולטפל בשינויים בהגדרות באפליקציה, צריך להצהיר על תמיכה בשינויים בהגדרות בקובץ AndroidManifest.xml של האפליקציה ולטפל בשינויים בהגדרות בקריאה החוזרת onConfigurationChanged().

<activity
    android:name=".MyGameActivity"
    android:configChanges="colorMode|touchscreen|density|...">
    ...
</activity>

לולאות מרצדות

אם אפליקציה לא תומכת בכל כיווני התצוגה, היא עשויה לבקש שוב ושוב כיוונים חדשים כשמתרחש שינוי בהגדרה, וכך ליצור לולאה אינסופית שגורמת לתצוגה להבהב או לאפליקציה להסתובב ללא הפסקה.

בעיה

ב-Android 12 (רמת API‏ 31) ומעלה, יצרני מכשירים יכולים להגדיר את המכשירים שלהם כך שיתעלמו מהגבלות על כיוון המסך שצוינו באפליקציות, ובמקום זאת יאכפו מצבי תאימות. לדוגמה, מכשיר מתקפל יכול להתעלם מההגדרה android:screenOrientation="portrait" של פעילות מסוימת כשהפעילות מוצגת במסך הפנימי של המכשיר, בגודל של טאבלט במצב לרוחב.

אם הגבלות האוריינטציה של אפליקציה מתעלמות, האפליקציה יכולה להגדיר את האוריינטציה שלה באופן פרוגרמטי על ידי קריאה ל-Activity#setRequestedOrientation(). הקריאה מפעילה הפעלה מחדש של האפליקציה אם האפליקציה לא מטפלת בשינויים בהגדרות (ראו טיפול בשינויים בהגדרות). אחרי ההפעלה מחדש, המערכת שוב מתעלמת מההגבלות על האוריינטציה של האפליקציה, האפליקציה חוזרת על הקריאה ל-setRequestedOrientation(), הקריאה מפעילה הפעלה מחדש של האפליקציה וכן הלאה בלולאה נצחית.

דרך נוספת שבה יכול להיות שתיתקלו בבעיה הזו היא כשהכיוון הטבעי (הכיוון הרגיל כפי שנקבע על ידי Android) של מסך המכשיר הוא לרוחב (כלומר, הקריאה ל-Display#getRotation() מחזירה Surface.ROTATION_0 בזמן שיחס הגובה-רוחב של המכשיר הוא לרוחב). בעבר, האפליקציות הניחו שDisplay.getRotation() = Surface.ROTATION_0 מייצג את המכשיר במצב אנכי, אבל זה לא תמיד המצב, למשל במסך הפנימי של חלק מהמכשירים המתקפלים ובחלק מהטאבלטים.

אפליקציה בתצוגה לרוחב במסך פנימי של מכשיר מתקפל עשויה לבדוק את סיבוב המסך, לקבל ערך של ROTATION_0, להניח שהתצורה הטבעית של המכשיר היא לאורך ולקרוא לפונקציה setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT ) כדי להגדיר מחדש את פריסת האפליקציה. אחרי שהאפליקציה מופעלת מחדש (במצב לרוחב), יכול להיות שהיא שוב תבדוק את סיבוב המסך, תקבל ערך של ROTATION_0, תקרא לפונקציה setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) ותמשיך את הלולאה האינסופית.

אופטימיזציה

אפליקציות לא צריכות לבצע את הפעולות הבאות:

  • צריך להגדיר כיוון ברירת מחדל באמצעות Activity#setRequestedOrientation() בשיטת הפעילות onCreate() כי בקשת הכיוון יכולה להיות מופעלת באופן בלתי צפוי על ידי שינויים בהגדרות שלא טופלו
  • הנחה שכיוון המכשיר הטבעי (ROTATION_0) הוא לאורך
  • הגדרת כיוון על סמך אותות שלא קשורים לגודל החלון הנוכחי, כמו Display#getRotation(), נוכחות של FoldingFeature או ממשקי API שיצאו משימוש.

פתרון עקיף לבעיות תאימות

מערכת Android מתעלמת מקריאות ל-Activity#setRequestedOrientation() במצבים הבאים:

  • הפעילות כבר הופעלה מחדש מקריאה קודמת לשיטה או שהופעל טיפול בכפייה של סיבוב תאימות המצלמה (ראו תצוגה מקדימה של המצלמה בהמשך).

    יצרני מכשירים יכולים להחיל את ההתנהגות הזו על אפליקציה עם OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION.

  • במהלך הפעילות בוצעו יותר משתי בקשות לשינוי כיוון בשנייה אחת, מה שמצביע על כך שהתרחשה לולאה. מתוך שתי הבקשות בלולאה, מערכת Android משתמשת בזו שמגדילה את אזור התצוגה של האפליקציה.

    יצרני מכשירים יכולים להחיל את ההתנהגות הזו על אפליקציה עם OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED.

  • הבעלים של המכשיר הווירטואלי ביטלו את קריאת השיטה במכשירים נבחרים.

תצוגה מקדימה של המצלמה

התצוגה המקדימה של המצלמה (או העינית) באפליקציות של מצלמות עשויה להיות לא מיושרת או מעוותת בטאבלטים, במחשבים ניידים ובמסכים מתקפלים.

בעיה

במסמך הגדרת התאימות של Android מצוין שחיישן תמונה של מצלמה "חייב להיות מכוון כך שהמימד הארוך של המצלמה יתאים למימד הארוך של המסך".

אפליקציות מניחות לעיתים קרובות שהכיוון של המכשיר והכיוון של חיישן המצלמה הם לאורך – הנחה סבירה בטלפונים ניידים רגילים. אבל האוריינטציה הטבעית של טאבלטים ומחשבים ניידים ושל חיישני המצלמה שלהם יכולה להיות לרוחב. בנוסף, יכול להיות שלמכשירים עם גורמי צורה חדשים, כמו מכשירים מתקפלים, יהיו כמה כיוונים טבעיים וכמה חיישני מצלמה בכיוונים שונים.

התחלת פעילות עם כיוון מצלמה שהאפליקציה לא מצפה לו או מעבר בין מצלמות שונות או בין מסכי מכשיר (במכשירים מתקפלים) עלולים לגרום לתצוגה מקדימה של המצלמה שלא מיושרת או מעוותת.

אופטימיזציה

אפליקציות מצלמה צריכות לזהות ולנהל בצורה נכונה את כיוון המכשיר ואת כיוון חיישן המצלמה כדי להציג תצוגה מקדימה של המצלמה עם יישור ושינוי גודל נכונים. האפליקציות צריכות לחשב את סיבוב המכשיר, סיבוב החיישן ויחס הגובה-רוחב של המסך או החלון, ואז להחיל את התוצאות על התצוגה המקדימה של המצלמה. הוראות מפורטות זמינות במאמרים תצוגה מקדימה של המצלמה והיכרות עם תצוגת עינית המצלמה.

פתרון עקיף לבעיות תאימות

מכשיר נמצא בכיוון טבעי כש-Display#getRotation() מחזיר Surface.ROTATION_0. המערכת מחשבת את CameraCharacteristics.SENSOR_ORIENTATION מתוך הכיוון הטבעי של המכשיר. מערכת Android מיישרת את חלון האפליקציה לאורך של אפליקציות שמוגבלות לאורך עם הכיוון הטבעי של המכשיר, שזה מה שרוב האפליקציות מצפות לו. בנוסף, מערכת Android חותכת את התמונה מחיישן המצלמה כשהכיוון של החיישן הוא לרוחב והתצוגה המקדימה של המצלמה היא לאורך. הפתרונות הספציפיים כוללים את הפתרונות הבאים:

  • הפעלת סיבוב בכוח של תצוגות מקדימות של מצלמה באפליקציות שמוגבלות למצב אנכי: אפליקציות שמוגבלות למצב אנכי מצפות שהכיוון הטבעי של המכשיר והכיוון של חיישן המצלמה יהיו אנכיים. עם זאת, ב-Android 12 (רמת API ‏31) ומעלה, אפליקציות יכולות לפעול בכמה כיווני מכשיר אם יצרני המכשירים מתעלמים מהגדרת הכיוון.

    כשאפליקציה שמוגבלת למצב פורטרט מחוברת למצלמה, מערכת Android מסובבת את האפליקציה בכוח כדי ליישר את חלון הפורטרט של האפליקציה עם הכיוון הטבעי של המכשיר.

    בטאבלטים מסוימים (ראו מכשירי הפניה), חלון האפליקציה במצב לאורך מסובב למצב לאורך במסך מלא כדי להתאים לכיוון הטבעי של המכשיר. האפליקציה תופסת את המסך המלא אחרי סיבוב בכוח.

    במסך הפנימי של מכשירים מתקפלים במצב לרוחב (ראו מכשירי הפניה), פעילויות שמוצגות רק במצב לאורך מסובבות למצב לרוחב כדי להתאים לכיוון הטבעי כשהמכשיר פתוח. האפליקציה מוצגת עם פסים שחורים בצדדים אחרי סיבוב מאולץ.

  • חיתוך של המצלמה הקדמית הפנימית: בחלק מהמכשירים המתקפלים, החיישן של המצלמה הקדמית הפנימית נמצא במצב אופקי. בנוסף לסיבוב בכוח של התצוגה המקדימה של המצלמה במסך הפנימי המתקפל, מערכת Android חותכת את שדה הראייה של המצלמה הקדמית הפנימית (לרוחב) כך שהחיישן מצלם תצוגה הפוכה לכיוון המכשיר.

  • רענון בכוח של תצוגות מקדימות של המצלמה: המערכת עוברת בין שיטות הפעילות onStop() ו-onStart() (כברירת מחדל) או onPause() ו-onResume() (מוגדר על ידי OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE כהחלפה לכל אפליקציה) אחרי סיבוב בכוח כדי לוודא שהתצוגה המקדימה של המצלמה מוצגת בצורה תקינה.

  • שינוי קנה מידה של יחס גובה-רוחב: המערכת משנה באופן דינמי את יחס הגובה-רוחב של התצוגה המקדימה של המצלמה שסובבה בכוח ליחס גובה-רוחב מינימלי גבוה יותר, כדי להבטיח שהתצוגה המקדימה של המצלמה תותאם בצורה נכונה.

מפתחי אפליקציות יכולים לעקוף את הפתרונות האלה אם האפליקציות מטפלות בתצוגה המקדימה של המצלמה בצורה נכונה. מידע נוסף על ביטול פעולות באפליקציות

ממשקי API שנעשה בהם שימוש לרעה

מערכת Android הוסיפה תמיכה בתכונות כמו מצב מרובה חלונות ובמכשירים כמו מכשירים מתקפלים. לכן, הוצאנו משימוש ממשקי API מדור קודם והחלפנו אותם בממשקי API עדכניים שפועלים בכל הגדלים של המסכים ובכל גורמי הצורה של המכשירים. עם זאת, ממשקי ה-API שהוצאו משימוש עדיין זמינים לצורך תאימות לאחור.

חלק מממשקי ה-API של View מיועדים למטרות מיוחדות שמפתחים לא תמיד מבינים.

בעיה

מפתחים ממשיכים להשתמש בממשקי API שהוצאו משימוש Displayומניחים בטעות שממשקי ה-API מחזירים את גבולות האפליקציה במקום את גבולות אזור התצוגה של המכשיר. או שמפתחים משתמשים בטעות בממשקי API של תצוגות למטרות מיוחדות כדי לקבל מדדים כלליים של תצוגה. התוצאה היא חישובים שגויים כשממקמים מחדש רכיבים בממשק המשתמש אחרי אירועים של שינוי גודל חלון האפליקציה, מה שגורם לבעיות בפריסה.

ממשקי API של רשת המדיה שהוצאו משימוש ונעשה בהם שימוש לרעה:

מידע נוסף זמין במאמר בנושא תמיכה במצב מרובה חלונות.

ממשקי API של תצוגות שנעשה בהם שימוש לרעה:

אופטימיזציה

אל תסתמכו אף פעם על הגודל הפיזי של המסך כדי למקם רכיבי ממשק משתמש. מעבירים את האפליקציה לממשקי API שמבוססים על WindowMetrics, כולל ממשקי ה-API הבאים של WindowManager:

פתרון עקיף לבעיות תאימות

שתי שיטות לביטול הגדרות משנות את ממשקי ה-API שהוצאו משימוש, Display, ואת ממשקי ה-API שנעשה בהם שימוש לא תקין, View, כדי להחזיר את גבולות האפליקציה: ‫ALWAYS_SANDBOX_DISPLAY_APIS עבור ממשקי ה-API‏ Display;‏ OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS עבור ממשקי ה-API‏ View. ‫ALWAYS_SANDBOX_DISPLAY_APIS מוחל כברירת מחדל גם על אפליקציות שעומדות בדרישות להפעלת מצב תאימות לגודל.

פעילויות שקופות

פעילויות שקופות הן תוצאה של סגנונות רקע שקופים, לדוגמה:

<style name="Transparent" parent="AppTheme">
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowBackground">@android:color/transparent</item>
</style>

עיצובים שקשורים לתיבות דו-שיח, כמו Theme.MaterialComponents.Dialog, יכולים לכלול סגנונות שגורמים לפעילויות להיות שקופות.

פעילויות שקופות לא מכסות את כל שטח התצוגה הזמין, ולכן קשה לנהל אותן כי שטח התצוגה הזמין יכול להשתנות בהתאם לשינויים בהגדרות, כמו סיבוב המכשיר, קיפול ופתיחה של המכשיר ומצב ריבוי חלונות.

בעיה

פעילות שקופה צריכה להיות בתוך הגבולות של הפעילות האטומה הראשונה שמתחתיה ברשימת הפעילויות של המשימה. עם זאת, פעילות אטומה שמפעילה תיבת דו-שיח של הרשאות יכולה להיות פעילות מעבר (פעילות שמפעילה פעילות אחרת ואז נעלמת). לכן, המערכת לא יכולה לקבוע את הגבולות של פעילות המעבר שהפעילה את פעילות תיבת הדו-שיח השקופה של ההרשאות.

אופטימיזציה

פעילויות שקופות מקבלות את המגבלות שלהן מהפעילות האטומית העליונה שמתחתיהן במצבור הפעילויות של המשימה. הפעילות האטומה צריכה להיות זמינה לאורך כל מחזור החיים של הפעילות השקופה, מהרגע שבו הפעילות נוצרת ועד שהיא נהרסת. לכן, אל תפעילו בקשות הרשאה מפעילויות מסוג trampoline.

אם פעילות מסוג trampoline מפעילה בקשת הרשאה, יכול להיות שהמשתמש לא יוכל לראות את תיבת הדו-שיח של ההרשאה, כי פעילות ה-trampoline תיהרס לפני שהמשתמש יקבל הזדמנות להגיב לתיבת הדו-שיח, ויכול להיות שהמידות והמיקום של פעילות תיבת הדו-שיח יחושבו בצורה שגויה.

אפליקציות צריכות תמיד להפעיל בקשות להרשאות מפעילויות שנשארות גלויות עד שהמשתמש מחליט לגבי מתן הרשאה.

פינות מעוגלות

פעילות יכולה להיות שקופה בגלל סגנון שמציין שקיפות של הרקע, או בגלל שהתוכן של הפעילות לא ממלא את שטח התצוגה הזמין. אם פעילות שקופה ממלאת את שטח המסך הזמין, המערכת מעגלת את הפינות של הפעילות באופן אוטומטי אם יצרן המכשיר הגדיר אותה לעשות זאת. אבל אם פעילות שקופה (כמו תיבת דו-שיח של הרשאה) לא ממלאת את השטח הזמין, אתם יכולים להחליט אם להחיל פינות מעוגלות או לא.

תיבות הדו-שיח של ההרשאות לא ממלאות את שטח התצוגה הזמין כי פריסת תיבת הדו-שיח משתמשת בדרך כלל ב-LayoutParams.WRAP_CONTENT ולא ב-LayoutParams.MATCH_PARENT.

פתרון עקיף לבעיות תאימות

פעילויות שפותחות פעילויות של תיבת דו-שיח יישארו גלויות עד שהמשתמש יגיב לתיבת הדו-שיח.

המערכת מוודאת שפעילות שקופה יורשת את כל האילוצים מהפעילות האטומה הראשונה שמתחת לפעילות השקופה במצבור הפעילויות, כולל אילוצים שקשורים ל:

  • מצב תאימות לגודל
  • כיוון
  • יחס גובה-רוחב

משחקי Unity

משחקי Unity פועלים במסך מלא ב-Android או במצב ריבוי חלונות. עם זאת, בהרבה משחקי Unity, המיקוד נעלם והתוכן מפסיק להיטען כשהאפליקציה מועברת למצב ריבוי חלונות.

בעיה

‫Unity הוסיפה אפשרות Resizable Window ב-Unity 2019.4 כדי לתמוך במצב מרובה חלונות ב-Android. עם זאת, ההטמעה הראשונית לא הגיבה בצורה נכונה למחזור החיים של הפעילות במצב מרובה חלונות, ולכן UnityPlayer השהה את ההפעלה כשהאפליקציה איבדה את המיקוד. הנגן הציג מסך שחור או את הפריים האחרון של המשחק, שהיה קפוא. המשחק ימשיך רק אם המשתמש יקיש על המסך. אפליקציות רבות שמשתמשות במנוע Unity נתקלות בבעיה הזו ומוצגות כחלון שחור במצב ריבוי חלונות.

אופטימיזציה

משדרגים את Unity לגרסה 2019.4.40 ואילך ומייצאים מחדש את המשחק. חשוב להשאיר את האפשרות Resizable Window מסומנת בהגדרות של נגן Android. אחרת, המשחק יושהה כשהוא לא במרכז, גם אם הוא גלוי לחלוטין במצב ריבוי חלונות.

פתרון עקיף לבעיות תאימות

יצרני מכשירים יכולים להחיל את ההחלפה של OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS לכל אפליקציה כדי לספק לאפליקציה אירוע מזויף של מיקוד במצב ריבוי חלונות. השינוי מאפשר לפעילות לצייר מחדש את התוכן ולא להציג מסך שחור.

שינוי דינמי של חלונות במחשב

כשמפעילים אפליקציות בסביבת חלונות במחשב, יכול להיות שיופיעו מצבי תאימות נוספים.

אפשר לשנות את הגודל של אפליקציות עם כיוון נעול באופן חופשי. גם אם פעילות נעולה לכיוון לאורך, המשתמשים עדיין יכולים לשנות את גודל האפליקציה לכיוון לרוחב.

אנימציה של שינוי הגודל של אפליקציה שמוצגת לאורך לרוחב.

עם זאת, אם הפעילות מוגדרת כפעילות שלא ניתן לשנות את הגודל שלה (resizeableActivity = false), ממשק המשתמש של הפעילות משנה את הגודל שלו תוך שמירה על יחס רוחב-גובה זהה.

אנימציה של שינוי הגודל של האפליקציה. ממשק המשתמש מותאם כדי למלא את חלון שולחן העבודה.

תצוגה מקדימה של המצלמה בחלונות במחשב

כשמפעילים תצוגה מקדימה של המצלמה באפליקציות שמוצגות בחלונות בשולחן העבודה, ממשק המשתמש של העינית מותאם לגודל החלון תוך שמירה על יחס הגובה-רוחב המקורי. אפשר לשנות את הגודל של שאר חלון האפליקציה באופן חופשי.

בדיקת האפליקציה לאיתור בעיות תאימות

כדי לבדוק את האפליקציה ולהבין איך היא מתנהגת בגורמי צורה שונים, אפשר להיעזר במקורות המידע הבאים:

בפורמט letterbox

מוודאים שכל פעילות יכולה להשתמש בכל שטח המסך שזמין לאפליקציה. קודם כול, מצהירים על הקוד הבא בתיקיית הבדיקה:

Kotlin

fun isLetterboxed(activity: AppCompatActivity): Boolean {
    if (isInMultiWindowMode) return false

    val wmc = WindowMetricsCalculator.getOrCreate()
    val currentBounds = wmc.computeCurrentWindowMetrics(this).bounds
    val maxBounds = wmc.computeMaximumWindowMetrics(this).bounds

    val isScreenPortrait = maxBounds.height() > maxBounds.width()

    return if (isScreenPortrait) {
        currentBounds.height() < maxBounds.height()
    } else {
        currentBounds.width() < maxBounds.width()
    }
}

Java

public boolean isLetterboxed(AppCompatActivity activity) {
    if (activity.isInMultiWindowMode()) {
        return false;
    }

    WindowMetricsCalculator wmc = WindowMetricsCalculator.getOrCreate();
    Rect currentBounds = wmc.computeCurrentWindowMetrics(activity).getBounds();
    Rect maxBounds = wmc.computeMaximumWindowMetrics(activity).getBounds();

    boolean isScreenPortrait = maxBounds.height() > maxBounds.width();

    return (isScreenPortrait)
        ? currentBounds.height() < maxBounds.height()
        : currentBounds.width() < maxBounds.width();
}

לאחר מכן מריצים בדיקה כדי לוודא שההתנהגות תואמת לציפיות ושהפעילות המטורגטת לא מוצגת עם מסגרת שחורה:

Kotlin

@get:Rule
val activityRule = ActivityScenarioRule(MainActivity::class.java)

@Test
fun activity_launched_notLetterBoxed() {
    activityRule.scenario.onActivity {
        assertFalse(it.isLetterboxed())
    }
}

Java

@Rule
public ActivityScenarioRule<MainActivity> rule = new ActivityScenarioRule<>(MainActivity.class);

@Test
public void activity_launched_notLetterBoxed() {
    try (ActivityScenario<MainActivity> scenario =
        ActivityScenario.launch(MainActivity.class)) {
            scenario.onActivity( activity -> {
                assertFalse(activity.isLetterboxed());
            });
        }
}

מומלץ להריץ את הבדיקה הזו רק עד שהיא עוברת ומוודאת שהפעילויות של האפליקציה תופסות את כל שטח התצוגה שזמין לאפליקציה. חשוב לבדוק את האפליקציה בכל סוגי המכשירים כדי לוודא שההתנהגות שלה עקבית.

שינויים מברירת המחדל של המערכת לכל אפליקציה

מערכת Android מספקת שינויים שמשנים את ההתנהגות המוגדרת של אפליקציות. לדוגמה, החלפת ברירת המחדל FORCE_RESIZE_APP מורה למערכת לעקוף את מצב התאימות לגודל ולשנות את גודל האפליקציה כך שתתאים לממדי התצוגה, גם אם resizeableActivity="false" מצוין בקובץ המניפסט של האפליקציה.

יצרני מכשירים מחילים שינויים על אפליקציות נבחרות – או על כל האפליקציות – במכשירים ספציפיים עם מסך גדול. ב-Android 14 (רמת API‏ 34) ומעלה, משתמשים יכולים להחיל שינויים באפליקציות דרך הגדרות המכשיר. ב-Android 16 (API ברמה 36) ומעלה, בעלי מכשירים וירטואליים מחילים שינויים על מכשירים נבחרים שמנוהלים על ידי בעלי המכשירים הווירטואליים.

שינויים על ידי המשתמשים באפליקציות

ב-Android מגרסה 14 ומעלה, תפריט ההגדרות מאפשר למשתמשים לשנות את יחס הגובה-רוחב של האפליקציות. במכשירים עם מסך גדול, כמו מכשירי ההפניה, התפריט מיושם.

בתפריט מופיעה רשימה של כל האפליקציות שמותקנות במכשיר. המשתמשים בוחרים אפליקציה ואז מגדירים את יחס הגובה-רוחב של האפליקציה ל-3:4, ל-1:1, למסך מלא או לערך אחר שהוגדר על ידי יצרן המכשיר. המשתמשים יכולים גם לאפס את יחס הגובה-רוחב לברירת המחדל של האפליקציה, שמוגדרת במניפסט האפליקציה.

אפליקציות יכולות לבטל את ההסכמה לשינוי התאימות על ידי הגדרת התגים הבאים של PackageManager.Property:

  • PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE

    כדי לבטל את ההסכמה לשינוי יחס הגובה-רוחב של המשתמש לצורך תאימות, מוסיפים את המאפיין למניפסט של האפליקציה ומגדירים את הערך ל-false:

    <application>
        <property
            android:name="android.window.
            PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE"
            android:value="false" />
    </application>
    

    האפליקציה לא תופיע ברשימת האפליקציות בהגדרות המכשיר. המשתמשים לא יוכלו לשנות את יחס הגובה-רוחב של האפליקציה.

    הגדרת המאפיין לערך true לא משפיעה על כלום.

  • PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE

    כדי לבטל את ההסכמה לשימוש באפשרות של מסך מלא לשינוי יחס הגובה-רוחב של המשתמש לצורך תאימות, מוסיפים את המאפיין למניפסט של האפליקציה ומגדירים את הערך ל-false:

    <application>
        <property
            android:name="android.window.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE"
            android:value="false" />
    </application>
    

    האפשרות 'מסך מלא' מוסרת מרשימת האפשרויות של יחסי הגובה-רוחב בהגדרות המכשיר. המשתמשים לא יוכלו להחיל את ההגדרה לביטול ההצגה במסך מלא על האפליקציה שלכם.

    הגדרת המאפיין הזה ל-true לא משפיעה.

אופטימיזציה של האפליקציה לכל המסכים: אל תגדירו הגבלות על יחסי גובה-רוחב באפליקציה. השתמשו בסיווגים של גודל החלון כדי לתמוך בפריסות שונות בהתאם לכמות השטח הזמין לתצוגה.

שינויים מברירת המחדל של המערכת לכל אפליקציה במכשיר

יצרני מכשירים ובעלי מכשירים וירטואליים (אפליקציות נבחרות מהימנות עם הרשאות מיוחדות) מבצעים שינויים בהגדרות של אפליקציות ספציפיות במכשירים מסוימים, כולל טאבלטים, מכשירים מתקפלים, מכשירי ChromeOS ומסכים ברכב. יכול להיות שמכשירי ההפניה יחילו חלק מהשינויים על מגוון אפליקציות כברירת מחדל.

אפליקציות יכולות לבטל את ההסכמה לרוב ההגדרות שמוגדרות מראש (פרטים בטבלה הגדרות שמוגדרות מראש לכל אפליקציה שבהמשך).

אתם יכולים לבדוק את האפליקציה עם או בלי הפעלת שינויים באמצעות מסגרת התאימות (ראו כלים של מסגרת התאימות). כשההגדרה הזו מופעלת, ההגדרות שמוגדרות בה חלות על כל האפליקציה.

אפשר גם להשתמש בממשק הגישור של Android‏ (adb) כדי להפעיל או להשבית שינויים ולבדוק אילו שינויים חלים על האפליקציה.

כדי להפעיל או להשבית את ההגדרות שמוגדרות מראש:

adb shell am compat enable/disable <override name/id> <package>

במכשירים להתייחסות, בודקים אילו שינויים חלים על האפליקציה:

adb shell dumpsys platform_compat | grep <package name>

בטבלה הבאה מפורטים אמצעי ההגנה הזמינים, וגם הנחיות לאופטימיזציה של האפליקציה כדי שלא תצטרכו להסתמך על אמצעי ההגנה האלה. אתם יכולים להוסיף דגלים של מאפיינים למניפסט של האפליקציה כדי לבטל את ההסכמה להחלפות מסוימות.

שינויים מברירת המחדל של המערכת לכל אפליקציה
סוג שם מזהה תיאור
יכולת שינוי הגודל FORCE_RESIZE_APP 174042936 עוקף את מצב התאימות לגודל האפליקציה בשינויים בהגדרות.
FORCE_NON_RESIZE_APP 181136395 האפליקציה נאלצת לעבור למצב תאימות לגודל הדף בשינויים בהגדרות.
יחס גובה-רוחב