ใช้ 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 นี่เป็นไลบรารีแบบคงที่ที่คุณเพิ่มลงในแอปพลิเคชันเพื่อใช้ android.webkit
API ที่ไม่พร้อมใช้งานในแพลตฟอร์มเวอร์ชันเก่า
เพิ่มลงในไฟล์ 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 ดังที่แสดงในตัวอย่างต่อไปนี้
<manifest ... > <uses-permission android:name="android.permission.INTERNET" /> ... </manifest>
คุณปรับแต่ง WebView
ได้โดยทำอย่างใดอย่างหนึ่งต่อไปนี้
- เปิดใช้การรองรับโหมดเต็มหน้าจอโดยใช้
WebChromeClient
นอกจากนี้ ระบบยังเรียกใช้คลาสนี้เมื่อWebView
ต้องการสิทธิ์ในการแก้ไข UI ของแอปโฮสต์ เช่น การสร้างหรือปิดหน้าต่าง หรือส่งกล่องโต้ตอบ JavaScript ไปยังผู้ใช้ อ่านข้อมูลเพิ่มเติมเกี่ยวกับการแก้ไขข้อบกพร่องในบริบทนี้ได้ที่แก้ไขข้อบกพร่องเว็บ - การจัดการเหตุการณ์ที่ส่งผลต่อการแสดงผลเนื้อหา เช่น ข้อผิดพลาดในการส่งแบบฟอร์มหรือการนําทางโดยใช้
WebViewClient
นอกจากนี้ คุณยังใช้คลาสย่อยนี้เพื่อขัดขวางการโหลด URL ได้ด้วย - เปิดใช้ JavaScript ด้วยการแก้ไข
WebSettings
- การใช้ JavaScript เพื่อเข้าถึงออบเจ็กต์เฟรมเวิร์ก 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 ของคุณ คุณสามารถกำหนดสตริง User Agent ที่กําหนดเองด้วย setUserAgentString()
จากนั้นค้นหา User Agent ที่กําหนดเองในหน้าเว็บเพื่อยืนยันว่าไคลเอ็นต์ที่ขอหน้าเว็บเป็นแอป 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 บางส่วนที่สร้างข้อความ Toast โดยใช้อินเทอร์เฟซใหม่เมื่อผู้ใช้แตะปุ่ม
<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 โดยปกติแล้วเว็บเบราว์เซอร์เริ่มต้นจะเปิดขึ้นและโหลด 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 ตรงกับโดเมนที่เฉพาะเจาะจงหรือไม่ ตามที่ระบุไว้ในตัวอย่างก่อนหน้านี้ หากตรงกัน เมธอดจะแสดงผลเป็นเท็จและไม่ลบล้างการโหลด URL ซึ่งจะช่วยให้ WebView
โหลด URL ตามปกติ หากโฮสต์ URL ไม่ตรงกัน ระบบจะสร้าง Intent
เพื่อเปิด Activity
เริ่มต้นสำหรับการจัดการ URL ซึ่งจะเปลี่ยนเส้นทางไปยังเว็บเบราว์เซอร์เริ่มต้นของผู้ใช้
จัดการ URL ที่กำหนดเอง
WebView
ใช้ข้อจำกัดเมื่อขอทรัพยากรและแก้ไขลิงก์ที่ใช้รูปแบบ URL ที่กําหนดเอง เช่น หากคุณใช้การเรียกกลับ เช่น
shouldOverrideUrlLoading()
หรือ
shouldInterceptRequest()
WebView
จะเรียกใช้เฉพาะ URL ที่ถูกต้องเท่านั้น
เช่น WebView
อาจไม่เรียกใช้เมธอด shouldOverrideUrlLoading()
สำหรับลิงก์เช่นนี้
<a href="showProfile">Show Profile</a>
ระบบจะจัดการ URL ที่ไม่ถูกต้อง เช่น 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; }
shouldOverrideUrlLoading()
API มีไว้เพื่อเปิดใช้งาน Intent สำหรับ URL ที่เฉพาะเจาะจงเป็นหลัก เมื่อใช้งาน ให้ตรวจสอบว่าได้ส่งกลับ false
สำหรับ URL ที่ WebView
จัดการ แต่คุณไม่ได้จํากัดไว้เพียงการเปิดตัว Intent คุณสามารถแทนที่ Intent การเปิดใช้งานด้วยลักษณะการทำงานที่กำหนดเองในตัวอย่างโค้ดก่อนหน้า
ไปยังส่วนต่างๆ ในประวัติหน้าเว็บ
เมื่อ 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()
จะแสดงผลเป็น "จริง" หากมีประวัติหน้าเว็บที่ผู้ใช้เข้าชม ในทำนองเดียวกัน คุณสามารถใช้ canGoForward()
เพื่อตรวจสอบว่ามีประวัติการเดินหน้าหรือไม่ หากคุณไม่ทำการตรวจสอบนี้ goBack()
และ goForward()
จะไม่ทําการใดๆ หลังจากที่ผู้ใช้ดูประวัติจนจบ
จัดการการเปลี่ยนแปลงการกำหนดค่าอุปกรณ์
ในระหว่างรันไทม์ สถานะกิจกรรมจะเปลี่ยนแปลงเมื่อการกำหนดค่าของอุปกรณ์เปลี่ยนแปลง เช่น เมื่อผู้ใช้หมุนอุปกรณ์หรือปิดเครื่องมือแก้ไขวิธีการป้อนข้อมูล (IME) การเปลี่ยนแปลงเหล่านี้จะทำให้ระบบทำลายกิจกรรมของออบเจ็กต์ WebView
และสร้างกิจกรรมใหม่ ซึ่งจะสร้างออบเจ็กต์ WebView
ใหม่ด้วยซึ่งจะโหลด URL ของออบเจ็กต์ที่ถูกทำลาย หากต้องการแก้ไขลักษณะการทำงานเริ่มต้นของกิจกรรม ให้เปลี่ยนวิธีจัดการการเปลี่ยนแปลง orientation
ในไฟล์ Manifest ดูข้อมูลเพิ่มเติมเกี่ยวกับการจัดการการเปลี่ยนแปลงการกำหนดค่าระหว่างรันไทม์ได้ที่จัดการการเปลี่ยนแปลงการกำหนดค่า
จัดการหน้าต่าง
โดยค่าเริ่มต้น ระบบจะละเว้นคําขอเปิดหน้าต่างใหม่ ไม่ว่าจะเปิดโดย JavaScript หรือแอตทริบิวต์เป้าหมายในลิงก์ คุณสามารถปรับแต่ง WebChromeClient
เพื่อกำหนดลักษณะการทำงานของคุณเองสำหรับการเปิดหน้าต่างหลายรายการ
คุณควรป้องกันไม่ให้ป๊อปอัปและหน้าต่างใหม่เปิดขึ้นเพื่อให้แอปมีความปลอดภัยมากขึ้น วิธีที่ปลอดภัยที่สุดในการใช้ลักษณะการทํางานนี้คือการส่ง "true"
ไปยัง setSupportMultipleWindows()
แต่ไม่ต้องลบล้างเมธอด onCreateWindow()
ที่ setSupportMultipleWindows()
นั้นใช้ ตรรกะนี้จะป้องกันไม่ให้หน้าเว็บที่ใช้ target="_blank"
ในลิงก์โหลด