WebView nesnelerini yönetme

Android, uygulamanızda web içeriğini gösteren WebView nesnelerini yönetmenize yardımcı olmak için çeşitli API'ler sağlar.

Bu sayfada, bu API'leri WebView nesneleriyle daha verimli bir şekilde çalışmak ve uygulamanızın kararlılığını ve güvenliğini iyileştirmek için nasıl kullanabileceğiniz açıklanmaktadır.

Sürüm API'si

Android 7.0'dan (API düzeyi 24) başlayarak, kullanıcılar bir WebView nesnesinde web içeriğini görüntülemek için farklı paketler arasından seçim yapabilirler. AndroidX.webkit kitaplığı, uygulamanızda web içeriğini görüntüleyen paketle ilgili bilgileri getirmek için getCurrentWebViewPackage() yöntemini içerir. Bu yöntem, yalnızca uygulamanız belirli bir paketin WebView uygulamasını kullanarak web içeriğini görüntülemeye çalıştığında oluşan hataları analiz ederken yararlıdır.

Bu yöntemi kullanmak için aşağıdaki kod snippet'inde gösterilen mantığı ekleyin:

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 Güvenli Tarama Hizmeti

WebView, kullanıcılarınıza daha güvenli bir göz atma deneyimi sunmak için URL'leri Google Güvenli Tarama'yı kullanarak doğrular. Bu nesne, uygulamanızın güvenli olmayabilecek bir web sitesine gitmeye çalışan kullanıcılara bir uyarı göstermesini sağlar.

Varsayılan EnableSafeBrowsing değeri true olsa da, Güvenli Tarama'yı yalnızca koşullu olarak etkinleştirmek veya devre dışı bırakmak isteyebileceğiniz durumlar da vardır. Android 8.0 (API düzeyi 26) ve sonraki sürümler tek bir WebView nesnesi için Güvenli Tarama'yı açıp kapatmak için setSafeBrowsingEnabled() kullanımını destekler.

Tüm WebView nesnelerinin Güvenli Tarama kontrollerini devre dışı bırakmasını istiyorsanız aşağıdaki <meta-data> öğesini uygulamanızın manifest dosyasına ekleyin:

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

Programatik işlemleri tanımlayın

WebView örneği, Google tarafından bilinen bir tehdit olarak sınıflandırılan bir sayfayı yüklemeye çalıştığında, WebView varsayılan olarak bilinen tehdit konusunda kullanıcıları uyaran bir geçiş reklamı gösterir. Bu ekran, kullanıcılara URL'yi yine de yükleme veya önceki güvenli bir sayfaya dönme seçeneği sunar.

Android 8.1 (API düzeyi 27) veya sonraki sürümleri hedeflerseniz uygulamanızın bilinen bir tehdide nasıl tepki vereceğini aşağıdaki yöntemlerle programatik olarak tanımlayabilirsiniz:

  • Uygulamanızın, Güvenli Tarama'ya yönelik bilinen tehditleri bildirip bildirmeyeceğini kontrol edebilirsiniz.
  • Uygulamanızın, bilinen tehdit olarak sınıflandırılmış bir URL ile her karşılaştığında otomatik olarak belirli bir işlemi (örneğin, güvenliğe geri dönme) gerçekleştirmesini sağlayabilirsiniz.

Aşağıdaki kod snippet'leri, uygulamanızın bilinen bir tehditle karşılaştıktan sonra her zaman güvenli bir duruma geri dönmesi için uygulamanızın WebView örneklerini nasıl bildireceğinizi gösterir:

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 Coğrafi Konum API'sı

Android 6.0 (API düzeyi 23) ve sonraki sürümleri hedefleyen uygulamalar için Coğrafi Konum API, yalnızca HTTPS gibi güvenli kaynaklarda desteklenir. Güvenli olmayan kaynaklarda Geolocation API'ye yapılan tüm istekler, ilgili onGeolocationPermissionsShowPrompt() yöntemi çağrılmadan otomatik olarak reddedilir.

Metrik toplamayı devre dışı bırak

WebView, kullanıcı izin verdiğinde anonim teşhis verilerini Google'a yükleyebilir. Veriler, WebView somutlaştıran her uygulama için uygulama bazında toplanır. Manifest'in <application> öğesinde aşağıdaki etiketi oluşturarak bu özelliği devre dışı bırakabilirsiniz:

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

Veriler yalnızca kullanıcı izin verirse ve uygulama devre dışı bırakmazsa bir uygulamadan yüklenir. Teşhis verileri raporlamasını devre dışı bırakma hakkında daha fazla bilgi için Web Görünümü raporlarında kullanıcı gizliliği bölümüne bakın.

Fesih İşlemi API'si

Fesih İşlemler API'si, sistemin gerekli belleği geri kazanmak için oluşturucuyu sonlandırması veya oluşturucu işleminin çökmesi nedeniyle bir WebView nesnesine ilişkin oluşturucu sürecinin kaybolduğu durumları ele alır. Bu API'yi kullandığınızda, oluşturucu işlemi kaybolsa bile uygulamanızın çalışmaya devam etmesini sağlarsınız.

Oluşturucu belirli bir web sayfası yüklenirken kilitlenirse aynı sayfanın tekrar yüklenmeye çalışılması yeni bir WebView nesnesinin aynı oluşturma kilitlenme davranışını göstermesine neden olabilir.

Aşağıdaki kod snippet'inde bu API'nin bir Activity içinde nasıl kullanılacağı gösterilmektedir:

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

Oluşturucu Önem API'si

WebView nesneleri çok işlemli modda çalıştığında uygulamanızın bellek yetersizliği durumlarını ele alma konusunda biraz esnekliğe sahip olursunuz. Belirli bir WebView nesnesine atanan oluşturucu için bir öncelik politikası belirlemek üzere Android 8.0'da sunulan Renderer Importance API'sini kullanabilirsiniz. Özellikle, uygulamanızın WebView nesnelerini gösteren bir oluşturucu sonlandırıldığında uygulamanızın ana bölümünün çalışmaya devam etmesini isteyebilirsiniz. Örneğin, sistemin oluşturucunun kullandığı belleği geri kazanabilmesi için WebView nesnesinin uzun süre gösterilmemesini istiyorsanız bunu yapabilirsiniz.

Aşağıdaki kod snippet'inde, uygulamanızın WebView nesneleriyle ilişkili oluşturucu işlemine nasıl öncelik atanacağı gösterilmektedir:

Kotlin

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

Java

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

Bu belirli snippet'te oluşturucunun önceliği, uygulamanın varsayılan önceliğiyle aynıdır veya bu önceliğe bağlıdır. true bağımsız değişkeni, ilişkili WebView nesnesi artık görünür olmadığında oluşturucunun önceliğini RENDERER_PRIORITY_WAIVED değerine düşürür. Diğer bir deyişle, true bağımsız değişkeni, uygulamanızın sistemin oluşturucu sürecini canlı tutup tutmadığını umursamadığını gösterir. Aslında bu düşük öncelik düzeyi, oluşturucu işleminin bellek yetersiz durumlarda sonlandırılmasına neden olabilir.

Sistemin düşük bellek durumlarını nasıl ele aldığı hakkında daha fazla bilgi edinmek için Süreçler ve uygulama yaşam döngüsü bölümüne bakın.