Android
提供了几个API
来帮助您管理在应用程序中显示Web
内容的WebView
对象。
本页介绍如何使用这些API
更有效地使用WebView
对象,从而提高应用程序的稳定性和安全性。
一、版本API
从Android 7.0
(API级别24)开始,用户可以在几个不同的包中进行选择,以便在WebView
对象中显示Web
内容。 Android 8.0
(API级别26)及更高版本包含一个API
,用于获取与在您的应用中显示Web
内容的包相关的信息。 在分析仅在您的应用尝试使用特定包的WebView
实现显示Web
内容时发生的错误时,此API
特别有用。
要使用此API
,请添加以下代码段中显示的逻辑:
PackageInfo webViewPackageInfo = WebView.getCurrentWebViewPackage();
Log.d("MY_APP_TAG", "WebView version: " + webViewPackageInfo.versionName);
注意:如果尚未正确设置设备,则
WebView.getCurrentWebViewPackage()
方法可以返回null
。 如果您在不支持WebView
的设备上运行应用程序(例如Wear OS
设备),它也会返回null
。
二、Google安全浏览API
为了向您的用户提供更安全的浏览体验,您的WebView
对象使用Google
安全浏览功能验证网址,这样您的应用就可以在用户尝试导航到可能不安全的网站时向用户显示警告。
虽然EnableSafeBrowsing
的默认值为true
,但偶尔会出现您可能只想有条件地启用安全浏览或禁用安全浏览的情况。Android 8.0
(API级别26)以及使用setSafeBrowsingEnabled()
的更高支持。 在较低API
级别编译的应用程序无法使用setSafeBrowsingEnabled()
,并且应将清单中的EnableSafeBrowsing
值更改为false
以禁用所有WebView
实例的功能。
如果您的应用针对Android 7.1
(API级别25)或更低版本,则可以通过将以下<meta-data>
元素添加到应用的清单文件中来选择WebView
对象,而无需检查针对Google Safe Browsing
的不安全网站列表的URL
:
<manifest>
<application>
<meta-data android:name="android.webkit.WebView.EnableSafeBrowsing"
android:value="false" />
...
</application>
</manifest>
定义程序化操作
当WebView
实例尝试加载已被Google
归类为已知威胁的页面时,默认情况下WebView
会显示一个插页式广告,警告用户已知威胁。 此屏幕为用户提供了加载URL
或者返回上一页安全的选项。
如果您定位到Android 8.1
(API级别27)或更高级别,则可以通过编程方式定义应用程序如何响应已知威胁:
- 您可以控制应用是否报告安全浏览的已知威胁。
- 您可以让您的应用自动执行特定操作 - 例如回到安全状态 - 每次遇到被归类为已知威胁的网址时。
注意:为了获得针对已知威胁的最佳保护,请等到您在调用
WebView
对象的loadUrl()
方法之前初始化安全浏览。
以下代码段显示了如何在遇到已知威胁后指示应用程序的WebView
实例始终恢复安全:
private WebView mSuperSafeWebView;
private boolean mSafeBrowsingIsInitialized;
// ...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mSuperSafeWebView = new WebView(this);
mSuperSafeWebView.setWebViewClient(new MyWebViewClient());
mSafeBrowsingIsInitialized = false;
mSuperSafeWebView.startSafeBrowsing(this, new ValueCallback<Boolean>() {
@Override
public void onReceiveValue(Boolean success) {
mSafeBrowsingIsInitialized = true;
if (!success) {
Log.e("MY_APP_TAG", "Unable to initialize Safe Browsing!");
}
}
});
}
public class MyWebViewClient extends WebViewClient {
// Automatically go "back to safety" when attempting to load a website that
// Google has identified 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, SafeBrowsingResponse callback) {
// The "true" argument indicates that your app reports incidents like
// this one to Safe Browsing.
callback.backToSafety(true);
Toast.makeText(view.getContext(), "Unsafe web page blocked.",
Toast.LENGTH_LONG).show();
}
}
三、HTML5地理位置API
对于定位到Android 6.0
(API级别23)及更高版本的应用,仅在安全来源(例如HTTPS)上支持Geolocation API
。 在不调用相应的onGeolocationPermissionsShowPrompt()
方法的情况下,将自动拒绝对非安全源上的Geolocation API
的任何请求。
四、选择退出指标收集
当用户同意时,WebView
可以将匿名诊断数据上传到Google
。 对于已实例化WebView
的每个应用程序,基于每个应用程序收集数据。 您可以通过在清单的<application>
元素中创建以下标记来选择退出此功能:
<manifest>
<application>
...
<meta-data android:name="android.webkit.WebView.MetricsOptOut"
android:value="true" />
</application>
</manifest>
只有在用户同意并且应用尚未选择退出的情况下,才会从应用上传数据。
五、终止处理API
此API
处理WebView
对象的渲染器进程消失的情况,因为系统终止了渲染器以回收急需的内存,或者因为渲染器进程本身崩溃。 通过使用此API
,即使呈现器进程已消失,您也可以继续执行应用程序。
警告:如果您的应用程序在渲染器进程消失后继续执行,则无论渲染器进程是否被终止或崩溃,都无法重用关联的WebView实例。 您的应用必须从视图层次结构中删除该实例并销毁该实例以继续执行。 然后,您的应用必须创建一个全新的WebView实例才能继续呈现网页。
请注意,如果渲染器在加载特定网页时崩溃,则尝试再次加载同一页面可能会导致新的WebView
对象显示相同的渲染崩溃行为。
以下代码段说明了如何使用此API
:
public class MyRendererTrackingWebViewClient extends WebViewClient {
private WebView mWebView;
@Override
public boolean onRenderProcessGone(WebView view,
RenderProcessGoneDetail detail) {
if (!detail.didCrash()) {
// Renderer was 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 crashed 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 choose to handle the crash more gracefully
// and allow your app to continue executing, you should 1) destroy the
// current WebView instance, 2) specify logic for how the app can
// continue executing, and 3) return "true" instead.
return false;
}
}
六、渲染器重要性API
现在WebView
对象在多进程模式下运行,您可以灵活地处理应用程序处理内存不足的情况。 您可以使用Android 8.0
中引入的Renderer
重要性API
为分配给特定WebView
对象的渲染器设置优先级策略。 特别是,当显示应用程序的WebView
对象的渲染器被终止时,您可能希望应用程序的主要部分继续执行。 例如,如果您希望不长时间显示WebView
对象,以便系统可以回收渲染器正在使用的内存,则可以执行此操作。
以下代码段显示如何为与应用程序的WebView
对象关联的呈现器进程分配优先级:
WebView myWebView;
myWebView.setRendererPriorityPolicy(RENDERER_PRIORITY_BOUND, true);
在此特定代码段中,渲染器的优先级与应用程序的默认优先级相同(或“绑定到”)。 当关联的WebView
对象不再可见时,true
参数会将渲染器的优先级降低为RENDERER_PRIORITY_WAIVED
。 换句话说,true
参数表示您的应用程序不关心系统是否使渲染器进程保持活动状态。 事实上,这种较低的优先级使得渲染器进程很可能在内存不足的情况下被终止。
警告:为了保持应用程序稳定性,您不应更改
WebView
对象的呈现器优先级策略,除非您还使用终止句柄API
来指定WebView
在关联的呈现器消失时的反应方式。