תכונות וממשקי API של Android 8.1

‫Android 8.1 (רמת API‏ 27) כוללת מגוון תכונות ויכולות חדשות למשתמשים ולמפתחים. במסמך הזה מפורטים החידושים למפתחים.

(Go edition)‏ Android Oreo‏

‫ Android Go הוא מיזם שלנו שמטרתו לייעל את חוויית השימוש ב-Android עבור מיליארדי אנשים שמתחברים לאינטרנט ברחבי העולם. החל מ-Android 8.1, אנחנו הופכים את Android לפלטפורמה מצוינת למכשירים ברמת הכניסה. התכונות בהגדרה של Android Oreo (מהדורת Go) כוללות:

  • אופטימיזציות של הזיכרון. שיפור השימוש בזיכרון בפלטפורמה כדי להבטיח שאפליקציות יוכלו לפעול ביעילות במכשירים עם זיכרון RAM בנפח 1GB או פחות.
  • אפשרויות טירגוט גמישות. קבועים חדשים של תכונות חומרה שמאפשרים לכם לטרגט את הפצת האפליקציות שלכם למכשירים עם זיכרון RAM רגיל או נמוך דרך Google Play.
  • ‫Google Play. כל האפליקציות יהיו זמינות במכשירים עם Android Oreo (מהדורת Go), אבל ב-Google Play תהיה חשיפה לאפליקציות שעברו אופטימיזציה ספציפית על ידי מפתחים כדי לספק חוויה מצוינת למיליארדי אנשים, בהתאם להנחיות בנושא פיתוח למיליארדי משתמשים.

עדכנו את ההנחיות בנושא פיתוח אפליקציות למיליארדי משתמשים, והוספנו הנחיות נוספות בנושא אופטימיזציה של האפליקציה למכשירים עם Android Oreo (מהדורת Go). לרוב המפתחים, הדרך הכי טובה להתכונן למכשירים עם Android Oreo (מהדורת Go) היא לבצע אופטימיזציה של קובץ ה-APK הקיים או להשתמש ב תכונת ה-APK המרובים של Google Play כדי לטרגט גרסה של קובץ ה-APK למכשירים עם זיכרון RAM נמוך. חשוב לזכור ש הפחתת המשקל של האפליקציה ושיפור היעילות שלה מועילים לכל הקהל, בלי קשר למכשיר.

Neural Networks API

‫Neural Networks API מספק חישוב והסקת מסקנות מואצים למסגרות למידת מכונה במכשיר, כמו TensorFlow Lite – ספריית ה-ML של Google לנייד, שפועלת בפלטפורמות שונות – וגם Caffe2 ואחרות. אפשר להוריד את TensorFlow Lite ולעיין במסמכים שלו במאגר הקוד הפתוח. ‫TensorFlow Lite פועל עם Neural Networks API כדי להריץ מודלים כמו MobileNets,‏ Inception v3 ו- Smart Reply ביעילות במכשיר הנייד.

עדכונים של מסגרת המילוי האוטומטי

‫Android 8.1 (רמת API‏ 27) כולל כמה שיפורים ב-Autofill Framework שאפשר לשלב באפליקציות.

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

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

ב-Android 8.1, שירותי המילוי האוטומטי יכולים גם להתאים אישית את ממשק המשתמש של השמירה, כי נוספה תמיכה ב-CustomDescription and Validatorבתוך SaveInfo.

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

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

התראות

ב-Android 8.1 בוצעו השינויים הבאים בהתראות:

  • עכשיו אפליקציות יכולות להשמיע צליל התראה רק פעם אחת בשנייה. צלילי התראות שחורגים מהקצב הזה לא מתווספים לתור ונעלמים. השינוי הזה לא משפיע על היבטים אחרים של התנהגות ההתראות, והודעות ההתראות עדיין מתפרסמות כצפוי.
  • במכשירים עם מערכת Android וזיכרון RAM נמוך, שמוחזרת בהם התוצאה true כשמבצעים קריאה ל-ActivityManager.isLowRamDevice(), אין תמיכה ב-NotificationListenerService וב-ConditionProviderService.

עדכון של EditText

החל מרמת API‏ 27, ה-method‏ EditText.getText() מחזיר Editable. לפני כן הוא החזיר CharSequence. השינוי הזה תואם לגרסאות קודמות, כי Editable מטמיע את CharSequence.

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

פעולות של גלישה בטוחה שמתבצעות באופן פרוגרמטי

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

ב-Android 8.1, אפשר להגדיר באופן פרוגרמטי איך האפליקציה מגיבה לאיום מוכר:

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

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

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

AndroidManifest.xml

<manifest>
    <application>
        ...
        <meta-data android:name="android.webkit.WebView.EnableSafeBrowsing"
                   android:value="true" />
    </application>
</manifest>

MyWebActivity.java

Kotlin

private var superSafeWebView: WebView? = null
private var safeBrowsingIsInitialized: Boolean = false

// ...

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    superSafeWebView = WebView(this).apply {
        webViewClient = MyWebViewClient()
        safeBrowsingIsInitialized = false
        startSafeBrowsing(this@SafeBrowsingActivity, { success ->
            safeBrowsingIsInitialized = true
            if (!success) {
                Log.e("MY_APP_TAG", "Unable to initialize Safe Browsing!")
            }
        })
    }
}

Java

private WebView superSafeWebView;
private boolean safeBrowsingIsInitialized;

// ...

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    superSafeWebView = new WebView(this);
    superSafeWebView.setWebViewClient(new MyWebViewClient());
    safeBrowsingIsInitialized = false;

    superSafeWebView.startSafeBrowsing(this, new ValueCallback<Boolean>() {
        @Override
        public void onReceiveValue(Boolean success) {
            safeBrowsingIsInitialized = true;
            if (!success) {
                Log.e("MY_APP_TAG", "Unable to initialize Safe Browsing!");
            }
        }
    });
}

MyWebViewClient.java

Kotlin

class MyWebViewClient : WebViewClient() {
    // Automatically go "back to safety" when attempting to load a website that
    // Safe Browsing has identified as a known threat. An instance of WebView
    // calls this method only after Safe Browsing is initialized, so there's no
    // conditional logic needed here.
    override fun onSafeBrowsingHit(
            view: WebView,
            request: WebResourceRequest,
            threatType: Int,
            callback: SafeBrowsingResponse
    ) {
        // The "true" argument indicates that your app reports incidents like
        // this one to Safe Browsing.
        callback.backToSafety(true)
        Toast.makeText(view.context, "Unsafe web page blocked.", Toast.LENGTH_LONG).show()
    }
}

Java

public class MyWebViewClient extends WebViewClient {
    // Automatically go "back to safety" when attempting to load a website that
    // Safe Browsing has identified as a known threat. An instance of WebView
    // calls this method only after Safe Browsing is initialized, so there's no
    // conditional logic needed here.
    @Override
    public void onSafeBrowsingHit(WebView view, WebResourceRequest request,
            int threatType, SafeBrowsingResponse callback) {
        // The "true" argument indicates that your app reports incidents like
        // this one to Safe Browsing.
        callback.backToSafety(true);
        Toast.makeText(view.getContext(), "Unsafe web page blocked.",
                Toast.LENGTH_LONG).show();
    }
}

כלי לחילוץ תמונות ממוזערות של סרטונים

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

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

Shared memory API

ב-Android 8.1 (רמת API‏ 27) הושק SharedMemory API חדש. המחלקות האלה מאפשרות ליצור, למפות ולנהל מופע אנונימי של SharedMemory. אתם מגדירים את ההגנה על הזיכרון באובייקט SharedMemory לקריאה או לכתיבה, ומכיוון שאובייקט SharedMemory הוא Parcelable, אתם יכולים להעביר אותו בקלות לתהליך אחר באמצעות AIDL.

‫SharedMemory API פועל בשילוב עם מתקן ASharedMemory ב-NDK. ‫ASharedMemory נותן גישה לתיאור קובץ, שאפשר למפות אותו לקריאה ולכתיבה. זו דרך מצוינת לשתף כמויות גדולות של נתונים בין אפליקציות או בין כמה תהליכים באפליקציה אחת.

WallpaperColors API

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

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

  • כדי ליצור אובייקט WallpaperColors באמצעות שלושה צבעים, יוצרים מופע של המחלקה WallpaperColors על ידי העברת הצבע הראשי, המשני והשלישוני. הצבע הראשי לא יכול להיות ריק (null).
  • כדי ליצור אובייקט WallpaperColors ממפת סיביות (bitmap), צריך לקרוא ל-method‏ fromBitmap() ולהעביר את מקור מפת הסיביות כפרמטר.
  • כדי ליצור אובייקט WallpaperColors מ-drawable, צריך לקרוא ל-method‏ fromDrawable() ולהעביר את מקור ה-drawable כפרמטר.

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

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

כדי להוסיף listener לשינויים בצבע, אפשר לקרוא ל-method‏ addOnColorsChangedListener(). אפשר גם לקרוא לשיטה getWallpaperColors() כדי לאחזר את הצבעים הראשיים של טפט.

עדכונים לטביעת האצבע

במחלקת FingerprintManager הוצגו קודי השגיאה הבאים:

  • ‫FINGERPRINT_ERROR_LOCKOUT_PERMANENT – המשתמש ניסה יותר מדי פעמים לפתוח את נעילת המכשיר באמצעות קורא טביעות האצבע.
  • ‫FINGERPRINT_ERROR_VENDOR – אירעה שגיאה בקורא טביעות האצבעות הספציפי לספק.

עדכונים בנושא קריפטוגרפיה

בוצעו מספר שינויים בקריפטוגרפיה ב-Android 8.1:

  • הוטמעו אלגוריתמים חדשים ב-Conscrypt. ההטמעה של Conscrypt מועדפת על פני ההטמעה הקיימת של Bouncy Castle. האלגוריתמים החדשים כוללים:
    • AlgorithmParameters:GCM
    • KeyGenerator:AES
    • KeyGenerator:DESEDE
    • KeyGenerator:HMACMD5
    • KeyGenerator:HMACSHA1
    • KeyGenerator:HMACSHA224
    • KeyGenerator:HMACSHA256
    • KeyGenerator:HMACSHA384
    • KeyGenerator:HMACSHA512
    • SecretKeyFactory:DESEDE
    • Signature:NONEWITHECDSA
  • ‫Cipher.getParameters().getParameterSpec(IvParameterSpec.class) כבר לא פועל באלגוריתמים שמשתמשים ב-GCM. במקום זאת, צריך להשתמש ב-getParameterSpec(GCMParameterSpec.class).
  • בוצע רפקטורינג של הרבה מחלקות פנימיות של Conscrypt שמשויכות ל-TLS. מכיוון שמפתחים ניגשים לפעמים ל-shims באופן רפלקטיבי, הם נשארו במקומם כדי לתמוך בשימוש הקודם, אבל חלק מהפרטים השתנו. לדוגמה, בעבר שקעים היו מסוג OpenSSLSocketImpl, אבל עכשיו הם מסוג ConscryptFileDescriptorSocket או ConscryptEngineSocket, שניהם הרחבה של OpenSSLSocketImpl.
  • השיטות SSLSession ששימשו להקפיץ הודעת שגיאה IllegalArgumentException כשמועברת אליהן הפניה null, מקפיצות עכשיו את הודעת השגיאה NullPointerException.
  • ה-RSA KeyFactory כבר לא מאפשר יצירה של מפתחות ממערכי בייטים שגדולים מהמפתח המוצפן. שיחות אל generatePrivate() ו-generatePublic() שמספקות KeySpec שבהן מבנה המפתח לא ממלא את כל המאגר יגרמו ל-InvalidKeySpecException.
  • כשקריאת socket מופרעת בגלל סגירת ה-socket, בעבר Conscrypt החזיר ‎-1 מהקריאה. הקריאה זורקת עכשיו את השגיאה SocketException.
  • השתנה אוסף אישורי ה-CA ברמה הבסיסית. בעיקר הוסרו מספר רב של אישורים שיצאו משימוש, אבל גם הוסרו אישורי הבסיס של WoSign ו-StartCom. מידע נוסף על ההחלטה הזו זמין בפוסט בבלוג האבטחה של Google בנושא הסרה סופית של האמון באישורים של WoSign ו-StartCom.