Quản lý đối tượng WebView

Android cung cấp một số API để giúp bạn quản lý WebView các đối tượng hiển thị nội dung web trong ứng dụng của bạn.

Trang này mô tả cách sử dụng các API này để làm việc với WebView đối tượng một cách hiệu quả hơn, nhờ đó cải thiện độ ổn định và tính bảo mật của ứng dụng.

API phiên bản

Kể từ Android 7.0 (API cấp 24), người dùng có thể chọn trong số các gói khác nhau để hiện nội dung trên web trong đối tượng WebView. Lớp AndroidX.webkit thư viện bao gồm getCurrentWebViewPackage() để tìm nạp thông tin liên quan đến gói đang hiển thị web nội dung trong ứng dụng của bạn. Phương pháp này rất hữu ích khi phân tích các lỗi chỉ xảy ra khi ứng dụng của bạn cố gắng hiển thị nội dung trên web bằng cách sử dụng triển khai WebView.

Để sử dụng phương thức này, hãy thêm logic có trong đoạn mã sau:

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);

Dịch vụ Duyệt web An toàn của Google

Để mang đến cho người dùng trải nghiệm duyệt web an toàn hơn, WebView bằng cách sử dụng các đối tượng xác minh URL Tính năng Duyệt web An toàn của Google, Tính năng này cho phép ứng dụng của bạn hiển thị cảnh báo cho người dùng khi họ cố gắng truy cập vào trang web có thể không an toàn.

Mặc dù giá trị mặc định của EnableSafeBrowsing là true, nhưng là các trường hợp bạn có thể chỉ muốn bật Duyệt web an toàn theo điều kiện hoặc hãy tắt tính năng đó. Android 8.0 (API cấp 26) trở lên hỗ trợ sử dụng setSafeBrowsingEnabled() để bật/tắt tính năng Duyệt web an toàn cho từng đối tượng WebView.

Nếu bạn muốn tất cả đối tượng WebView chọn không sử dụng tính năng Duyệt web an toàn kiểm tra, hãy thêm phần tử <meta-data> sau vào tệp kê khai:

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

Xác định các hành động có lập trình

Khi một thực thể của WebView cố gắng tải một trang được Google phân loại là mối đe doạ đã biết, WebView theo mặc định hiển thị một quảng cáo xen kẽ cảnh báo người dùng về mối đe doạ đã biết. Màn hình này cung cấp cho người dùng lựa chọn vẫn tải URL hoặc quay lại trang trước đó an toàn.

Nếu nhắm đến Android 8.1 (API cấp 27) trở lên, bạn có thể xác định cách ứng dụng của bạn ứng phó với mối đe doạ đã biết như sau: cách:

  • Bạn có thể kiểm soát việc ứng dụng của mình có báo cáo các mối đe doạ đã biết đến chế độ An toàn hay không Duyệt web.
  • Bạn có thể đặt để ứng dụng tự động thực hiện một hành động cụ thể, chẳng hạn như như quay lại trang an toàn—mỗi khi gặp một URL được phân loại là mối đe doạ đã biết.

Các đoạn mã sau đây cho biết cách hướng dẫn các thực thể của ứng dụng WebView để luôn quay lại an toàn sau khi gặp phải mối đe doạ:

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 vị trí địa lý HTML5

Đối với ứng dụng nhắm mục tiêu Android 6.0 (API cấp 23) trở lên, API vị trí địa lý chỉ được hỗ trợ trên các nguồn gốc bảo mật, chẳng hạn như HTTPS. Mọi yêu cầu đối với Hệ thống sẽ tự động từ chối API vị trí địa lý trên các nguồn gốc không an toàn mà không gọi phương thức onGeolocationPermissionsShowPrompt() tương ứng.

Chọn không thu thập chỉ số

WebView có thể tải dữ liệu chẩn đoán ẩn danh lên Google khi người dùng đồng ý. Dữ liệu được thu thập theo từng ứng dụng cho mỗi ứng dụng tạo thực thể WebView. Bạn có thể chọn không áp dụng bằng cách tạo thẻ sau trong tệp kê khai Phần tử <application>:

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

Dữ liệu chỉ được tải lên từ một ứng dụng nếu người dùng đồng ý ứng dụng không chọn không tham gia. Để biết thêm thông tin về cách chọn không sử dụng dữ liệu chẩn đoán báo cáo, hãy xem Quyền riêng tư của người dùng trong WebView báo cáo.

API Xử lý việc chấm dứt

Chấm dứt API xử lý các trường hợp trong đó trình kết xuất xử lý một WebView đối tượng sẽ biến mất do hệ thống loại bỏ trình kết xuất để lấy lại bộ nhớ cần thiết hoặc do quá trình kết xuất gặp sự cố. Bằng cách sử dụng API này, bạn hãy cho phép ứng dụng tiếp tục thực thi, ngay cả khi quy trình kết xuất đã ngừng hoạt động.

Nếu trình kết xuất gặp sự cố trong khi tải một trang web cụ thể, hãy thử thì việc tải lại cùng một trang đó có thể khiến đối tượng WebView mới thể hiện cùng một hành vi sự cố kết xuất hình ảnh.

Đoạn mã sau minh hoạ cách sử dụng API này trong một 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 Mức độ quan trọng của trình kết xuất

Khi đối tượng WebView hoạt động ở chế độ đa quy trình, nên bạn có thể linh hoạt trong cách ứng dụng của mình xử lý tình huống hết bộ nhớ. Bạn có thể dùng API Mức độ quan trọng của trình kết xuất, được giới thiệu trong Android 8.0: thiết lập chính sách ưu tiên cho trình kết xuất được chỉ định cho một trình kết xuất cụ thể Đối tượng WebView. Cụ thể, bạn nên thực hiện phần chính tiếp tục thực thi khi một trình kết xuất hiển thị WebView đối tượng đã bị tiêu diệt. Bạn có thể làm việc này, chẳng hạn như nếu bạn dự kiến sẽ không hiển thị đối tượng WebView trong một thời gian dài để hệ thống có thể lấy lại bộ nhớ mà trình kết xuất đang sử dụng.

Đoạn mã sau đây cho biết cách chỉ định mức độ ưu tiên cho trình kết xuất quy trình liên kết với đối tượng WebView của ứng dụng:

Kotlin

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

Java

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

Trong đoạn mã cụ thể này, mức độ ưu tiên của trình kết xuất giống như—hoặc được liên kết với mức độ ưu tiên mặc định cho ứng dụng. true đối số giảm mức độ ưu tiên của trình kết xuất xuống RENDERER_PRIORITY_WAIVED khi đối tượng WebView liên kết không còn xuất hiện. Trong khu vực khác thì đối số true cho biết ứng dụng của bạn không quan tâm đến việc hệ thống giúp quá trình kết xuất tiếp tục hoạt động. Trên thực tế, mức độ ưu tiên thấp hơn này có khả năng quá trình kết xuất đồ hoạ bị dừng khi hết bộ nhớ ngoại lệ.

Để tìm hiểu thêm về cách hệ thống xử lý các tình huống dung lượng bộ nhớ thấp, hãy xem Quy trình và ứng dụng Lifecycle.