จัดการออบเจ็กต์ WebView

Android มี API มากมายที่จะช่วยคุณจัดการ WebView ที่แสดงเนื้อหาเว็บในแอปของคุณ

หน้านี้จะอธิบายวิธีใช้ API เหล่านี้เพื่อทำงานกับ WebView ออบเจ็กต์ได้อย่างมีประสิทธิภาพมากขึ้น ซึ่งจะช่วยปรับปรุงความเสถียรและความปลอดภัยของแอป

API เวอร์ชัน

เริ่มตั้งแต่ Android 7.0 (API ระดับ 24) เป็นต้นไป ผู้ใช้จะเลือกได้จาก แพ็กเกจต่างๆ สำหรับการแสดงเนื้อหาเว็บในออบเจ็กต์ WebView AndroidX.webkit จะมี getCurrentWebViewPackage() วิธีการดึงข้อมูลที่เกี่ยวข้องกับแพ็กเกจที่แสดงเว็บ เนื้อหาในแอปของคุณ วิธีนี้มีประโยชน์เมื่อวิเคราะห์ข้อผิดพลาดที่เกิดขึ้นเท่านั้น เมื่อแอปของคุณพยายามแสดงเนื้อหาเว็บโดยใช้แพ็กเกจ การใช้งาน WebView

หากต้องการใช้วิธีนี้ ให้เพิ่มตรรกะที่แสดงในข้อมูลโค้ดต่อไปนี้

Kotlin

val webViewPackageInfo = WebViewCompat.getCurrentWebViewPackage(appContext)
Log.d("MY_APP_TAG", "WebView version: ${webViewPackageInfo.versionName}")

Java

PackageInfo webViewPackageInfo = WebViewCompat.getCurrentWebViewPackage(appContext);
Log.d("MY_APP_TAG", "WebView version: " + webViewPackageInfo.versionName);

บริการ Google Safe Browsing

เพื่อมอบประสบการณ์การท่องเว็บที่ปลอดภัยยิ่งขึ้นแก่ผู้ใช้ WebView ออบเจ็กต์ยืนยัน URL โดยใช้ Google Safe Browsing ซึ่งทำให้แอปของคุณแสดงคำเตือนแก่ผู้ใช้เมื่อพยายามไปที่ เว็บไซต์ที่อาจไม่ปลอดภัย

แม้ว่าค่าเริ่มต้นของ EnableSafeBrowsing จะเป็นจริง แต่ ในกรณีที่คุณต้องการเปิดใช้ Google Safe Browsing แบบมีเงื่อนไขเท่านั้น หรือ ปิดใช้ Android 8.0 (API ระดับ 26) ขึ้นไปรองรับการใช้ setSafeBrowsingEnabled() เพื่อสลับ Google Safe Browsing สำหรับออบเจ็กต์ WebView แต่ละรายการ

หากคุณต้องการให้ออบเจ็กต์ WebView ทั้งหมดเลือกไม่ใช้ Google Safe Browsing ตรวจสอบ ให้เพิ่มองค์ประกอบ <meta-data> ต่อไปนี้ลงใน ไฟล์ Manifest:

<manifest>
    <application>
        <meta-data android:name="android.webkit.WebView.EnableSafeBrowsing"
                   android:value="false" />
        ...
    </application>
</manifest>

กำหนดการทำงานแบบเป็นโปรแกรม

เมื่ออินสแตนซ์ของ WebView พยายามโหลดหน้าเว็บที่ ที่จัดโดย Google ว่าเป็นภัยคุกคามที่รู้จัก WebView โดยค่าเริ่มต้น แสดงโฆษณาคั่นระหว่างหน้าที่เตือนผู้ใช้เกี่ยวกับภัยคุกคามที่ทราบ หน้าจอนี้จะให้ ผู้ใช้สามารถเลือกที่จะโหลด URL ต่อไป หรือกลับไปยังหน้าก่อนหน้าที่ ได้อย่างปลอดภัย

หากกำหนดเป้าหมายเป็น Android 8.1 (API ระดับ 27) ขึ้นไป คุณจะกำหนด วิธีที่แอปตอบสนองต่อภัยคุกคามที่ทราบแล้วโดยใช้โปรแกรมในสิ่งต่อไปนี้ ด้วยวิธีต่อไปนี้

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

ข้อมูลโค้ดต่อไปนี้จะแสดงวิธีออกคำสั่งให้อินสแตนซ์ของแอป WebViewเพื่อกลับสู่ความปลอดภัยเสมอหลังจากพบ ภัยคุกคาม:

MyWebActivity.java

Kotlin

private lateinit var superSafeWebView: WebView
private var safeBrowsingIsInitialized: Boolean = false

// ...

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    superSafeWebView = WebView(this)
    superSafeWebView.webViewClient = MyWebViewClient()
    safeBrowsingIsInitialized = false

    if (WebViewFeature.isFeatureSupported(WebViewFeature.START_SAFE_BROWSING)) {
        WebViewCompat.startSafeBrowsing(this, ValueCallback<Boolean> { success ->
            safeBrowsingIsInitialized = true
            if (!success) {
                Log.e("MY_APP_TAG", "Unable to initialize Safe Browsing!")
            }
        })
    }
}

Java

private WebView superSafeWebView;
private boolean safeBrowsingIsInitialized;

// ...

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    superSafeWebView = new WebView(this);
    superSafeWebView.setWebViewClient(new MyWebViewClient());
    safeBrowsingIsInitialized = false;

    if (WebViewFeature.isFeatureSupported(WebViewFeature.START_SAFE_BROWSING)) {
        WebViewCompat.startSafeBrowsing(this, new ValueCallback<Boolean>() {
            @Override
            public void onReceiveValue(Boolean success) {
                safeBrowsingIsInitialized = true;
                if (!success) {
                    Log.e("MY_APP_TAG", "Unable to initialize Safe Browsing!");
                }
            }
        });
    }
}

MyWebViewClient.java

Kotlin

class MyWebViewClient : WebViewClientCompat() {
    // Automatically go "back to safety" when attempting to load a website that
    // Google identifies as a known threat. An instance of WebView calls this
    // method only after Safe Browsing is initialized, so there's no conditional
    // logic needed here.
    override fun onSafeBrowsingHit(
            view: WebView,
            request: WebResourceRequest,
            threatType: Int,
            callback: SafeBrowsingResponseCompat
    ) {
        // The "true" argument indicates that your app reports incidents like
        // this one to Safe Browsing.
        if (WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY)) {
            callback.backToSafety(true)
            Toast.makeText(view.context, "Unsafe web page blocked.", Toast.LENGTH_LONG).show()
        }
    }
}

Java

public class MyWebViewClient extends WebViewClientCompat {
    // Automatically go "back to safety" when attempting to load a website that
    // Google identifies as a known threat. An instance of WebView calls this
    // method only after Safe Browsing is initialized, so there's no conditional
    // logic needed here.
    @Override
    public void onSafeBrowsingHit(WebView view, WebResourceRequest request,
            int threatType, SafeBrowsingResponseCompat callback) {
        // The "true" argument indicates that your app reports incidents like
        // this one to Safe Browsing.
        if (WebViewFeature.isFeatureSupported(WebViewFeature.SAFE_BROWSING_RESPONSE_BACK_TO_SAFETY)) {
            callback.backToSafety(true);
            Toast.makeText(view.getContext(), "Unsafe web page blocked.",
                    Toast.LENGTH_LONG).show();
        }
    }
}

API ตำแหน่งทางภูมิศาสตร์ของ HTML5

สำหรับแอปที่กำหนดเป้าหมายเป็น Android 6.0 (API ระดับ 23) ขึ้นไป Geolocation API รองรับเฉพาะในต้นทางที่ปลอดภัย เช่น HTTPS คำขอใดๆ ที่ส่งไปยัง Geolocation API ในต้นทางที่ไม่ปลอดภัยจะถูกปฏิเสธโดยอัตโนมัติโดยไม่มีการเรียกใช้ เมธอด onGeolocationPermissionsShowPrompt() ที่เกี่ยวข้อง

เลือกไม่ใช้การรวบรวมเมตริก

WebView สามารถอัปโหลดข้อมูลการวินิจฉัยที่ไม่ระบุตัวตนไปยัง Google เมื่อผู้ใช้ให้ความยินยอม มีการเก็บข้อมูลแยกตามแอป สำหรับแต่ละแอปที่สร้างอินสแตนซ์ WebView คุณสามารถเลือกไม่รับ โดยการสร้างแท็กต่อไปนี้ในไฟล์ Manifest องค์ประกอบ <application>:

<manifest>
    <application>
    ...
    <meta-data android:name="android.webkit.WebView.MetricsOptOut"
               android:value="true" />
    </application>
</manifest>

ข้อมูลจะอัปโหลดจากแอปในกรณีที่ผู้ใช้ยินยอมและเท่านั้น แอปไม่อาจเลือกไม่ให้ความยินยอมได้ ดูข้อมูลเพิ่มเติมเกี่ยวกับการเลือกไม่ใช้ข้อมูลการวินิจฉัย การรายงาน โปรดดูที่ความเป็นส่วนตัวของผู้ใช้ใน WebView การรายงาน

API การจัดการการสิ้นสุด

API การจัดการการสิ้นสุดจะจัดการกับกรณีที่กระบวนการแสดงผลสำหรับ WebView หายไป เนื่องจากระบบจะปิดโหมดแสดงภาพเพื่อเรียกคืน หน่วยความจำที่จำเป็น หรือเนื่องจากกระบวนการของโหมดแสดงภาพขัดข้อง เมื่อใช้ API นี้ คุณ ให้แอปของคุณดำเนินการต่อไป แม้ว่ากระบวนการของโหมดแสดงภาพจะหายไปก็ตาม

หากโหมดแสดงภาพขัดข้องในขณะที่โหลดหน้าเว็บบางหน้า การโหลดหน้าเว็บเดียวกันนั้นอีกครั้งอาจทำให้ออบเจ็กต์ WebView ใหม่ จะแสดงลักษณะการทำงานของ ข้อขัดข้องในการแสดงผลเดียวกัน

ข้อมูลโค้ดต่อไปนี้จะแสดงวิธีใช้ API นี้ใน Activity:

Kotlin

    
inner class MyRendererTrackingWebViewClient : WebViewClient() {
    private var mWebView: WebView? = null

    override fun onRenderProcessGone(view: WebView, detail: RenderProcessGoneDetail): Boolean {
        if (!detail.didCrash()) {
            // Renderer is killed because the system ran out of memory. The app
            // can recover gracefully by creating a new WebView instance in the
            // foreground.
            Log.e("MY_APP_TAG", ("System killed the WebView rendering process " +
                "to reclaim memory. Recreating..."))

            mWebView?.also { webView ->
                val webViewContainer: ViewGroup = findViewById(R.id.my_web_view_container)
                webViewContainer.removeView(webView)
                webView.destroy()
                mWebView = null
            }

            // By this point, the instance variable "mWebView" is guaranteed to
            // be null, so it's safe to reinitialize it.

            return true // The app continues executing.
        }

        // Renderer crashes because of an internal error, such as a memory
        // access violation.
        Log.e("MY_APP_TAG", "The WebView rendering process crashed!")

        // In this example, the app itself crashes after detecting that the
        // renderer crashed. If you handle the crash more gracefully and let
        // your app continue executing, you must destroy the current WebView
        // instance, specify logic for how the app continues executing, and
        // return "true" instead.
        return false
    }
}

Java

public class MyRendererTrackingWebViewClient extends WebViewClient {
    private WebView mWebView;

    @Override
    public boolean onRenderProcessGone(WebView view,
            RenderProcessGoneDetail detail) {
        if (!detail.didCrash()) {
            // Renderer is killed because the system ran out of memory. The app
            // can recover gracefully by creating a new WebView instance in the
            // foreground.
            Log.e("MY_APP_TAG", "System killed the WebView rendering process " +
                    "to reclaim memory. Recreating...");

            if (mWebView != null) {
                ViewGroup webViewContainer =
                        (ViewGroup) findViewById(R.id.my_web_view_container);
                webViewContainer.removeView(mWebView);
                mWebView.destroy();
                mWebView = null;
            }

            // By this point, the instance variable "mWebView" is guaranteed to
            // be null, so it's safe to reinitialize it.

            return true; // The app continues executing.
        }

        // Renderer crashes because of an internal error, such as a memory
        // access violation.
        Log.e("MY_APP_TAG", "The WebView rendering process crashed!");

        // In this example, the app itself crashes after detecting that the
        // renderer crashed. If you handle the crash more gracefully and let
        // your app continue executing, you must destroy the current WebView
        // instance, specify logic for how the app continues executing, and
        // return "true" instead.
        return false;
    }
}

API ความสำคัญของตัวแสดงผล

เมื่อ WebView ออบเจ็กต์ ดำเนินการใน หลายขั้นตอน คุณจึงมีความยืดหยุ่นในการจัดการแอป คุณสามารถใช้ Renderer Importance API ซึ่งเปิดตัวไปใน Android 8.0 หากต้องการตั้งค่านโยบายลำดับความสำคัญให้กับโหมดแสดงภาพที่กำหนดให้ ออบเจ็กต์ WebView รายการ โดยเฉพาะอย่างยิ่ง คุณอาจต้องการส่วนหลักๆ เพื่อดำเนินการต่อเมื่อโหมดแสดงภาพที่แสดง วัตถุ WebView รายการเสียชีวิต คุณอาจทำเช่นนี้ถ้า คาดว่าจะไม่แสดงออบเจ็กต์ WebView เป็นเวลานานเพื่อให้ ระบบจะเรียกคืนหน่วยความจำที่โหมดแสดงภาพใช้อยู่ได้

ข้อมูลโค้ดต่อไปนี้แสดงวิธีกำหนดลำดับความสำคัญให้กับโหมดแสดงภาพ กระบวนการที่เชื่อมโยงกับออบเจ็กต์ WebView ของแอป

Kotlin

val myWebView: WebView = ...
myWebView.setRendererPriorityPolicy(RENDERER_PRIORITY_BOUND, true)

Java

WebView myWebView;
myWebView.setRendererPriorityPolicy(RENDERER_PRIORITY_BOUND, true);

ในข้อมูลโค้ดนี้ ลำดับความสำคัญของโหมดแสดงภาพจะเหมือนกับ หรือ เป็นลำดับความสำคัญเริ่มต้นของแอป true ลดลำดับความสำคัญของตัวแสดงผลเป็น วันที่ RENDERER_PRIORITY_WAIVED เมื่อออบเจ็กต์ WebView ที่เชื่อมโยงไม่ปรากฏอีกต่อไป ในอีก อาร์กิวเมนต์ true แสดงว่าแอปของคุณไม่คํานึงถึง ระบบจะทำให้กระบวนการแสดงผลทำงานอย่างต่อเนื่อง อันที่จริง ระดับความสำคัญที่ต่ำกว่า ทำให้กระบวนการแสดงผล หายไปจากหน่วยความจำ เท่านั้น

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