WebView nesnelerini yönetme

Android, uygulamanızda web içeriğini gösteren WebView nesneleri 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 (API düzeyi 24) sürümünden başlayarak, kullanıcılar WebView nesnesinde web içeriğini görüntülemek için çeşitli paketler arasından seçim yapabilir. Jetpack Webkit kitaplığı, uygulamanızda web içeriği gösteren paketle ilgili bilgileri getirmek için getCurrentWebViewPackage() yöntemini içerir. Bu yöntem, yalnızca uygulamanız belirli bir paketin WebView uygulamasıyla web içeriği göstermeye ç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 için varsayılan değer 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

Bir 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 ekranda kullanıcılara URL'yi yine de yükleme veya güvenli olan önceki bir sayfaya dönme seçeneği sunulur.

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 Coğrafi Konum API'si 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ı izin verdiğinde Google'a anonim teşhis verileri yükleyebilir. Veriler, WebView oluşturulan 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 nesnenin oluşturucu sürecinin, sistemin gerekli belleği geri kazanmak için oluşturucuyu sonlandırması veya oluşturucu sürecinin kilitlenmesi nedeniyle ortadan kalktığı durumları 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 Renderer Importance API'yi kullanarak belirli bir WebView nesnesine atanmış oluşturucu için ö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 değerine 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.

Web içeriği kullanırken uygulamanızın bellekte kapladığı yeri teşhis etme ve optimize etme hakkında daha fazla bilgi edinmek için WebView belleğini yönetme ve teşhis etme başlıklı makaleyi inceleyin. Sistemin, işlemler genelinde 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.

Durumu ve gezinme geçmişini koruma

Sistem arka plan kaynaklarını geri aldığında veya cihazda yapılandırma değişikliği yapıldığında uygulamanın etkinliği ve WebView nesneleri yok edilebilir. Kullanıcının gezinme bağlamını korumak için gezinme geçmişini saveState(Bundle) içinde onSaveInstanceState() yöntemiyle Bundle olarak serileştirin ve ardından restoreState(Bundle) kullanarak geri yükleyin.

Android, savedInstanceState için tüm süreçte 1 MB'lık katı bir sınır uyguladığından, büyük göz atma oturumlarını standart çerçeve API'si ile serileştirmek TransactionTooLargeException ile sonuçlanabilir. Boyut sınırlarını zorlamak veya ileriye doğru geçmiş girişlerini güvenli bir şekilde bırakmak için Jetpack Webkit yöntemini kullanın WebViewCompat.saveState().

Durumu verimli bir şekilde yönetmeyle ilgili ayrıntılı stratejiler ve en iyi uygulamalar için WebView durumunu verimli bir şekilde yönetme başlıklı makaleye bakın.