Zarządzaj obiektami WebView

Android udostępnia kilka interfejsów API, które ułatwiają zarządzanie WebView obiekty, które wyświetlają treści z internetu w aplikacji.

Na tej stronie dowiesz się, jak używać tych interfejsów API w pracy z usługą WebView obiektów, zwiększając w ten sposób stabilność i bezpieczeństwo aplikacji.

Interfejs API wersji

Począwszy od Androida 7.0 (poziom interfejsu API 24) użytkownicy mają do wyboru kilka różne pakiety do wyświetlania treści internetowych w obiekcie WebView. AndroidX.webkit biblioteka obejmuje getCurrentWebViewPackage() metoda pobierania informacji o pakiecie, który wyświetla sieć treści w aplikacji. Metoda ta przydaje się przy analizowaniu błędów występujących tylko gdy aplikacja próbuje wyświetlić treści z internetu przy użyciu pakietu implementacja WebView.

Aby użyć tej metody, dodaj mechanizm logiczny widoczny w tym fragmencie kodu:

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

Usługa Bezpieczne przeglądanie Google

Aby zwiększyć bezpieczeństwo użytkowników podczas przeglądania internetu, WebView Obiekty weryfikuje adresy URL za pomocą Bezpieczne przeglądanie Google, który pozwala aplikacji wyświetlać użytkownikom ostrzeżenie przy próbie przejścia do potencjalnie niebezpiecznej stronie.

Chociaż domyślna wartość EnableSafeBrowsing to prawda, To sytuacje, gdy możesz włączyć Bezpieczne przeglądanie tylko warunkowo lub możesz ją wyłączyć. Android 8.0 (poziom interfejsu API 26) i nowsze obsługują używanie setSafeBrowsingEnabled() aby włączyć lub wyłączyć Bezpieczne przeglądanie dla pojedynczego obiektu WebView.

Jeśli chcesz, aby wszystkie obiekty WebView zrezygnowały z Bezpiecznego przeglądania sprawdź, dodaj ten element <meta-data> do plik manifestu:

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

Zdefiniuj działania zautomatyzowane

Gdy instancja WebView próbuje wczytać stronę, która jest sklasyfikowanych przez Google jako znane zagrożenie, domyślnie WebView wyświetla reklamę pełnoekranową, która ostrzega użytkowników o znanym zagrożeniu. Ten ekran pokazuje użytkownicy mogą wczytać adres URL mimo to lub wrócić do poprzedniej strony, bezpieczeństwa.

Jeśli kierujesz aplikację na Androida 8.1 (poziom interfejsu API 27) lub nowszego, możesz zdefiniować w sposób zautomatyzowany, w jaki sposób aplikacja reaguje na znane zagrożenia: sposoby:

  • Możesz określić, czy aplikacja będzie zgłaszać znane zagrożenia bezpieczeństwa Przeglądanie.
  • Aplikacja może automatycznie wykonywać określone działanie, np. jako powrót do zabezpieczeń – za każdym razem, gdy napotka adres URL, sklasyfikowanych jako znane zagrożenia.
.

Te fragmenty kodu pokazują, jak przekazać instrukcje instancji aplikacji WebView, aby zawsze wrócić do zabezpieczeń po napotkaniu znanego zdarzenia zagrożenie:

MojaWebActivity.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();
        }
    }
}

Interfejs API geolokalizacji w HTML5

W przypadku aplikacji kierowanych na Androida 6.0 (poziom interfejsu API 23) i nowsze wersje interfejsu API geolokalizacji jest obsługiwany tylko w przypadku bezpiecznych źródeł, takich jak HTTPS. Wszystkie prośby skierowane do Interfejs API geolokalizacji w przypadku niezabezpieczonych źródeł jest automatycznie odrzucany bez wywoływania odpowiednią metodę onGeolocationPermissionsShowPrompt().

Zrezygnuj ze zbierania danych

WebView może przesyłać anonimowe dane diagnostyczne do Google, gdy użytkownik wyrazi zgodę. Dane są zbierane w odniesieniu do poszczególnych aplikacji dla każdej aplikacji, która tworzy instancję WebView. Możesz zrezygnować z tej opcji. przez utworzenie w pliku manifestu następującego tagu Element <application>:

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

Dane są przesyłane z aplikacji tylko wtedy, gdy użytkownik wyrazi zgodę oraz nie rezygnuje. Więcej informacji o rezygnowaniu z danych diagnostycznych raportowania dowiesz się z artykułu Prywatność użytkowników w komponencie WebView .

Interfejs API obsługi wypowiedzenia

Interfejs Termination Handling API obsługuje przypadki, w których mechanizm renderowania WebView gdy obiekt znika, ponieważ system kończy działanie mechanizmu renderowania, by odzyskać niezbędną pamięć lub z powodu błędu procesu renderowania. Korzystając z tego interfejsu API, Pozwól aplikacji kontynuować wykonywanie, mimo że mechanizm renderowania przestanie działać.

Jeśli mechanizm renderowania ulegnie awarii podczas wczytywania konkretnej strony internetowej, ponowne wczytanie tej samej strony może spowodować, że nowy obiekt WebView występują w przypadku tego samego błędu renderowania.

Poniższy fragment kodu ilustruje, jak używać tego interfejsu API w tagu 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;
    }
}

Interfejs Renderer Importance API

Gdy obiekty WebView działa w w trybie wielu procesów, możesz elastycznie reagować typu „za mało pamięci”. Korzystając z interfejsu Renderer Importance API, omówionego w artykule Android 8.0, aby ustawić zasadę priorytetu dla mechanizmu renderowania przypisanego do WebView obiekt. Szczególnie przydałaby się najważniejsza część aby kontynuować wykonywanie, gdy mechanizm renderowania wyświetla WebView obiektu zostało zakończone. Możesz to zrobić na przykład, jeśli obiekt WebView nie będzie przez dłuższy czas wyświetlany, więc system może odzyskać pamięć używaną przez mechanizm renderowania.

Fragment kodu poniżej pokazuje, jak przypisać priorytet do mechanizmu renderowania proces powiązany z obiektami WebView Twojej aplikacji:

Kotlin

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

Java

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

W tym fragmencie kodu priorytet mechanizmu renderowania jest taki sam jak – lub – jest to domyślny priorytet aplikacji. true zmniejsza priorytet mechanizmu renderowania do RENDERER_PRIORITY_WAIVED gdy powiązany obiekt WebView nie jest już widoczny. W innym słów, argument true wskazuje, że aplikacja nie dba o to, czy system utrzymuje proces renderowania. Ten niższy priorytet może doprowadzić do zakończenia procesu renderowania z „brakiem pamięci” w różnych sytuacjach.

Aby dowiedzieć się więcej o tym, jak system postępuje w sytuacjach, gdy brakuje pamięci, zobacz Procesy i aplikacja cyklu życia usługi.