Android 提供了多种 API 来帮助您管理
WebView
对象,这些对象可在您的应用中显示 Web 内容。
本页介绍了如何使用这些 API 来处理 WebView
对象,从而提升应用的稳定性和安全性。
Version API
从 Android 7.0(API 级别 24)开始,用户可以在多个
用于在 WebView
对象中显示 Web 内容的不同软件包。
AndroidX.webkit
库包含
getCurrentWebViewPackage()
用于获取与显示 Web 的软件包相关的信息的方法
。此方法在分析仅发生的错误时非常有用
如果您的应用尝试使用特定软件包的
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 安全浏览服务
为了给您的用户提供更安全的浏览体验,WebView
对象使用
Google 安全浏览、
这样一来,当用户尝试转到
可能不安全的网站
虽然 EnableSafeBrowsing
的默认值为 true,
您可能只想有条件地启用安全浏览功能
禁用它。Android 8.0(API 级别 26)及更高版本支持使用
setSafeBrowsingEnabled()
针对个别 WebView
对象开启/关闭安全浏览功能。
如果您希望所有 WebView
个对象都停用安全浏览功能
请将以下 <meta-data>
元素添加到应用的
清单文件:
<manifest> <application> <meta-data android:name="android.webkit.WebView.EnableSafeBrowsing" android:value="false" /> ... </application> </manifest>
定义程序化操作
当 WebView
的实例尝试加载
被 Google 归类为已知威胁,默认为 WebView
会显示一个插页,警告用户存在已知威胁。通过该屏幕
用户仍然可以选择加载网址或返回到
安全。
如果您以 Android 8.1(API 级别 27)或更高版本为目标平台,则可以定义 应用如何以程序化方式响应以下已知威胁 方式:
- 您可以控制应用是否向“安全”应用报告已知威胁 浏览。
- 您可以让应用自动执行特定操作,例如 就像返回到安全网页一样:每次遇到包含 被归类为已知威胁
以下代码段展示了如何指示应用的
在遇到已知警报后,WebView
一律返回安全状态
威胁:
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!"); } } }); } }
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
对于以 Android 6.0(API 级别 23)及更高版本为目标平台的应用,Geolocation API
仅受 HTTPS 等安全源支持。任何向
非安全起点上的 Geolocation API 会被自动拒绝,而不会调用
相应的 onGeolocationPermissionsShowPrompt()
方法。
停用指标收集
WebView
可将匿名诊断数据上传到
Google。系统会按应用收集数据
每个实例化 WebView
的应用。您可以选择停用此功能
方法是在清单的
<application>
元素:
<manifest> <application> ... <meta-data android:name="android.webkit.WebView.MetricsOptOut" android:value="true" /> </application> </manifest>
只有在用户同意并且 您的应用不会选择停用详细了解如何选择停用诊断数据 请参阅 WebView 中的用户隐私 报告。
Termination Handling
Teriation Handling API 可处理针对
WebView
对象都会消失
或由于渲染器进程崩溃而造成崩溃。通过使用此 API
让您的应用继续执行,即使渲染器进程消失也是如此。
如果在加载特定网页时渲染程序崩溃了,
再次加载同一页面可能会导致新的 WebView
对象
呈现相同的崩溃行为。
以下代码段说明了如何在
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
当 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
参数表示您的应用并不在意,
系统会使渲染器进程保持活动状态事实上,这个较低的优先级
可能会导致渲染器进程在内存不足时终止
情况。
如需详细了解系统如何处理内存不足的情况,请参阅 进程和应用 生命周期。