Android cung cấp một số API để giúp bạn quản lý các đối tượng WebView hiển thị nội dung trên web trong ứng dụng của mình.
Trang này mô tả cách sử dụng các API này để làm việc với các đối tượng WebView một cách hiệu quả hơn, giúp cải thiện độ ổn định và tính bảo mật của ứng dụng.
Version API
Kể từ Android 7.0 (cấp độ API 24), người dùng có thể chọn trong số một số gói khác nhau để hiển thị nội dung web trong một đối tượng WebView. Thư viện Jetpack Webkit bao gồm phương thức getCurrentWebViewPackage() để tìm nạp thông tin liên quan đến gói đang hiển thị nội dung web trong ứng dụng của bạn. Phương thức 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 web bằng cách triển khai WebView của một gói cụ thể.
Để 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, WebViewcác đối tượng sẽ xác minh URL bằng tính năng Duyệt web An toàn của Google. Nhờ đó, ứng dụng của bạn có thể cho người dùng thấy cảnh báo khi họ cố gắng truy cập vào một trang web không an toàn.
Mặc dù giá trị mặc định của EnableSafeBrowsing là true, nhưng có những trường hợp bạn chỉ muốn bật tính năng Duyệt web an toàn có điều kiện hoặc tắt tính năng này. Android 8.0 (cấp độ API 26) trở lên hỗ trợ việc 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ả các đối tượng WebView không tham gia kiểm tra của tính năng Duyệt web an toàn, hãy thêm phần tử <meta-data> sau đây vào tệp kê khai của ứng dụng:
<manifest> <application> <meta-data android:name="android.webkit.WebView.EnableSafeBrowsing" android:value="false" /> ... </application> </manifest>
Xác định các thao tác có lập trình
Khi một phiên bản WebView cố gắng tải một trang mà Google phân loại là mối đe doạ đã biết, theo mặc định, WebView sẽ hiển thị một trang xen kẽ cảnh báo người dùng về mối đe doạ đã biết. Màn hình này cho phép người dùng chọn tải URL dù sao đi nữa hoặc quay lại một trang trước đó an toàn.
Nếu nhắm đến Android 8.1 (cấp độ API 27) trở lên, bạn có thể xác định theo phương thức lập trình cách ứng dụng của bạn phản hồi một mối đe doạ đã biết theo những cách sau:
- 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 cho tính năng Duyệt web an toàn hay không.
- Bạn có thể thiết lập để ứng dụng tự động thực hiện một hành động cụ thể (chẳng hạn như quay lại chế độ an toàn) mỗi khi gặp phải một URL bị 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 phiên bản WebView của ứng dụng luôn quay lại trạng thái an toàn sau khi gặp phải một mối đe doạ đã biết:
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(); } } }
HTML5 Geolocation API
Đối với các ứng dụng nhắm đến Android 6.0 (cấp độ API 23) trở lên, Geolocation API chỉ được hỗ trợ trên các nguồn an toàn, chẳng hạn như HTTPS. Mọi yêu cầu đối với Geolocation API trên các nguồn không an toàn đều tự động bị từ chối mà không cần 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 trên cơ sở mỗi ứng dụng cho từng ứng dụng khởi tạo một WebView. Bạn có thể chọn không sử dụng tính năng này bằng cách tạo thẻ sau trong phần tử <application> của tệp kê khai:
<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 ý và ứng dụng đó không chọn không tham gia. Để biết thêm thông tin về việc chọn không báo cáo dữ liệu chẩn đoán, hãy xem bài viết Quyền riêng tư của người dùng trong báo cáo WebView.
Termination Handling API
Termination Handling API xử lý các trường hợp trong đó quy trình kết xuất cho một đối tượng WebView biến mất, có thể là do hệ thống tắt trình kết xuất để thu hồi bộ nhớ cần thiết hoặc do quy trình kết xuất gặp sự cố. Khi sử dụng API này, bạn cho phép ứng dụng tiếp tục thực thi, ngay cả khi quy trình kết xuất biến mất.
Nếu một trình kết xuất gặp sự cố khi tải một trang web cụ thể, thì việc cố gắng tải lại trang đó có thể khiến một đối tượng WebView mới gặp phải hành vi kết xuất tương tự.
Đoạn mã sau đây minh hoạ cách sử dụng API này trong 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; } }
Renderer Importance API
Khi các đối tượng WebView hoạt động ở chế độ nhiều quy trình, bạn có thể linh hoạt trong cách ứng dụng xử lý các trường hợp hết bộ nhớ. Bạn có thể sử dụng Renderer Importance API (API Mức độ quan trọng của trình kết xuất) ra mắt trong Android 8.0 để đặt chính sách ưu tiên cho trình kết xuất được chỉ định cho một đối tượng WebView cụ thể. Cụ thể, bạn có thể muốn phần chính của ứng dụng tiếp tục thực thi khi một trình kết xuất hiển thị các đối tượng WebView của ứng dụng bị huỷ. Ví dụ: bạn có thể làm việc này nếu dự kiến không hiển thị đối tượng WebView trong một thời gian dài để hệ thống có thể thu hồ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 quy trình kết xuất được liên kết với các đố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 với mức độ ưu tiên mặc định của ứng dụng hoặc được liên kết với mức độ ưu tiên mặc định của ứng dụng. Đối số true 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 được liên kết không còn hiển thị nữa. Nói cách khác, đối số true cho biết ứng dụng của bạn không quan tâm đến việc hệ thống có duy trì quy trình kết xuất hay không. Trên thực tế, mức độ ưu tiên thấp hơn này có thể khiến quy trình kết xuất đồ hoạ bị tắt trong trường hợp hết bộ nhớ.
Để tìm hiểu thêm về cách hệ thống xử lý các trường hợp thiếu bộ nhớ, hãy xem bài viết Các quy trình và vòng đời ứng dụng.