שימוש ב-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 אל משתמש. למידע נוסף על ניפוי באגים בהקשר הזה, אפשר לקרוא את המאמר ניפוי באגים באינטרנט של Google. - טיפול באירועים שמשפיעים על רינדור התוכן, כמו שגיאות בטופס.
שליחות או ניווט באמצעות
WebViewClient
אפשר גם להשתמש המחלקה המשנית הזו כדי ליירט את הטעינה של כתובות ה-URL. - הפעלת JavaScript על-ידי שינוי
WebSettings
- שימוש ב-JavaScript כדי לגשת לאובייקטים של framework ב-Android שהחדרת
ל
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 יכול לקרוא ל-method ב-
את הקוד של 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 כרגיל. אם המארח של כתובת האתר לא תואם, אז
הדומיין Intent
נוצר כדי להפעיל את ברירת המחדל
Activity
לטיפול בכתובות URL, שמפנה לדפדפן האינטרנט שמוגדר כברירת מחדל של המשתמש.
טיפול בכתובות URL מותאמות אישית
WebView
מחילה הגבלות כאשר מבקשים משאבים ופותרים קישורים
שמשתמשים בסכימה של כתובת URL מותאמת אישית. לדוגמה, אם אתם מטמיעים קריאות חוזרות (callback), כמו
shouldOverrideUrlLoading()
או
shouldInterceptRequest()
,
לאחר מכן, WebView
מפעיל אותן רק עבור כתובות URL חוקיות.
לדוגמה, יכול להיות ש-WebView
לא יקרא ל-method 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()
מיועד בעיקר להשקה של Intents
לכתובות URL ספציפיות. כשמטמיעים את המזהה, צריך להקפיד להחזיר את הערך false
לכתובות URL
הכינויים של WebView
. עם זאת, אתם לא מוגבלים להשקת כוונות. אפשר
החלפת ההפעלה של Intents בכל התנהגות מותאמת אישית שמופיעה בקוד הקודם
דוגמאות.
ניווט בהיסטוריית דפי אינטרנט
כשהערך של 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"
.