משתמשים ב-WebView
כדי להעביר אפליקציית אינטרנט או דף אינטרנט כחלק מאפליקציית לקוח. הכיתה WebView
היא תוסף לכיתה View
של Android, שמאפשרת להציג דפי אינטרנט כחלק מתצוגת הפעילות. הוא לא כולל את התכונות של דפדפן אינטרנט מפותח, כמו אמצעי ניווט או שורת כתובות. כברירת מחדל, האפשרות WebView
מציגה דף אינטרנט.
WebView
יכול לעזור לכם לספק באפליקציה מידע שעשוי להיות צורך לעדכן, כמו הסכם משתמש קצה או מדריך למשתמש. באפליקציה ל-Android, אפשר ליצור Activity
שמכיל WebView
, ואז להשתמש בו כדי להציג את המסמך שמתארח באינטרנט.
WebView
יכולה לעזור גם כשהאפליקציה מספקת למשתמש נתונים שדורשים חיבור לאינטרנט כדי לאחזר אותם, כמו אימייל. במקרה כזה, יכול להיות שיהיה קל יותר ליצור WebView
באפליקציה ל-Android שמוצג בו דף אינטרנט עם כל נתוני המשתמש, במקום לבצע בקשת רשת, לנתח את הנתונים ולבצע להם רינדור בפריסה של Android. במקום זאת, תוכלו לעצב דף אינטרנט שמותאם למכשירי Android, ולאחר מכן להטמיע WebView
באפליקציה ל-Android שיטמיע את דף האינטרנט.
במסמך הזה מוסבר איך מתחילים להשתמש ב-WebView
, איך מקשרים JavaScript מדף האינטרנט לקוד בצד הלקוח באפליקציה ל-Android, איך מטפלים בניווט בדפים ואיך מנהלים חלונות כשמשתמשים ב-WebView
.
עבודה עם WebView בגרסאות קודמות של Android
כדי להשתמש בבטחה ביכולות WebView
עדכניות יותר במכשיר שבו האפליקציה פועלת, מוסיפים את הספרייה AndroidX Webkit. זוהי ספרייה סטטית שאפשר להוסיף לאפליקציה כדי להשתמש בממשקי API של android.webkit
שלא זמינים לגרסאות קודמות של הפלטפורמה.
מוסיפים אותו לקובץ build.gradle
באופן הבא:
Kotlin
dependencies { implementation("androidx.webkit:webkit:1.8.0") }
Groovy
dependencies { implementation ("androidx.webkit:webkit:1.8.0") }
פרטים נוספים זמינים בדוגמה WebView
ב-GitHub.
הוספת WebView לאפליקציה
כדי להוסיף WebView
לאפליקציה, אפשר לכלול את האלמנט <WebView>
בפריסה של הפעילות או להגדיר את כל חלון Activity
כ-WebView
ב-onCreate()
.
הוספת רכיב WebView בפריסה של הפעילות
כדי להוסיף WebView
לאפליקציה בתצוגה, מוסיפים את הקוד הבא לקובץ ה-XML של הפריסה של הפעילות:
<WebView android:id="@+id/webview" android:layout_width="match_parent" android:layout_height="match_parent" />
כדי לטעון דף אינטרנט ב-WebView
, משתמשים ב-loadUrl()
, כפי שמוצג בדוגמה הבאה:
Kotlin
val myWebView: WebView = findViewById(R.id.webview) myWebView.loadUrl("http://www.example.com")
Java
WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.loadUrl("http://www.example.com");
הוספת WebView ב-onCreate()
כדי להוסיף WebView
לאפליקציה במקום זאת בשיטה onCreate()
של פעילות, צריך להשתמש בלוגיקה דומה לזו:
Kotlin
val myWebView = WebView(activityContext) setContentView(myWebView)
Java
WebView myWebView = new WebView(activityContext); setContentView(myWebView);
לאחר מכן טוענים את הדף:
Kotlin
myWebView.loadUrl("http://www.example.com")
Java
myWebView.loadUrl("https://www.example.com");
לחלופין, אפשר לטעון את כתובת ה-URL ממחרוץ HTML:
Kotlin
// Create an unencoded HTML string, then convert the unencoded HTML string into // bytes. Encode it with base64 and load the data. val unencodedHtml = "<html><body>'%23' is the percent code for ‘#‘ </body></html>"; val encodedHtml = Base64.encodeToString(unencodedHtml.toByteArray(), Base64.NO_PADDING) myWebView.loadData(encodedHtml, "text/html", "base64")
Java
// Create an unencoded HTML string, then convert the unencoded HTML string into // bytes. Encode it with base64 and load the data. String unencodedHtml = "<html><body>'%23' is the percent code for ‘#‘ </body></html>"; String encodedHtml = Base64.encodeToString(unencodedHtml.getBytes(), Base64.NO_PADDING); myWebView.loadData(encodedHtml, "text/html", "base64");
לאפליקציה צריכה להיות גישה לאינטרנט. כדי לקבל גישה לאינטרנט, מבקשים את ההרשאה INTERNET
בקובץ המניפסט, כמו בדוגמה הבאה:
<manifest ... > <uses-permission android:name="android.permission.INTERNET" /> ... </manifest>
אפשר להתאים אישית את WebView
באמצעות אחת מהפעולות הבאות:
- הפעלת התמיכה במסך מלא באמצעות
WebChromeClient
. הכיתה הזו נקראת גם כש-WebView
צריך הרשאה לשנות את ממשק המשתמש של אפליקציית המארח, למשל ליצור או לסגור חלונות או לשלוח למשתמש תיבת דו-שיח של JavaScript. מידע נוסף על ניפוי באגים בהקשר הזה זמין במאמר ניפוי באגים באפליקציות אינטרנט. - טיפול באירועים שמשפיעים על עיבוד התוכן, כמו שגיאות בשליחת טפסים או ניווט באמצעות
WebViewClient
. אפשר גם להשתמש בתת-הסוג הזה כדי ליירט את טעינת כתובות ה-URL. - הפעלת JavaScript על ידי שינוי של
WebSettings
. - שימוש ב-JavaScript כדי לגשת לאובייקטים של Android framework שהחדרתם ל-
WebView
.
שימוש ב-JavaScript ב-WebView
אם דף האינטרנט שרוצים לטעון ב-WebView
משתמש ב-JavaScript, צריך להפעיל את JavaScript ב-WebView
. אחרי שמפעילים את JavaScript, אפשר ליצור ממשקים בין קוד האפליקציה לקוד JavaScript.
הפוך JavaScript לפעיל
JavaScript מושבת ב-WebView
כברירת מחדל. אפשר להפעיל אותו דרך ה-WebSettings
שמצורף ל-WebView
. מאחזרים את WebSettings
באמצעות getSettings()
, ואז מפעילים את JavaScript באמצעות setJavaScriptEnabled()
.
דוגמה:
Kotlin
val myWebView: WebView = findViewById(R.id.webview) myWebView.settings.javaScriptEnabled = true
Java
WebView myWebView = (WebView) findViewById(R.id.webview); WebSettings webSettings = myWebView.getSettings(); webSettings.setJavaScriptEnabled(true);
WebSettings
מספק גישה למגוון הגדרות נוספות שעשויות להיות שימושיות. לדוגמה, אם אתם מפתחים אפליקציית אינטרנט שמיועדת במיוחד ל-WebView
באפליקציית Android שלכם, תוכלו להגדיר מחרוזת של סוכן משתמש בהתאמה אישית עם setUserAgentString()
, ואז להריץ שאילתה על סוכן המשתמש בהתאמה אישית בדף האינטרנט כדי לוודא שהלקוח שמבקש את דף האינטרנט הוא אפליקציית Android שלכם.
קישור קוד JavaScript לקוד Android
כשאתם מפתחים אפליקציית אינטרנט שמיועדת במיוחד ל-WebView
באפליקציית Android שלכם, אתם יכולים ליצור ממשקים בין קוד JavaScript לבין קוד Android בצד הלקוח. לדוגמה, קוד JavaScript יכול להפעיל שיטה בקוד Android כדי להציג Dialog
, במקום להשתמש בפונקציה alert()
של JavaScript.
כדי לקשר ממשק חדש בין קוד ה-JavaScript לקוד Android, צריך לבצע קריאה ל-addJavascriptInterface()
, ולהעביר לו מופע של הכיתה שרוצים לקשר ל-JavaScript ושם של ממשק שאפשר לקרוא ל-JavaScript כדי לגשת לכיתה.
לדוגמה, אפשר לכלול את הכיתה הבאה באפליקציה ל-Android:
Kotlin
/** Instantiate the interface and set the context. */ class WebAppInterface(private val mContext: Context) { /** Show a toast from the web page. */ @JavascriptInterface fun showToast(toast: String) { Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show() } }
Java
public class WebAppInterface { Context mContext; /** Instantiate the interface and set the context. */ WebAppInterface(Context c) { mContext = c; } /** Show a toast from the web page. */ @JavascriptInterface public void showToast(String toast) { Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show(); } }
בדוגמה הזו, הכיתה WebAppInterface
מאפשרת לדף האינטרנט ליצור הודעת Toast
באמצעות השיטה showToast()
.
אפשר לקשר את הכיתה הזו ל-JavaScript שפועל ב-WebView
באמצעות addJavascriptInterface()
, כפי שמוצג בדוגמה הבאה:
Kotlin
val webView: WebView = findViewById(R.id.webview) webView.addJavascriptInterface(WebAppInterface(this), "Android")
Java
WebView webView = (WebView) findViewById(R.id.webview); webView.addJavascriptInterface(new WebAppInterface(this), "Android");
הפעולה הזו יוצרת ממשק שנקרא Android
ל-JavaScript שפועל ב-WebView
. בשלב הזה, לאפליקציית האינטרנט יש גישה לכיתה WebAppInterface
. לדוגמה, הנה קצת HTML ו-JavaScript שיוצרים הודעת טוסט באמצעות הממשק החדש כשהמשתמש מקייש על לחצן:
<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" /> <script type="text/javascript"> function showAndroidToast(toast) { Android.showToast(toast); } </script>
אין צורך לאתחל את הממשק Android
מ-JavaScript. ה-WebView
הופך אותו לזמין באופן אוטומטי לדף האינטרנט שלכם. לכן, כשמשתמש מקשיב על הלחצן, הפונקציה showAndroidToast()
משתמשת בממשק Android
כדי לקרוא ל-method WebAppInterface.showToast()
.
טיפול בניווט בדפים
כשהמשתמש מקייש על קישור מדף אינטרנט ב-WebView
, כברירת מחדל, מערכת Android מפעילה אפליקציה שמטפלת בכתובות URL. בדרך כלל, דפדפן האינטרנט שמוגדר כברירת מחדל נפתח ומטעין את כתובת היעד. עם זאת, אפשר לשנות את ההתנהגות הזו ב-WebView
כך שהקישורים יפתחו ב-WebView
. לאחר מכן תוכלו לאפשר למשתמש לנווט אחורה וקדימה בהיסטוריית דפי האינטרנט שלו, שמתוחזקת על ידי WebView
.
כדי לפתוח קישורים שהמשתמש הקיש עליהם, צריך לספק WebViewClient
ל-WebView
באמצעות setWebViewClient()
.
כל הקישורים שהמשתמש מקייש עליהם נטענים ב-WebView
. אם אתם רוצים יותר שליטה על המיקום שבו נטען הקישור שנלחץ עליו, תוכלו ליצור WebViewClient
משלכם שיחליף את השיטה shouldOverrideUrlLoading()
. בדוגמה הבאה MyWebViewClient
הוא כיתה פנימית של Activity
.
Kotlin
private class MyWebViewClient : WebViewClient() { override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean { if (Uri.parse(url).host == "www.example.com") { // This is your website, so don't override. Let your WebView load // the page. return false } // Otherwise, the link isn't for a page on your site, so launch another // Activity that handles URLs. Intent(Intent.ACTION_VIEW, Uri.parse(url)).apply { startActivity(this) } return true } }
Java
private class MyWebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { if ("www.example.com".equals(request.getUrl().getHost())) { // This is your website, so don't override. Let your WebView load the // page. return false; } // Otherwise, the link isn't for a page on your site, so launch another // Activity that handles URLs. Intent intent = new Intent(Intent.ACTION_VIEW, request.getUrl()); startActivity(intent); return true; } }
לאחר מכן יוצרים מכונה של WebViewClient
החדש הזה עבור WebView
:
Kotlin
val myWebView: WebView = findViewById(R.id.webview) myWebView.webViewClient = MyWebViewClient()
Java
WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.setWebViewClient(new MyWebViewClient());
עכשיו, כשהמשתמש מקייש על קישור, המערכת קוראת לשיטה shouldOverrideUrlLoading()
, שבה בודקים אם מארח כתובת ה-URL תואם לדומיין ספציפי, כפי שהוגדר בדוגמה הקודמת. אם יש התאמה, השיטה מחזירה את הערך false ולא מבטלת את טעינת כתובת ה-URL. הוא מאפשר ל-WebView
לטעון את כתובת ה-URL כרגיל. אם מארח כתובת ה-URL לא תואם, נוצר Intent
כדי להפעיל את Activity
שמוגדרת כברירת מחדל לטיפול בכתובות URL, שמפנה לדפדפן האינטרנט שמוגדר כברירת מחדל של המשתמש.
טיפול בכתובות URL בהתאמה אישית
WebView
מחיל הגבלות כשמבקשים משאבים ומפנים קישורים שמשתמשים בסכימת כתובת URL מותאמת אישית. לדוגמה, אם מטמיעים קריאות חזרה (callbacks) כמו shouldOverrideUrlLoading()
או shouldInterceptRequest()
, WebView
מפעיל אותן רק עבור כתובות URL תקינות.
לדוגמה, יכול להיות ש-WebView
לא יפעיל את השיטה shouldOverrideUrlLoading()
עבור קישורים כמו:
<a href="showProfile">Show Profile</a>
כתובות URL לא תקינות, כמו זו שמוצגת בדוגמה הקודמת, מטופלות באופן לא עקבי ב-WebView
, לכן מומלץ להשתמש במקום זאת בכתובת URL תקינה.
אפשר להשתמש בסכמה מותאמת אישית או בכתובת URL מסוג HTTPS לדומיין שבשליטת הארגון.
במקום להשתמש במחרוזת פשוטה בקישור, כמו בדוגמה הקודמת, אפשר להשתמש בסכימה מותאמת אישית כמו זו:
<a href="example-app:showProfile">Show Profile</a>
לאחר מכן תוכלו לטפל בכתובת ה-URL הזו בשיטה shouldOverrideUrlLoading()
באופן הבא:
Kotlin
// The URL scheme must be non-hierarchical, meaning no trailing slashes. const val APP_SCHEME = "example-app:" override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean { return if (url?.startsWith(APP_SCHEME) == true) { urlData = URLDecoder.decode(url.substring(APP_SCHEME.length), "UTF-8") respondToData(urlData) true } else { false } }
Java
// The URL scheme must be non-hierarchical, meaning no trailing slashes. private static final String APP_SCHEME = "example-app:"; @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (url.startsWith(APP_SCHEME)) { urlData = URLDecoder.decode(url.substring(APP_SCHEME.length()), "UTF-8"); respondToData(urlData); return true; } return false; }
ה-API של shouldOverrideUrlLoading()
מיועד בעיקר להפעלת כוונות לכתובות URL ספציפיות. כשמיישמים אותו, חשוב להחזיר את הערך false
לכתובות URL ש-WebView
מטפל בהן. עם זאת, אתם לא מוגבלים להפעלת כוונות. אפשר להחליף את כוונת ההפעלה בכל התנהגות בהתאמה אישית בדוגמאות הקוד שלמעלה.
ניווט בהיסטוריית דפי האינטרנט
כשה-WebView
מבטל את טעינת כתובת ה-URL, הוא מצטבר באופן אוטומטי היסטוריה של דפי אינטרנט שנצפו. אפשר לנווט אחורה וקדימה בהיסטוריה באמצעות goBack()
ו-goForward()
.
לדוגמה, כך אפשר להשתמש בלחצן 'הקודם' במכשיר כדי לנווט לאחור ב-Activity
:
Kotlin
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { // Check whether the key event is the Back button and if there's history. if (keyCode == KeyEvent.KEYCODE_BACK && myWebView.canGoBack()) { myWebView.goBack() return true } // If it isn't the Back button or there isn't web page history, bubble up to // the default system behavior. Probably exit the activity. return super.onKeyDown(keyCode, event) }
Java
@Override public boolean onKeyDown(int keyCode, KeyEvent event) { // Check whether the key event is the Back button and if there's history. if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) { myWebView.goBack(); return true; } // If it isn't the Back button or there's no web page history, bubble up to // the default system behavior. Probably exit the activity. return super.onKeyDown(keyCode, event); }
אם האפליקציה שלכם משתמשת ב-AndroidX AppCompat
מגרסה 1.6.0 ואילך, תוכלו לפשט עוד יותר את קטע הקוד הקודם:
Kotlin
onBackPressedDispatcher.addCallback { // Check whether there's history. if (myWebView.canGoBack()) { myWebView.goBack() } }
Java
onBackPressedDispatcher.addCallback { // Check whether there's history. if (myWebView.canGoBack()) { myWebView.goBack(); } }
השיטה canGoBack()
מחזירה את הערך true אם יש היסטוריית דפי אינטרנט שהמשתמש יכול לבקר בהם. באופן דומה, אפשר להשתמש ב-canGoForward()
כדי לבדוק אם יש היסטוריה של העברה קדימה. אם לא מבצעים את הבדיקה הזו, אחרי שהמשתמש מגיע לסוף ההיסטוריה, goBack()
ו-goForward()
לא עושים כלום.
טיפול בשינויים בהגדרות המכשיר
במהלך זמן הריצה, שינויים במצב הפעילות מתרחשים כשהגדרות המכשיר משתנות, למשל כשמשתמשים מסובבים את המכשיר או סוגרים עורך שיטת קלט (IME). השינויים האלה גורמים להשמדת הפעילות של אובייקט WebView
וליצירת פעילות חדשה, שבהמשך יוצרים אובייקט WebView
חדש שמעלה את כתובת ה-URL של האובייקט שהושמד. כדי לשנות את התנהגות ברירת המחדל של הפעילות, אפשר לשנות את האופן שבו היא מטפלת בשינויים ב-orientation
במניפסט. למידע נוסף על טיפול בשינויים בהגדרות במהלך זמן הריצה, קראו את המאמר טיפול בשינויים בהגדרות.
ניהול החלונות
כברירת מחדל, המערכת מתעלמת מבקשות לפתיחת חלונות חדשים. זה נכון גם אם הם נפתחים על ידי JavaScript וגם אם הם נפתחים על ידי מאפיין היעד בקישור. אתם יכולים להתאים אישית את WebChromeClient
כדי לקבוע את ההתנהגות שלכם כשאתם פותחים כמה חלונות.
כדי לשפר את האבטחה של האפליקציה, מומלץ למנוע פתיחה של חלונות קופצים וחלונות חדשים. הדרך הבטוחה ביותר להטמיע את ההתנהגות הזו היא להעביר את "true"
אל setSupportMultipleWindows()
, אבל לא לשנות את השיטה onCreateWindow()
, ש-setSupportMultipleWindows()
תלויה בה. הלוגיקה הזו מונעת את הטעינה של כל דף שמשתמש ב-target="_blank"
בקישורים שלו.