WebView nesnelerini yönetme

Android, uygulamanızda web içeriğini gösteren WebViewnesneleri yönetmenize yardımcı olacak çeşitli API'ler sunar.

Bu sayfada, WebView nesneleriyle daha etkili bir şekilde çalışmak için bu API'lerin nasıl kullanılacağı açıklanmaktadır. Bu sayede uygulamanızın kararlılığı ve güvenliği artırılır.

Version API

Android 7.0'dan (API düzeyi 24) itibaren kullanıcılar, web içeriğini bir WebView nesnesinde görüntülemek için çeşitli paketler arasından seçim yapabilir. Jetpack 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ı kullanılarak web içeriğini görüntülemeye çalıştığında oluşan hataları analiz ederken faydalı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

Kullanıcılarınıza daha güvenli bir tarama deneyimi sunmak için WebView nesneler, URL'leri Google Güvenli Tarama'yı kullanarak doğrular. Bu sayede uygulamanız, kullanıcılar potansiyel olarak güvenli olmayan bir web sitesine gitmeye çalıştığında onlara uyarı gösterebilir.

EnableSafeBrowsing'nın varsayılan değeri doğru olsa da Güvenli Tarama'yı yalnızca koşullu olarak etkinleştirmek veya devre dışı bırakmak isteyebileceğiniz durumlar olabilir. Android 8.0 (API düzeyi 26) ve sonraki sürümlerde, tek bir WebView nesnesi için Güvenli Tarama'yı etkinleştirmek veya devre dışı bırakmak üzere setSafeBrowsingEnabled() kullanılabilir.

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

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

Programatik işlemleri tanımlama

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 kullanıcılara bilinen tehdit hakkında uyarı veren bir ara sayfa gösterir. Bu ekran, kullanıcılara URL'yi yine de yükleme veya güvenli olan önceki bir sayfaya dönme seçeneği sunar.

Android 8.1'i (API düzeyi 27) veya sonraki sürümleri hedefliyorsanız uygulamanızın bilinen bir tehdide nasıl yanıt vereceğini aşağıdaki şekillerde programatik olarak tanımlayabilirsiniz:

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

Aşağıdaki kod snippet'lerinde, bilinen bir tehditle karşılaştıktan sonra uygulamanızın WebView örneklerine her zaman güvenliğe geri dönme talimatının nasıl verileceği gösterilmektedir:

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 Geolocation API

Android 6.0 (API düzeyi 23) ve sonraki sürümleri hedefleyen uygulamalarda Geolocation 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ırakma

WebView, kullanıcı izni verdiğinde Google'a anonim teşhis verileri yükleyebilir. Veriler, WebView örneği oluşturan her uygulama için uygulama bazında toplanır. Manifest dosyasının <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 kapsam dışında kalmayı tercih etmezse uygulamadan yüklenir. Teşhis verileri raporlamayı devre dışı bırakma hakkında daha fazla bilgi için WebView raporlamasında kullanıcı gizliliği başlıklı makaleyi inceleyin.

Termination Handling API

Termination Handling API, bir WebView nesnesinin oluşturma işlemi, sistemin gerekli belleği geri kazanmak için oluşturma işlemini sonlandırması veya oluşturma işleminin kilitlenmesi nedeniyle ortadan kalktığında bu durumu ele alır. Bu API'yi kullanarak, oluşturma işlemi ortadan kalksa bile uygulamanızın yürütülmeye devam etmesini sağlayabilirsiniz.

Belirli bir web sayfası yüklenirken bir oluşturucu kilitlenirse aynı sayfayı tekrar yüklemeye çalışmak yeni bir WebView nesnesinin aynı oluşturma kilitlenme davranışını sergilemesine neden olabilir.

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

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 nesneleri çoklu işlem modunda çalışırken uygulamanızın bellek yetersizliği durumlarını nasıl işlediği konusunda biraz esnekliğe sahip olursunuz. Android 8.0'da kullanıma sunulan Oluşturucu Önem Derecesi API'sini kullanarak belirli bir WebView nesnesine atanan oluşturucu için bir öncelik politikası belirleyebilirsiniz. Özellikle, uygulamanızın WebView nesnelerini görüntüleyen bir oluşturucu sonlandırıldığında uygulamanızın ana bölümünün yürütülmeye devam etmesini isteyebilirsiniz. Örneğin, WebView nesnesini uzun süre göstermeyeceğinizi düşünüyorsanız bu işlemi yapabilirsiniz. Böylece sistem, oluşturucunun kullandığı belleği geri alabilir.

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 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 olarak düşürür. Diğer bir deyişle, true bağımsız değişkeni, uygulamanızın sistemin oluşturma işlemini canlı tutmasıyla ilgilenmediğini gösterir. Hatta bu düşük öncelik düzeyi, oluşturucu sürecinin bellek yetersizliği durumlarında sonlandırılma olasılığını artırır.

Sistemin düşük bellek durumlarını nasıl ele aldığı hakkında daha fazla bilgi edinmek için İşlemler ve uygulama yaşam döngüsü başlıklı makaleyi inceleyin.