מערכת Android מספקת כמה ממשקי API שיעזרו לכם לנהל את
WebView
האובייקטים שמציגים תוכן מהאינטרנט באפליקציה שלכם.
בדף הזה מוסבר איך להשתמש בממשקי ה-API האלה כדי לעבוד עם WebViewאובייקטים בצורה יעילה יותר, ולשפר את היציבות והאבטחה של האפליקציה.
Version API
החל מ-Android 7.0 (רמת API 24), המשתמשים יכולים לבחור מבין כמה חבילות שונות להצגת תוכן אינטרנט באובייקט WebView.
הספרייה Jetpack Webkit
כוללת את השיטה getCurrentWebViewPackage()
לאחזור מידע שקשור לחבילה שמציגה תוכן אינטרנט באפליקציה. השיטה הזו שימושית כשמנתחים שגיאות שמתרחשות רק כשהאפליקציה מנסה להציג תוכן אינטרנט באמצעות הטמעה של חבילה מסוימת של WebView.
כדי להשתמש בשיטה הזו, צריך להוסיף את הלוגיקה שמוצגת בקטע הקוד הבא:
Kotlin
val webViewPackageInfo = WebViewCompat.getCurrentWebViewPackage(appContext) Log.d("MY_APP_TAG", "WebView version: ${webViewPackageInfo.versionName}")
Java
PackageInfo webViewPackageInfo = WebViewCompat.getCurrentWebViewPackage(appContext); Log.d("MY_APP_TAG", "WebView version: " + webViewPackageInfo.versionName);
שירות הגלישה הבטוחה של Google
כדי לספק למשתמשים חוויית גלישה בטוחה יותר, אובייקטים מאמתים כתובות URL באמצעות הגלישה הבטוחה של Google, וכך האפליקציה יכולה להציג למשתמשים אזהרה כשהם מנסים לעבור לאתר שעלול להיות לא בטוח.WebView
למרות שערך ברירת המחדל של EnableSafeBrowsing הוא true, יש מקרים שבהם כדאי להפעיל את הגלישה הבטוחה רק בתנאים מסוימים או להשבית אותה. ב-Android מגרסה 8.0 (רמת API 26) ואילך, אפשר להשתמש ב-setSafeBrowsingEnabled() כדי להפעיל או להשבית את הגלישה הבטוחה לאובייקט WebView ספציפי.
אם רוצים שכל אובייקטי WebView לא ייבדקו על ידי הגלישה הבטוחה, צריך להוסיף את רכיב <meta-data> הבא לקובץ המניפסט של האפליקציה:
<manifest> <application> <meta-data android:name="android.webkit.WebView.EnableSafeBrowsing" android:value="false" /> ... </application> </manifest>
הגדרת פעולות פרוגרמטיות
כשמופע של WebView מנסה לטעון דף ש-Google סיווגה כאיום מוכר, WebView מציג כברירת מחדל דף ביניים שמזהיר את המשתמשים מפני האיום המוכר. במסך הזה יש למשתמשים אפשרות לטעון את כתובת ה-URL בכל זאת או לחזור לדף קודם שהוא בטוח.
אם אתם מטרגטים ל-Android 8.1 (רמת API 27) או לגרסה מתקדמת יותר, אתם יכולים להגדיר באופן פרוגרמטי איך האפליקציה שלכם מגיבה לאיום מוכר באופנים הבאים:
- אתם יכולים להחליט אם האפליקציה תדווח על איומים מוכרים לגלישה בטוחה.
- אתם יכולים להגדיר שהאפליקציה תבצע באופן אוטומטי פעולה מסוימת – כמו חזרה למצב בטוח – בכל פעם שהיא נתקלת בכתובת URL שמסווגת כאיום מוכר.
קטעי הקוד הבאים מראים איך להנחות את המופעים של WebView באפליקציה לחזור תמיד למצב בטוח אחרי שנתקלים באיום מוכר:
MyWebActivity.java
Kotlin
private lateinit var superSafeWebView: WebView private var safeBrowsingIsInitialized: Boolean = false // ... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) superSafeWebView = WebView(this) superSafeWebView.webViewClient = MyWebViewClient() safeBrowsingIsInitialized = false if (WebViewFeature.isFeatureSupported(WebViewFeature.START_SAFE_BROWSING)) { WebViewCompat.startSafeBrowsing(this, ValueCallback<Boolean> { 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; if (WebViewFeature.isFeatureSupported(WebViewFeature.START_SAFE_BROWSING)) { WebViewCompat.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 : WebViewClientCompat() { // Automatically go "back to safety" when attempting to load a website that // Google identifies 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: SafeBrowsingResponseCompat ) { // The "true" argument indicates that your app reports incidents like // this one to Safe Browsing. if (WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY)) { callback.backToSafety(true) Toast.makeText(view.context, "Unsafe web page blocked.", Toast.LENGTH_LONG).show() } } }
Java
public class MyWebViewClient extends WebViewClientCompat { // Automatically go "back to safety" when attempting to load a website that // Google identifies 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, SafeBrowsingResponseCompat callback) { // The "true" argument indicates that your app reports incidents like // this one to Safe Browsing. if (WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY)) { callback.backToSafety(true); Toast.makeText(view.getContext(), "Unsafe web page blocked.", Toast.LENGTH_LONG).show(); } } }
HTML5 Geolocation API
באפליקציות שמטרגטות את Android 6.0 (רמת API 23) ואילך, Geolocation API נתמך רק במקורות מאובטחים, כמו HTTPS. כל בקשה ל-Geolocation API במקורות לא מאובטחים נדחית באופן אוטומטי בלי להפעיל את שיטת onGeolocationPermissionsShowPrompt() המתאימה.
ביטול ההסכמה לאיסוף מדדים
ל-WebView יש אפשרות להעלות נתוני אבחון אנונימיים ל-Google כשהמשתמש נותן את הסכמתו. הנתונים נאספים ברמת האפליקציה
לכל אפליקציה שיוצרת מופע של WebView. כדי להשבית את התכונה הזו, צריך ליצור את התג הבא ברכיב <application> של קובץ המניפסט:
<manifest> <application> ... <meta-data android:name="android.webkit.WebView.MetricsOptOut" android:value="true" /> </application> </manifest>
הנתונים מועלים מאפליקציה רק אם המשתמש מסכים והאפליקציה לא משביתה את האפשרות הזו. מידע נוסף על השבתת הדיווח על נתוני אבחון זמין במאמר פרטיות המשתמש בדיווח של WebView.
Termination Handling API
Termination Handling API מטפל במקרים שבהם תהליך הרינדור של אובייקט WebView נעלם, או בגלל שהמערכת מפסיקה את הרינדור כדי לפנות זיכרון נחוץ, או בגלל שתהליך הרינדור קורס. באמצעות ה-API הזה, אתם מאפשרים לאפליקציה שלכם להמשיך לפעול, גם אם תהליך הרינדור נעלם.
אם רכיב ה-Renderer קורס בזמן טעינה של דף אינטרנט מסוים, ניסיון לטעון את אותו דף שוב עלול לגרום לאובייקט WebView חדש להציג את אותה התנהגות של קריסת ה-Rendering.
קטע הקוד הבא מדגים איך להשתמש ב-API הזה בתוך Activity:
Kotlin
inner class MyRendererTrackingWebViewClient : WebViewClient() { private var mWebView: WebView? = null override fun onRenderProcessGone(view: WebView, detail: RenderProcessGoneDetail): Boolean { if (!detail.didCrash()) { // Renderer is killed because the system ran out of memory. The app // can recover gracefully by creating a new WebView instance in the // foreground. Log.e("MY_APP_TAG", ("System killed the WebView rendering process " + "to reclaim memory. Recreating...")) mWebView?.also { webView -> val webViewContainer: ViewGroup = findViewById(R.id.my_web_view_container) webViewContainer.removeView(webView) webView.destroy() mWebView = null } // By this point, the instance variable "mWebView" is guaranteed to // be null, so it's safe to reinitialize it. return true // The app continues executing. } // Renderer crashes because of an internal error, such as a memory // access violation. Log.e("MY_APP_TAG", "The WebView rendering process crashed!") // In this example, the app itself crashes after detecting that the // renderer crashed. If you handle the crash more gracefully and let // your app continue executing, you must destroy the current WebView // instance, specify logic for how the app continues executing, and // return "true" instead. return false } }
Java
public class MyRendererTrackingWebViewClient extends WebViewClient { private WebView mWebView; @Override public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) { if (!detail.didCrash()) { // Renderer is killed because the system ran out of memory. The app // can recover gracefully by creating a new WebView instance in the // foreground. Log.e("MY_APP_TAG", "System killed the WebView rendering process " + "to reclaim memory. Recreating..."); if (mWebView != null) { ViewGroup webViewContainer = (ViewGroup) findViewById(R.id.my_web_view_container); webViewContainer.removeView(mWebView); mWebView.destroy(); mWebView = null; } // By this point, the instance variable "mWebView" is guaranteed to // be null, so it's safe to reinitialize it. return true; // The app continues executing. } // Renderer crashes because of an internal error, such as a memory // access violation. Log.e("MY_APP_TAG", "The WebView rendering process crashed!"); // In this example, the app itself crashes after detecting that the // renderer crashed. If you handle the crash more gracefully and let // your app continue executing, you must destroy the current WebView // instance, specify logic for how the app continues executing, and // return "true" instead. return false; } }
Renderer Importance API
כשWebViewאובייקטיםפועלים במצב ריבוי תהליכים, יש לכם גמישות מסוימת באופן שבו האפליקציה מטפלת במצבים של חוסר בזיכרון. אפשר להשתמש ב-Renderer Importance API, שהושק ב-Android 8.0, כדי להגדיר מדיניות עדיפות למעבד שהוקצה לאובייקט WebView מסוים. לדוגמה, יכול להיות שתרצו שהחלק העיקרי של האפליקציה ימשיך לפעול כשמערכת הרינדור שמציגה את אובייקטי WebView האפליקציה מושבתת. לדוגמה, אם אתם לא מתכוונים להציג את האובייקט WebView במשך זמן רב, כדי שהמערכת תוכל לפנות את הזיכרון שבו השתמש רכיב הרינדור.
בקטע הקוד הבא אפשר לראות איך מקצים עדיפות לתהליך העיבוד שמשויך לאובייקטים WebView של האפליקציה:
Kotlin
val myWebView: WebView = ... myWebView.setRendererPriorityPolicy(RENDERER_PRIORITY_BOUND, true)
Java
WebView myWebView; myWebView.setRendererPriorityPolicy(RENDERER_PRIORITY_BOUND, true);
בקטע הקוד הזה, העדיפות של רכיב ה-renderer זהה לעדיפות שמוגדרת כברירת מחדל לאפליקציה, או קשורה אליה. הארגומנט true מקטין את העדיפות של רכיב ה-renderer ל-RENDERER_PRIORITY_WAIVED כשאובייקט WebView המשויך כבר לא גלוי. במילים אחרות, ארגומנט true מציין שלאפליקציה לא משנה אם המערכת תשמור על תהליך ה-renderer פעיל. למעשה, רמת העדיפות הנמוכה הזו מגדילה את הסיכוי שתהליך ה-renderer יופסק במצבים של חוסר זיכרון.
מידע נוסף על אופן הטיפול של המערכת במצבים של זיכרון נמוך זמין במאמר בנושא תהליכים ומחזור החיים של האפליקציה.