สร้างเว็บแอปใน WebView

ใช้ 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")
}

ดึงดูด

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 ที่ สร้างข้อความโทสต์โดยใช้อินเทอร์เฟซใหม่เมื่อผู้ใช้แตะปุ่ม

<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 ที่กำหนดเอง ตัวอย่างเช่น หากคุณใช้ Callback เช่น shouldOverrideUrlLoading() หรือ shouldInterceptRequest(), จากนั้น WebView จะเรียกใช้หน่วยโฆษณาสำหรับ URL ที่ถูกต้องเท่านั้น

ตัวอย่างเช่น WebView อาจไม่เรียกเมธอด shouldOverrideUrlLoading() สำหรับลิงก์ที่มีลักษณะเช่นนี้:

<a href="showProfile">Show Profile</a>

URL ที่ไม่ถูกต้อง เช่น URL ที่แสดงในตัวอย่างก่อนหน้านี้ ได้รับการจัดการ ไม่สอดคล้องกับ WebView เราจึงขอแนะนำให้ใช้ URL ที่มีรูปแบบที่ถูกต้องแทน คุณสามารถใช้สคีมที่กำหนดเองหรือ HTTPS URL กับโดเมนที่องค์กรใช้

แทนที่จะใช้สตริงพื้นฐานในลิงก์ดังในตัวอย่างก่อนหน้านี้ คุณสามารถ ใช้รูปแบบที่กำหนดเองดังตัวอย่างต่อไปนี้

<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 ระบบจะรวบรวม 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" ในลิงก์ไม่ให้โหลด