Android 管理 WebView 对象

Managing WebView objects

一、API 版本

从 Android 7.0(API 级别 24)开始,用户可以在几个不同的包中进行选择,以便在 WebView 对象中显示 Web 内容。Android 8.0(API 级别 26)及更高版本中包含一个 API,用于获取 WebView 包的相关信息。在分析使用特定包的 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 Safe Browsing 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 的不安全网站列表的网址:

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

2.1 定义程序化操作

当 WebView 实例尝试加载已被 Google 归类为已知威胁的页面时,默认情况下 WebView 会显示一个页面,警告用户已知威胁。此页面为用户提供了无论如何加载 URL 或返回到安全的上一页的选项。

如果你定位到 Android 8.1(API 级别 27)或更高级别,则可以通过编程方式定义应用程序如何响应已知威胁:

  • 让应用报告 Safe Browsing 已知的威胁。

  • 让应用自动执行特定操作,例如每次遇到被归类为已知威胁的 URL 时回到安全状态。

注意:为了获得针对已知威胁的最佳保护,请在调用 WebView 对象的 loadUrl() 方法之前初始化安全浏览。

以下代码段显示了如何在遇到已知威胁后指示应用程序的 WebView 实例始终恢复安全:

MyWebActivity.java

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!");
            }
        }
    });
}

MyWebViewClient.java

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 Geolocation (地理位置) 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;
    }
}

六、Renderer 重要性 API — Renderer Importance 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 在关联的渲染器终止时的响应方式。

要了解更多有关系统如何处理低内存情况的信息,请参阅进程和应用程序生命周期

猜你喜欢

转载自blog.csdn.net/weixin_33739646/article/details/86995654