לצד תכונות ויכולות חדשות, מערכת Android 8.0 (רמת API 26) כוללת מגוון שינויים בהתנהגות של מערכות ו-API. במסמך הזה נדגיש כמה מהשינויים העיקריים שצריך להבין ולהבין באפליקציות שלך.
רוב השינויים האלה משפיעים על כל האפליקציות, ללא קשר לגרסת Android שאליה הן מטרגטות. עם זאת, כמה שינויים משפיעים רק על אפליקציות שמטרגטות ל-Android 8.0. כדי להבהיר את הנושא, הדף הזה מחולק לשני חלקים: שינויים לכל האפליקציות ושינויים באפליקציות שמטרגטות את Android 8.0.
שינויים בכל האפליקציות
שינויי ההתנהגות האלה חלים על
מגבלות על הרצה ברקע
אחד מהשינויים בגרסה 8.0 של Android (רמת API 26) שנועד לשפר את חיי הסוללה הוא שבזמן שהאפליקציה נמצאת במצב שנשמר במטמון, ללא רכיבים פעילים, המערכת משחררת את כל ה-wakelocks שהאפליקציה מחזיקה.
בנוסף, כדי לשפר את ביצועי המכשיר, המערכת מגבילה התנהגויות מסוימות של אפליקציות שלא פועלות בחזית. פרטים נוספים:
- לאפליקציות שפועלות ברקע יש מעכשיו הגבלות על הגישה החופשית לשירותים שפועלים ברקע.
- אפליקציות לא יכולות להשתמש במניפסטים שלהן כדי לרשום את רוב השידורים המרומזים (כלומר, שידורים שלא מטרגטים באופן ספציפי באפליקציה).
כברירת מחדל, ההגבלות האלה חלות רק על אפליקציות שמטרגטות את O. עם זאת, המשתמשים יכולים להפעיל את ההגבלות האלה לכל אפליקציה במסך הגדרות, גם אם האפליקציה לא טירגטה את O.
ב-Android 8.0 (רמת API 26) יש גם את השינויים הבאים בשיטות ספציפיות:
- השיטה
startService()
מקפיצה עכשיוIllegalStateException
אם אפליקציה שמטרגטת את Android 8.0 תנסה להשתמש בשיטה הזו במצב שבו היא לא מורשית ליצור שירותים ברקע. - השיטה החדשה
Context.startForegroundService()
מפעילה שירות שפועל בחזית. המערכת מאפשרת לאפליקציות להפעיל אתContext.startForegroundService()
גם כשהן פועלות ברקע. עם זאת, האפליקציה חייבת להפעיל את השיטהstartForeground()
של השירות הזה תוך חמש שניות אחרי יצירת השירות.
מידע נוסף זמין במאמר מגבלות על ביצוע ברקע.
מגבלות על מיקום ברקע ב-Android
כדי לשמור על הסוללה, על חוויית המשתמש ועל תקינות המערכת, אפליקציות ברקע מקבלות עדכוני מיקום בתדירות נמוכה יותר כשמשתמשים בהן במכשיר עם Android 8.0. שינוי ההתנהגות הזה משפיע על כל האפליקציות שמקבלות עדכוני מיקום, כולל Google Play Services.
השינויים האלה משפיעים על ממשקי ה-API הבאים:
- ספק מיקום משולב (FLP)
- גבולות וירטואליים
- מדידות GNSS
- מנהל מיקומים
- מנהל Wi-Fi
כדי לוודא שהאפליקציה תפעל כצפוי, יש לבצע את השלבים הבאים:
- מומלץ לבדוק את הלוגיקה של האפליקציה ולוודא שנעשה שימוש בממשקי ה-API העדכניים של המיקום.
- בודקים שהאפליקציה מתנהגת כצפוי בכל תרחיש לדוגמה.
- מומלץ להשתמש בספק המיקום המשולב (FLP) או בגיאו-פיינס כדי לטפל בתרחישי לדוגמה שתלויים במיקום הנוכחי של המשתמש.
מידע נוסף על השינויים האלה זמין במאמר מגבלות על מיקום ברקע.
קיצורי דרך של אפליקציות
Android 8.0 (רמת API 26) כולל את השינויים הבאים במקשי קיצור של אפליקציות:
- לשידור
com.android.launcher.action.INSTALL_SHORTCUT
כבר אין השפעה על האפליקציה שלכם, כי הוא עכשיו שידור פרטי וסמוי. במקום זאת, צריך ליצור קיצור דרך לאפליקציה באמצעות ה-methodrequestPinShortcut()
מהמחלקהShortcutManager
. - עכשיו אפשר ליצור קיצורי דרך לאפליקציות באמצעות הכוונה
ACTION_CREATE_SHORTCUT
, ולנהל אותם באמצעות הכיתהShortcutManager
. הכוונה הזו יכולה גם ליצור קיצורי דרך מדור קודם במרכז האפליקציות שלא מקיימים אינטראקציה עםShortcutManager
. בעבר, הכוונה הזו הייתה יכולה ליצור רק קיצורי דרך מדור קודם למרכז האפליקציות. - קיצורי דרך שנוצרו באמצעות
requestPinShortcut()
וקיצורי דרך שנוצרו בפעילות שמטפלת בכוונהACTION_CREATE_SHORTCUT
הם עכשיו קיצורי דרך מלאים של אפליקציות. כתוצאה מכך, אפליקציות יכולות עכשיו לעדכן אותן באמצעות השיטות שמפורטות בקטעShortcutManager
. - קיצורי הדרך הקודמים שומרים על הפונקציונליות שלהם מגרסאות קודמות של Android, אבל צריך להמיר אותם לקיצור דרך של אפליקציה באופן ידני באפליקציה.
מידע נוסף על השינויים בקיצורי הדרך לאפליקציות זמין במדריך התכונות הצמדת קיצורי דרך וווידג'טים.
לוקאלים ובינלאומיות
ב-Android 7.0 (רמת API 24) הושקה האפשרות לציין לוקאל של קטגוריה שמוגדר כברירת מחדל, אבל בחלק מממשקי ה-API נעשה שימוש
בשיטה הכללית Locale.getDefault()
, ללא ארגומנטים, במקרים שבהם הם היו צריכים להשתמש במקום זאת בלוקאל של קטגוריית ברירת המחדל DISPLAY
. ב-Android 8.0 (רמת API 26), בשיטות הבאות נעשה עכשיו שימוש ב-Locale.getDefault(Category.DISPLAY)
במקום ב-Locale.getDefault()
:
Locale.getDisplayScript(Locale)
חוזר גם לערך Locale.getDefault()
כשהערך displayScript שצוין לארגומנט Locale
לא זמין.
שינויים נוספים שקשורים ללוקאל ולתמיכה בשפות שונות הם:
- קריאה ל-
Currency.getDisplayName(null)
מפעילהNullPointerException
, בהתאם להתנהגות המתועדת. - ניתוח השם של אזור הזמן השתנה. בעבר, מכשירי Android השתמשו בערך של שעון המערכת שנדגם בזמן האתחול כדי לשמור במטמון את שמות אזורי הזמן ששימשו לניתוח תאריכים ושעות. כתוצאה מכך, יכול להיות שהניתוח יושפע לרעה אם שעון המערכת היה שגוי בזמן האתחול או במקרים נדירים אחרים.
עכשיו, במקרים נפוצים, לוגיקה של הניתוח משתמשת ב-ICU ובערך הנוכחי של שעון המערכת בזמן הניתוח של שמות תחומי הזמן. השינוי הזה מספק תוצאות נכונות יותר, והן עשויות להיות שונות מגרסאות קודמות של Android כשבאפליקציה שלך נעשה שימוש במחלקות כמו
SimpleDateFormat
. - ב-Android 8.0 (רמת API 26) הגרסה של ICU מתעדכנת לגרסה 58.
חלונות התראות
אם אפליקציה משתמשת בהרשאה SYSTEM_ALERT_WINDOW
ומשתמשת באחד מסוגי החלונות הבאים כדי לנסות להציג חלונות התראה מעל אפליקציות אחרות וחלונות מערכת:
...החלונות האלה תמיד מופיעים מתחת לחלונות שנעשה בהם שימוש בסוג החלון TYPE_APPLICATION_OVERLAY
. אם אפליקציה מטרגטת ל-Android 8.0 (רמת API 26), היא משתמשת בסוג החלון TYPE_APPLICATION_OVERLAY
כדי להציג חלונות התראה.
מידע נוסף זמין בקטע סוגי חלונות נפוצים לחלונות התראות במסגרת השינויים בהתנהגות של אפליקציות שמטרגטות את Android 8.0.
קלט וניווט
בעקבות ההשקה של אפליקציות ל-Android ב-ChromeOS וגורמי צורה גדולים אחרים, כמו טאבלטים, אנחנו רואים עלייה מחודשת בשימוש בניווט באמצעות המקלדת באפליקציות ל-Android. בגרסה 8.0 של Android (רמת API 26), שיפרנו את השימוש במקלדת כמכשיר קלט לניווט, וכתוצאה מכך יש מודל מהימן יותר וניתן לחיזוי לניווט באמצעות חיצים ולחיצה על Tab.
באופן ספציפי, ביצענו את השינויים הבאים בהתנהגות של התמקדות באלמנט:
-
אם לא הגדרתם צבעים למצב התמקדות לאובייקט
View
(ל-drawable של החזית או ל-drawable של הרקע), המסגרת מגדירה עכשיו צבע הדגשה של התמקדות כברירת מחדל לאובייקטView
.View
הדגשת המיקוד היא רכיב גרפי של תנודות שמבוסס על העיצוב של הפעילות.אם אתם לא רוצים שהאובייקט
View
ישתמש בהדגשה שמוגדרת כברירת מחדל כשהוא מקבל את המיקוד, צריך להגדיר את המאפייןandroid:defaultFocusHighlightEnabled
לערךfalse
בקובץ ה-XML של הפריסה שמכיל אתView
, או להעביר את הערךfalse
אלsetDefaultFocusHighlightEnabled()
בלוגיקה של ממשק המשתמש של האפליקציה. - כדי לבדוק איך קלט המקלדת משפיע על המיקוד של רכיבי ממשק המשתמש, אפשר להפעיל את האפשרות למפתחים שרטוט > הצגת גבולות פריסה. ב-Android 8.0, האפשרות הזו מציגה את הסמל 'X' מעל האלמנט שכרגע מתמקד בו.
בנוסף, כל הרכיבים בסרגל הכלים ב-Android 8.0 הם באופן אוטומטי אשכולות ניווט במקלדת, כך שמשתמשים יכולים לנווט בקלות לכל סרגל כלים ולצאת ממנו כמכלול.
למידע נוסף על שיפור התמיכה בניווט באמצעות מקלדת בתוך האפליקציה, קראו את המדריך תמיכה בניווט באמצעות מקלדת.
מילוי אוטומטי של טפסים באינטרנט
עכשיו, כשAutofill Framework של Android מספק תמיכה מובנית בפונקציית המילוי האוטומטי, השתנו השיטות הבאות שקשורות לאובייקטים מסוג WebView
באפליקציות שמותקנות במכשירים עם Android 8.0 (רמת API 26):
WebSettings
-
- השיטה
getSaveFormData()
מחזירה עכשיו את הערךfalse
. בעבר, השיטה הזו החזירה במקום זאת את הערךtrue
. - לקריאה ל-
setSaveFormData()
כבר אין השפעה.
- השיטה
WebViewDatabase
-
- לקריאה ל-
clearFormData()
כבר אין השפעה. - השיטה
hasFormData()
מחזירה עכשיו את הערךfalse
. בעבר, השיטה הזו החזירה את הערךtrue
כשהטופס הכיל נתונים.
- לקריאה ל-
נגישות
Android 8.0 (רמת API 26) כולל את השינויים הבאים בנגישות:
-
מסגרת הנגישות ממירה עכשיו את כל התנועות של הקשה כפולה לפעולות
ACTION_CLICK
. השינוי הזה מאפשר ל-TalkBack לפעול בצורה דומה יותר לשירותי נגישות אחרים.אם באובייקטים מסוג
View
באפליקציה שלכם נעשה שימוש בטיפול מותאם אישית במגע, עליכם לוודא שהם עדיין פועלים עם TalkBack. יכול להיות שתצטרכו פשוט לרשום את ה-handler של הקליקים שבו משתמשיםView
האובייקטים שלכם. אם TalkBack עדיין לא מזהה תנועות שמבוצעות על אובייקטיםView
האלה, משנים את הערך שלperformAccessibilityAction()
. - שירותי הנגישות יודעים עכשיו על כל המופעים של
ClickableSpan
באובייקטים שלTextView
באפליקציה.
למידע נוסף על שיפור הנגישות של האפליקציה, ראו נגישות.
רשתות וקישוריות HTTP(S)
ב-Android 8.0 (רמת API 26) יש שינויים בהתנהגות של הרשתות וקישוריות ה-HTTP(S):
- לבקשות OPTIONS ללא גוף יש כותרת
Content-Length: 0
. בעבר לא הייתה להם כותרתContent-Length
. - כדי לתקן כתובות URL שמכילות נתיבים ריקים, הספרייה HttpURLConnection מוסיפה קו נטוי אחרי שם המארח או הרשות. לדוגמה, הפונקציה ממירה את הערך
http://example.com
לערךhttp://example.com/
. - בורר proxy בהתאמה אישית שמוגדר באמצעות ProxySelector.setDefault() מטרגט רק את הכתובת (הסכמה, המארח והיציאה) של כתובת ה-URL המבוקשת. כתוצאה מכך, בחירת שרת ה-proxy עשויה להתבסס רק על הערכים האלה. כתובת URL שמועברת לבורר שרת proxy בהתאמה אישית לא כוללת את הנתיב, פרמטרים של השאילתה או מקטעים של כתובת ה-URL המבוקשת.
- מזהי URI לא יכולים לכלול תוויות ריקות.
בעבר, הפלטפורמה תמכה בפתרון עקיף לקבלת תוויות ריקות בשמות המארחים, שהוא שימוש לא חוקי במזהי URI. הפתרון הזה נועד לתאימות עם גרסאות ישנות יותר של libcore. מפתחים שמשתמשים ב-API יראו באופן שגוי הודעת ADB: "בכתובת ה-URI example.com יש תוויות ריקות בשם המארח. פורמט זה שגוי ולא יתקבל בגרסאות עתידיות של Android." ב-Android 8.0 הפתרון החלופי הזה הוסר, והמערכת מחזירה ערך null עבור URIs בפורמט שגוי.
- ההטמעה של HttpsURLConnection ב-Android 8.0 לא מבצעת חזרה לגרסה לא מאובטחת של פרוטוקול TLS/SSL.
- הטיפול במנהור חיבורי HTTP(S) השתנה באופן הבא:
- כשמפעילים מנהרה של חיבור HTTPS דרך חיבור, המערכת ממוקמת בצורה נכונה את מספר היציאה (:443) בשורת המארח כששולחים את המידע הזה לשרת ביניים. בעבר, מספר היציאה הופיע רק בשורה CONNECT.
- המערכת לא שולחת יותר כותרות של סוכן משתמש והרשאה לשרת proxy מבקשות שנשלחות במנהרה לשרת ה-proxy.
המערכת לא שולחת יותר כותרת להרשאה של שרת proxy ב-Http(s)URLConnection עם מנהרה לשרת ה-proxy, בעת הגדרת המנהרה. במקום זאת, המערכת יוצרת כותרת של הרשאת proxy ושולחת אותה ל-proxy כשה-proxy שולח HTTP 407 בתגובה לבקשה הראשונית.
באופן דומה, המערכת כבר לא מעתיקה את הכותרת של סוכן המשתמש מהבקשה שעוברת במנהרה לבקשת ה-proxy שמגדירה את המנהרה. במקום זאת, הספרייה יוצרת כותרת של סוכן משתמש לבקשה הזו.
- אם שיטת connect() שבוצעה קודם נכשלה, ה-method
send(java.net.DatagramPacket)
תשליך SocketException.- אם יש שגיאה פנימית, הפונקציה DatagramSocket.connect() מגדירה את pendingSocketException. לפני Android 8.0, קריאה חוזרת של recv() זרקה SocketException, גם אם קריאה של send() הייתה מצליחה. כדי לשמור על עקביות, בשתי הקריאות מתרחשת עכשיו הודעת SocketException.
- InetAddress.isReachable() מנסה את ה-ICMP לפני חזרה לפרוטוקול TCP Echo.
- יכול להיות שחלק מהמארחים שסוגרים את יציאה 7 (TCP Echo), כמו google.com, יהיו עכשיו נגישים אם הם יקבלו את פרוטוקול ICMP Echo.
- אם לא ניתן להגיע למארחים מסוימים, השינוי הזה אומר שיחלפו פי שניים יותר זמן עד שהקריאה תוחזר.
Bluetooth
בגרסה 8.0 של Android (רמת API 26) מתבצעים השינויים הבאים באורך הנתונים שמשחזרת השיטה ScanRecord.getBytes()
:
- השיטה
getBytes()
לא מבוססת על הנחות לגבי מספר הבייטים שהתקבלו. לכן, לא כדאי להסתמך על מספר מינימלי או מקסימלי של בייטים שמוחזרים. במקום זאת, צריך להעריך את האורך של המערך שנוצר. - מכשירים שתואמים ל-Bluetooth 5 עשויים להחזיר אורך נתונים שחורג מהאורך המקסימלי הקודם של כ-60 בייטים.
- אם מכשיר מרוחק לא מספק תגובה לסריקה, יכול להיות שיוחזר גם פחות מ-60 בייטים.
קישוריות חלקה
בגרסה 8.0 של Android (רמת API 26) נוספו כמה שיפורים להגדרות ה-Wi-Fi כדי שיהיה קל יותר לבחור את רשת ה-Wi-Fi שמספקת את חוויית המשתמש הטובה ביותר. שינויים ספציפיים כוללים:
- שיפורים ביציבות ובאמינות.
- ממשק משתמש אינטואיטיבי יותר לקריאה.
- תפריט מאוחד של העדפות Wi-Fi.
- במכשירים תואמים, הפעלה אוטומטית של Wi-Fi כשיש רשת שמורה באיכות גבוהה בקרבת מקום.
אבטחה
ב-Android מגרסה 8.0 יש את השינויים הבאים שקשורים לאבטחה:
- הפלטפורמה כבר לא תומכת ב-SSLv3.
- כשמקשרים HTTPS לשרת שמטמיע באופן שגוי את המשא ומתן על גרסת פרוטוקול TLS,
HttpsURLConnection
לא מנסה יותר את הפתרון החלופי של חזרה לגרסאות קודמות של פרוטוקול TLS וניסיון חוזר. - ב-Android 8.0 (רמת API 26) חל מסנן של Secure Computing (SECCOMP) על כל האפליקציות. רשימת הקריאות למערכת (syscalls) המותרות מוגבלת לאלה שנחשפות דרך bionic. למרות שיש כמה מערכות קריאה אחרות לתאימות לאחור, אנחנו ממליצים לא להשתמש בהן.
- האובייקטים מסוג
WebView
באפליקציה פועלים עכשיו במצב מרובה תהליכים. תוכן האינטרנט מטופל בתהליך נפרד ומבודד מהתהליך של האפליקציה המכילה, כדי לשפר את האבטחה. -
לא ניתן יותר להניח שקבצי APK נמצאים בספריות ששמותיהן מסתיימים ב--1 או ב--2. האפליקציות צריכות להשתמש ב-
sourceDir
כדי לקבל את הספרייה, ולא להסתמך ישירות על הפורמט של הספרייה. - מידע על שיפורי האבטחה שקשורים לשימוש בספריות מקוריות זמין במאמר ספריות מקוריות.
בנוסף, ב-Android 8.0 (רמת API 26) מוצגים השינויים הבאים שקשורים להתקנת אפליקציות לא ידועות ממקורות לא מוכרים:
- הערך של ההגדרה הקודמת
INSTALL_NON_MARKET_APPS
הוא עכשיו תמיד 1. כדי לקבוע אם מקור לא ידוע יכול להתקין אפליקציות באמצעות מנהל ההתקנה של החבילה, צריך להשתמש במקום זאת בערך המוחזר שלcanRequestPackageInstalls()
. - אם מנסים לשנות את הערך של
INSTALL_NON_MARKET_APPS
באמצעותsetSecureSetting()
, מתקבלת הודעת השגיאהUnsupportedOperationException
. כדי למנוע ממשתמשים להתקין אפליקציות לא מוכרות באמצעות מקורות לא מוכרים, צריך להחיל במקום זאת את הגבלת המשתמשDISALLOW_INSTALL_UNKNOWN_SOURCES
. -
הגבלת המשתמש
DISALLOW_INSTALL_UNKNOWN_SOURCES
מופעלת באופן אוטומטי בפרופילים מנוהלים שנוצרים במכשירים עם מערכת הפעלה Android מגרסה 8.0 (API ברמה 26). בפרופילים מנוהלים קיימים במכשירים ששודרגו ל-Android 8.0, ההגבלה על המשתמשDISALLOW_INSTALL_UNKNOWN_SOURCES
מופעלת באופן אוטומטי, אלא אם הבעלים של הפרופיל השבית את ההגבלה הזו באופן מפורש (לפני השדרוג) על ידי הגדרת הערךINSTALL_NON_MARKET_APPS
ל-1.
פרטים נוספים על התקנת אפליקציות לא מוכרות זמינים במדריך הרשאות התקנה של אפליקציות לא מוכרות.
הנחיות נוספות לשיפור האבטחה באפליקציה זמינות במאמר אבטחה למפתחי Android.
פרטיות
בגרסה 8.0 של Android (רמת API 26) בוצעו בפלטפורמה השינויים הבאים שקשורים לפרטיות.
- הפלטפורמה מטפלת עכשיו במזהים באופן שונה.
-
באפליקציות שהותקנו לפני עדכון OTA לגרסה של Android 8.0 (רמת API 26), הערך של
ANDROID_ID
נשאר ללא שינוי, אלא אם האפליקציה הוסרה ולאחר מכן הותקנה מחדש אחרי העדכון OTA. כדי לשמור את הערכים אחרי התקנות מחדש לאחר עדכון OTA, המפתחים יכולים לשייך את הערכים הישנים והחדשים באמצעות גיבוי של מפתח/ערך. - באפליקציות שמותקנות במכשיר עם Android מגרסה 8.0, הערך של
ANDROID_ID
מוגדר עכשיו לכל מפתח חתימה של אפליקציה ולכל משתמש. הערך שלANDROID_ID
הוא ייחודי לכל שילוב של מפתח לחתימה על אפליקציות, משתמש ומכשיר. כתוצאה מכך, אפליקציות עם מפתחות חתימה שונים שפועלות באותו מכשיר כבר לא רואות את אותו מזהה Android (גם אם מדובר באותו משתמש). - הערך של
ANDROID_ID
לא משתנה בהסרה או בהתקנה מחדש של החבילה, כל עוד מפתח החתימה זהה (והאפליקציה לא הותקנה לפני OTA לגרסת Android 8.0). - הערך של
ANDROID_ID
לא משתנה גם אם עדכון מערכת גורם למפתח החתימה על החבילה להשתנות. - במכשירים שכוללים את Google Play Services ואת מזהה הפרסום, חייבים להשתמש ב
מזהה הפרסום. מערכת פשוטה וסטנדרטית למונטיזציה של אפליקציות. מזהה הפרסום הוא מזהה ייחודי שניתן לאיפוס על ידי המשתמש ומשמש לצורך פרסום. הוא מסופק על ידי Google Play Services.
יצרני מכשירים אחרים אמורים להמשיך לספק את
ANDROID_ID
.
-
באפליקציות שהותקנו לפני עדכון OTA לגרסה של Android 8.0 (רמת API 26), הערך של
- שאילתה על נכס המערכת
net.hostname
מניבה תוצאה null.
רישום ביומן של חריגים שלא זוהו
אם אפליקציה מתקינה Thread.UncaughtExceptionHandler
שלא מבצע קריאה ל-Thread.UncaughtExceptionHandler
שמוגדר כברירת מחדל, המערכת לא תהרוג את האפליקציה אם מתרחשת חריגה שלא תפסה. החל מגרסה Android 8.0 (רמת API 26), המערכת מתעדת ביומן את סטאק-טראק החריגה במצב כזה. בגרסאות קודמות של הפלטפורמה, המערכת לא הייתה מתעדת ביומן את סטאק-טראק החריגה.
מומלץ שתמיד תתבצע קריאה של הטמעות בהתאמה אישית של Thread.UncaughtExceptionHandler
למטפל ברירת המחדל. אפליקציות שתואמות להמלצה הזו לא מושפעות מהשינוי ב-Android 8.0.
שינוי בחתימה של findViewById()
כל המופעים של השיטה findViewById()
מחזירים עכשיו את הערך
<T extends View> T
במקום View
. השינוי הזה משפיע על הדברים הבאים:
- כתוצאה מכך, יכול להיות שבקוד הקיים יהיה עכשיו סוג החזרה לא ברור. לדוגמה, אם יש גם
someMethod(View)
וגםsomeMethod(TextView)
שמקבל את התוצאה של הקריאהfindViewById()
. - כשמשתמשים בשפת המקור Java 8, צריך לבצע הטמעה מפורשת ל-
View
כשסוג ההחזרה לא מוגבל (לדוגמה,assertNotNull(findViewById(...)).someViewMethod())
). - כדי לעדכן את סוג ההחזרה של שיטות
findViewById()
לא סופיות (למשל,Activity.findViewById()
), צריך לבצע החלפה.
שינוי בנתוני השימוש של ספק אנשי הקשר
בגרסאות קודמות של Android, הרכיב של ספק אנשי הקשר מאפשר למפתחים לקבל נתוני שימוש לגבי כל איש קשר. נתוני השימוש האלה חושפים מידע על כל כתובת אימייל ועל כל מספר טלפון שמשויכים לאיש קשר, כולל מספר הפעמים שבהן יצרתם קשר עם איש הקשר והפעם האחרונה שבה יצרתם קשר עם איש הקשר. אפליקציות שמבקשות את ההרשאה READ_CONTACTS
יכולות לקרוא את הנתונים האלה.
אפליקציות עדיין יכולות לקרוא את הנתונים האלה אם הן מבקשות את ההרשאה READ_CONTACTS
. בגרסה 8.0 של Android (רמת API 26) ואילך, שאילתות לגבי נתוני שימוש מחזירות הערכות גסות במקום ערכים מדויקים. מערכת Android שומרת את הערכים המדויקים באופן פנימי, כך שהשינוי הזה לא משפיע על ממשק ה-API להשלמה אוטומטית.
שינוי ההתנהגות הזה משפיע על הפרמטרים הבאים של השאילתות:
טיפול באוספים
הפונקציות AbstractCollection.removeAll()
ו-AbstractCollection.retainAll()
תמיד גורמות להשלכת NullPointerException
. בעבר, ההשלכה של NullPointerException
לא התרחשה כשהאוסף היה ריק. השינוי הזה מביא את ההתנהגות לידי הסכמה עם המסמכים.
Android לארגונים
ב-Android 8.0 (רמת API 26) השתנה ההתנהגות של ממשקי API מסוימים ותכונות מסוימות באפליקציות ארגוניות, כולל בקרי מדיניות המכשיר (DPC). השינויים כוללים:
- התנהגויות חדשות שיעזרו לאפליקציות לתמוך בפרופילים של עבודה במכשירים מנוהלים באופן מלא.
- שינויים בטיפול בעדכוני מערכת, באימות אפליקציות ובאימות, כדי לשפר את תקינות המכשיר והמערכת.
- שיפורים בחוויית המשתמש להקצאת הרשאות ידנית, להתראות, למסך 'אחרונים' ול-VPN שפועל כל הזמן.
במאמר Android בארגון מפורטים כל השינויים לארגונים ב-Android 8.0 (רמת API 26), ומוסבר איך הם עשויים להשפיע על האפליקציה שלכם.
אפליקציות שמטרגטות את Android 8.0
השינויים האלה בהתנהגות חלים רק על אפליקציות שמטרגטות
ל-Android 8.0 (רמת API 26) ואילך. אפליקציות שמתאימות ל-Android 8.0 או שמגדירות את targetSdkVersion
ל-Android 8.0 ואילך צריכות לשנות את האפליקציות שלהן כדי לתמוך בהתנהגויות האלה בצורה תקינה, במקרים הרלוונטיים.
חלונות התראות
אפליקציות שמשתמשות בהרשאה SYSTEM_ALERT_WINDOW
כבר לא יכולות להשתמש בסוגי החלונות הבאים כדי להציג חלונות התראה מעל אפליקציות אחרות וחלונות מערכת:
במקום זאת, האפליקציות צריכות להשתמש בסוג חלון חדש שנקרא TYPE_APPLICATION_OVERLAY
.
כשמשתמשים בסוג החלון TYPE_APPLICATION_OVERLAY
כדי להציג חלונות התראה באפליקציה, חשוב לזכור את המאפיינים הבאים של סוג החלון החדש:
- חלונות ההתראות של האפליקציה תמיד מופיעים מתחת לחלונות קריטיים של המערכת, כמו שורת הסטטוס וממשקי IME.
- המערכת יכולה להזיז חלונות או לשנות את הגודל שלהם, אם הם משתמשים בסוג החלון
TYPE_APPLICATION_OVERLAY
, כדי לשפר את התצוגה במסך. - כשפותחים את חלונית ההתראות, המשתמשים יכולים לגשת להגדרות כדי למנוע מאפליקציה להציג חלונות התראה שמוצגים באמצעות סוג החלון
TYPE_APPLICATION_OVERLAY
.
התראות על שינויים בתוכן
ב-Android 8.0 (רמת API 26) יש שינוי בהתנהגות של ContentResolver.notifyChange()
ושל registerContentObserver(Uri, boolean, ContentObserver)
באפליקציות שמטרגטות את Android 8.0.
מעכשיו, ממשקי ה-API האלה דורשים הגדרה של ContentProvider
תקין עבור הרשות בכל כתובות ה-URI. הגדרת ContentProvider
תקין עם ההרשאות הרלוונטיות תעזור להגן על האפליקציה מפני שינויים בתוכן מפני אפליקציות זדוניות, ותמנע הדלפה של מידע שעשוי להיות פרטי לאפליקציות זדוניות.
הצגת מצב הריכוז
עכשיו אפשר להתמקד גם באובייקטים View
שניתן ללחוץ עליהם כברירת מחדל. אם רוצים שאפשר יהיה ללחוץ על אובייקט View
אבל לא להעביר אליו את המיקוד, צריך להגדיר את המאפיין
android:focusable
לערך false
בקובץ ה-XML של הפריסה שמכיל את View
, או להעביר את הערך false
אל setFocusable()
בלוגיקה של ממשק המשתמש של האפליקציה.
התאמה של סוכן משתמש בזיהוי דפדפנים
בגרסאות Android 8.0 (רמת API 26) ואילך נכללת המחרוזת של מזהה ה-build OPR
. התאמות מסוימות של דפוסים עלולות לגרום ללוגיקה של זיהוי הדפדפן לזהות בטעות דפדפן שאינו Opera בתור Opera.
דוגמה להתאמת תבניות כזו יכולה להיות:
if(p.match(/OPR/)){k="Opera";c=p.match(/OPR\/(\d+.\d+)/);n=new Ext.Version(c[1])}
כדי למנוע בעיות שנובעות מזיהוי שגוי כזה, צריך להשתמש במחרוזת שאינה OPR
כתוצאה של התאמה לדפוס בדפדפן Opera.
אבטחה
השינויים הבאים משפיעים על האבטחה ב-Android 8.0 (רמת API 26):
- אם בתצורה של אבטחת הרשת של האפליקציה לא מופיעה תמיכה בתנועה ללא הצפנה, לאובייקטים
WebView
של האפליקציה אין גישה לאתרים דרך HTTP. כל אובייקטWebView
חייב להשתמש ב-HTTPS. - הגדרת המערכת התרת מקורות לא ידועים הוסרה. במקום זאת, ההרשאה התקנת אפליקציות לא מוכרות מנהלת את ההתקנות של אפליקציות לא מוכרות ממקורות לא ידועים. מידע נוסף על ההרשאה החדשה הזו זמין במדריך הרשאות להתקנת אפליקציות לא מוכרות.
הנחיות נוספות לשיפור האבטחה באפליקציה זמינות במאמר אבטחה למפתחי Android.
גישה לחשבון וחשיפה
ב-Android 8.0 (רמת API 26), אפליקציות לא יכולות יותר לקבל גישה לחשבונות משתמשים, אלא אם לאימות החשבונות יש בעלות על החשבונות או שהמשתמש מעניק את הגישה הזו. ההרשאה GET_ACCOUNTS
כבר לא מספיקה. כדי לקבל גישה לחשבון, אפליקציות צריכות להשתמש ב-AccountManager.newChooseAccountIntent()
או בשיטה ספציפית למאמת החשבונות. אחרי קבלת גישה לחשבונות, אפליקציה יכולה להפעיל את AccountManager.getAccounts()
כדי לגשת אליהם.
ב-Android 8.0 הופסק השימוש ב-LOGIN_ACCOUNTS_CHANGED_ACTION
. במקום זאת, אפליקציות צריכות להשתמש ב-addOnAccountsUpdatedListener()
כדי לקבל עדכונים על חשבונות במהלך זמן הריצה.
מידע על ממשקי API ושיטות חדשים שנוספו לגישה לחשבון ולחשיפה שלו זמין בקטע גישה לחשבון וחשיפה בקטע 'ממשקי API חדשים' במסמך הזה.
פרטיות
השינויים הבאים משפיעים על הפרטיות ב-Android 8.0 (רמת API 26).
-
מאפייני המערכת
net.dns1
,net.dns2
,net.dns3
ו-net.dns4
כבר לא זמינים – שינוי שמשפר את הפרטיות בפלטפורמה. -
כדי לקבל מידע על רשתות, כמו שרתי DNS, אפליקציות עם ההרשאה
ACCESS_NETWORK_STATE
יכולות לרשום אובייקטNetworkRequest
אוNetworkCallback
. הכיתות האלה זמינות ב-Android מגרסה 5.0 (רמת API 21) ואילך. -
Build.SERIAL הוצא משימוש.
אפליקציות שצריכות לדעת את המספר הסידורי של החומרה צריכות להשתמש במקום זאת בשיטה החדשה
Build.getSerial()
, שמחייבת את ההרשאהREAD_PHONE_STATE
. -
ה-API של
LauncherApps
לא מאפשר יותר לאפליקציות בפרופיל העבודה לקבל מידע על הפרופיל הראשי. כשמשתמש נמצא בפרופיל עבודה, ה-API שלLauncherApps
פועל כאילו לא מותקנות אפליקציות בפרופילים אחרים באותה קבוצת פרופילים. כמו קודם, ניסיונות לגשת לפרופילים לא קשורים גורמים ל-Security חריגים.
הרשאות
לפני Android 8.0 (רמת API 26), אם אפליקציה ביקשה הרשאה במהלך זמן הריצה וההרשאה אושרה, המערכת גם העניקה לאפליקציה בטעות את שאר ההרשאות שהשתייכו לאותה קבוצת הרשאות ונרשמו במניפסט.
באפליקציות שמטרגטות את Android 8.0, הבעיה הזו תוקנה. האפליקציה תקבל רק את ההרשאות שביקשה באופן מפורש. עם זאת, אחרי שהמשתמש מעניק הרשאה לאפליקציה, כל הבקשות הבאות להרשאות בקבוצת ההרשאות הזו יתקבלו באופן אוטומטי.
לדוגמה, נניח שאפליקציה מפרטת את READ_EXTERNAL_STORAGE
וגם את WRITE_EXTERNAL_STORAGE
במניפסט שלה.
האפליקציה מבקשת את READ_EXTERNAL_STORAGE
והמשתמש נתן את ההרשאה הזו. אם האפליקציה מטרגטת לרמת API 25 או נמוכה יותר, המערכת מעניקה גם את ההרשאה WRITE_EXTERNAL_STORAGE
בו-זמנית, כי היא שייכת לאותה קבוצת הרשאות STORAGE
ורשומה גם במניפסט. אם האפליקציה מטרגטת את Android 8.0 (רמת API 26), המערכת מעניקה רק את ההרשאה READ_EXTERNAL_STORAGE
באותו זמן. עם זאת, אם האפליקציה מבקשת מאוחר יותר את ההרשאה WRITE_EXTERNAL_STORAGE
, המערכת מעניקה את ההרשאה הזו באופן מיידי בלי להציג בקשה למשתמש.
מדיה
- המסגרת יכולה לבצע בעצמה השתקה אוטומטית של אודיו. במקרה כזה, כשאפליקציה אחרת מבקשת להתמקד באמצעות
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
, האפליקציה שמקבלת את המיקוד מפחיתה את עוצמת הקול שלה, אבל בדרך כלל לא מקבלת קריאה חוזרת (callback) עםonAudioFocusChange()
ולא מאבדת את המיקוד האודיו. יש ממשקי API חדשים שאפשר להשתמש בהם כדי לשנות את ההתנהגות הזו באפליקציות שצריכות להשהות את האודיו במקום להנמיע אותו. - כשהמשתמש מבצע שיחת טלפון, שידורי המדיה הפעילים מושתקים במהלך השיחה.
- בכל ממשקי ה-API שקשורים לאודיו, צריך להשתמש ב-
AudioAttributes
במקום בסוגי סטרימינג של אודיו כדי לתאר את תרחיש לדוגמה של הפעלת אודיו. ממשיכים להשתמש בסוגי שידורי אודיו לצורך בקרת עוצמת קול בלבד. שימושים אחרים בסוגים של זרמים עדיין פועלים (לדוגמה, הארגומנטstreamType
ל-constructorAudioTrack
שהוצא משימוש), אבל המערכת מתעדת את הפעולה הזו כשגיאה. - כשמשתמשים ב-
AudioTrack
, אם האפליקציה מבקשת מאגר אודיו גדול מספיק, המסגרת תנסה להשתמש בפלט של מאגר הנתונים הזמני העמוק אם הוא זמין. - ב-Android 8.0 (רמת API 26), הטיפול באירועים של לחצני מדיה שונה:
- אופן הטיפול בלחצני המדיה בפעילות בממשק המשתמש לא השתנה: פעילויות בחזית עדיין מקבלות עדיפות בטיפול באירועים של לחצני מדיה.
- אם הפעילות בחזית לא מטפלת באירוע של לחצן המדיה, המערכת מפנה את האירוע לאפליקציה האחרונה שהפעילה אודיו באופן מקומי. הסטטוס הפעיל, הסימונים ומצב ההפעלה של סשן מדיה לא מובאים בחשבון כדי לקבוע איזו אפליקציה מקבלת אירועים של לחצני מדיה.
- אם שוחרר מהסשן במדיה של האפליקציה,
המערכת תשלח את האירוע של לחצן המדיה אל
MediaButtonReceiver
של האפליקציה, אם יש כזו. - בכל מקרה אחר, המערכת משליכה את האירוע של לחצן המדיה.
ספריות מקוריות
באפליקציות שמטרגטות ל-Android 8.0 (רמת API 26), ספריות מקוריות לא נטענות יותר אם הן מכילות פלח טעינה שניתן לכתיבה ולהפעלה. יכול להיות שחלק מהאפליקציות יפסיקו לפעול בעקבות השינוי אם יש בהן ספריות מקוריות עם מקטעים שגויים של טעינה. זהו אמצעי לחיזוק האבטחה.
מידע נוסף זמין במאמר פלחים שניתנים לכתיבה ולביצוע.
השינויים ב-Linker קשורים לרמת ה-API שאליה האפליקציה מטרגטת. אם יש שינוי במנגנון לקישור ברמת ה-API המטורגט, האפליקציה לא תוכל לטעון את הספרייה. אם מטרגטים לרמת API נמוכה יותר מרמת ה-API שבה מתרחש השינוי ב-linker, תוצג אזהרה ב-logcat.
טיפול באוסף
ב-Android 8.0 (רמת API 26), Collections.sort()
מיושם מעל List.sort()
. המצב ההפוך היה נכון ב-Android 7.x (רמות API 24 ו-25): ההטמעה שמוגדרת כברירת מחדל של List.sort()
נקראת Collections.sort()
.
השינוי הזה מאפשר ל-Collections.sort()
לנצל את היתרונות של הטמעות List.sort()
שהותאמו אופטימלית, אבל יש לו את האילוצים הבאים:
בהטמעות של הפונקציה
List.sort()
אסור לקרוא לפונקציהCollections.sort()
, כי פעולה כזו עלולה לגרום גלישת מחסנית בגלל חזרה אינסופית. במקום זאת, אם רוצים את התנהגות ברירת המחדל בהטמעה שלList
, צריך להימנע משינויים שרלוונטיים ל-sort()
.אם מחלקת הורה מיישמת את
sort()
בצורה לא הולמת, בדרך כלל אפשר לשנות אתList.sort()
באמצעות הטמעה שמבוססת עלList.toArray()
,Arrays.sort()
ו-ListIterator.set()
. לדוגמה:@Override public void sort(Comparator<? super E> c) { Object[] elements = toArray(); Arrays.sort(elements, c); ListIterator<E> iterator = (ListIterator<Object>) listIterator(); for (Object element : elements) { iterator.next(); iterator.set((E) element); } }
ברוב המקרים, אפשר גם לשנות את הערך של
List.sort()
באמצעות הטמעה שמעבירה את הגדרת ברירת המחדל להטמעות שונות בהתאם לרמת ה-API. לדוגמה:@Override public void sort(Comparator<? super E> comparator) { if (Build.VERSION.SDK_INT <= 25) { Collections.sort(this); } else { super.sort(comparator); } }
אם אתם עושים את הפעולה האחרונה רק כי אתם רוצים ששיטה
sort()
תהיה זמינה בכל רמות ה-API, כדאי לתת לה שם ייחודי, כמוsortCompat()
, במקום לשנות אתsort()
.-
Collections.sort()
נחשב עכשיו לשינוי מבני בהטמעות של רשימות שמפעילות אתsort()
. לדוגמה, בגרסאות של הפלטפורמה שקדמו ל-Android 8.0 (רמת API 26), אם היינו מבצעים חזרה עלArrayList
ומפעילים עליו אתsort()
באמצע החזרה, המערכת הייתה זורקתConcurrentModificationException
אם המיון בוצע על ידי קריאה ל-List.sort()
.Collections.sort()
לא החזירה חריג.השינוי הזה מאפשר לפלטפורמה לפעול בצורה עקבית יותר: כל אחת מהגישות האלה מובילה עכשיו ל-
ConcurrentModificationException
.
ההתנהגות של טעינת הכיתה
מערכת Android 8.0 (רמת API 26) בודקת כדי לוודא שמטעמי הכיתות לא מפירים את ההנחות לגבי סביבת זמן הריצה כשטוענים מחלקות חדשות. הבדיקות האלה מתבצעות גם אם יש הפניה לכיתה מ-Java (מ-forName()
), מ-Dalvik bytecode או מ-JNI. הפלטפורמה לא מפריעה לשיחות ישירות מ-Java ל-method loadClass()
, ולא בודקת את התוצאות של שיחות כאלה. ההתנהגות הזו לא אמורה להשפיע על הפעולה של מערכי טעינה של כיתות שמתנהגים בצורה תקינה.
הפלטפורמה בודקת שהתיאורים של הכיתה שהמעבד יוצר תואמים לתיאורים הצפויים. אם המתאר המוחזר לא תואם, הפלטפורמה תשליך שגיאה מסוג NoClassDefFoundError
ותשמור בהודעה מפורטת לגבי אי ההתאמה בחריגה.
הפלטפורמה גם בודקת שהתיאורים של הכיתות המבוקשות תקינים. הבדיקה הזו מזהה קריאות ל-JNI שגורמות לטעינת כיתות באופן עקיף, כמו GetFieldID()
, ומעבירות לכיתות האלה מתארים לא חוקיים. לדוגמה, שדה עם החתימה java/lang/String
לא נמצא כי החתימה הזו לא חוקית. צריך להשתמש בחתימה Ljava/lang/String;
.
הקריאה הזו שונה מקריאה ל-JNI ל-FindClass()
, שבה java/lang/String
הוא שם תקין שמוגדר במלואו.
ב-Android 8.0 (רמת API 26) אין תמיכה במספר מערכי טעינה של כיתות שמנסים להגדיר כיתות באמצעות אותו אובייקט DexFile. ניסיון לעשות זאת יגרום לזמן הריצה של Android להוציא שגיאת InternalError
עם ההודעה "Attempt to register dex file <filename>
with multiple class loaders".
DexFile API הוצא משימוש, ומומלץ מאוד להשתמש במקום זאת באחד ממטעני הכיתות של הפלטפורמה, כולל PathClassLoader
או BaseDexClassLoader
.
הערה: אפשר ליצור כמה מעמיסי הכיתות שמפנים לאותו מאגר של קובץ APK או JAR ממערכת הקבצים. בדרך כלל, הפעולה הזו לא גורמת לשימוש רב בזיכרון: אם קובצי ה-DEX בקונטיינר מאוחסנים במקום להיות דחוסים, הפלטפורמה יכולה לבצע עליהם פעולת mmap
במקום לחלץ אותם ישירות. עם זאת, אם הפלטפורמה צריכה לחלץ את קובץ ה-DEX מהקונטיינר, הפנייה לקובץ DEX באופן הזה עשויה לצרוך הרבה זיכרון.
ב-Android, כל מערכי הטעינה של הכיתות נחשבים ככאלה שיכולים לפעול במקביל. כשיש תחרות בין כמה חוטים לטעינה של אותה כיתה באמצעות אותו מעבד כיתה, החוט הראשון שמסיים את הפעולה מנצח והתוצאה משמשת את שאר החוטים. ההתנהגות הזו מתרחשת ללא קשר לכך שטען הכיתות החזיר את אותה הכיתה, החזיר כיתה אחרת או הפעיל חריגה. בעלי הפלטפורמה מתעלמת מחריגים כאלה בצורה שקטה.
זהירות: בגרסאות של הפלטפורמה שקודמות לגרסה Android 8.0 (רמת API 26), הפרת ההנחות האלה עלולה להוביל להגדרה של אותה כיתה כמה פעמים, לזיהום אשכול עקב בלבול בין כיתות ולתוצאות לא רצויות אחרות.