אפשר להשתמש ב-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") }
מגניב
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
כדי לקרוא לשיטה 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 מותאמת אישית. לדוגמה, אם מטמיעים קריאות חוזרות כמו
shouldOverrideUrlLoading()
או
shouldInterceptRequest()
,
אז WebView
מפעיל אותן רק עבור כתובות URL תקינות.
לדוגמה, יכול להיות שהשיטה shouldOverrideUrlLoading()
לא תופעל עבור קישורים כמו WebView
:
<a href="showProfile">Show Profile</a>
המערכת של WebView
מטפלת בכתובות URL לא תקינות, כמו זו שמוצגת בדוגמה הקודמת, בצורה לא עקבית. לכן מומלץ להשתמש בכתובת 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"
בקישורים שלו.