WebView'da tahmine dayalı içerik yükleme

Gezinme gecikmesi, kullanıcı deneyimi açısından kritik bir metriktir. WebView, geliştiricilerin bu gecikmeyi azaltmasına yardımcı olmak için tahmine dayalı içerik yükleme ve bağlantı optimizasyonu API'leri sağlar. Bu API'ler, uygulamanızın kullanıcı açıkça içeriğe gitmeden önce içeriği getirmesine veya oluşturmasına olanak tanır.

WebView, protokol görüşmesini optimize etmek için QUIC ipuçlarının yanı sıra üç temel tahmine dayalı içerik türünü destekler: Preconnect, Prefetch ve Prerender.

Tahmine dayalı içerik yükleme stratejisi uygulayarak aşağıdakileri elde edebilirsiniz:

  • Web içeriği yükleme gecikmesinde önemli azalma: Ağ başlatma süresini uygulama yaşam döngüsünde daha erkene taşıyın ve HTTP/3 gibi daha hızlı protokolleri tercih edin.
  • Daha yüksek gezinme başarı oranları: Ağı ve önbelleği önceden ısıtarak geçici ağ sorunları nedeniyle gezinmelerin başarısız olma olasılığı azalır.
  • Daha iyi algılanan yanıt verme hızı: Özellikle önceden işleme, uygulamanın önemli ölçüde daha hızlı görünmesini sağlayan anlık geçişlere olanak tanır.

Tahmine dayalı içerik stratejisi seçme

Bu stratejiler arasındaki temel fark kapsamlarında yatar: Preconnect ve QUIC ipuçları API'leri kaynak tabanlıdır. Bu nedenle yalnızca hedef alan adı gerekir. Önceden getirme ve önceden oluşturma API'leri URL tabanlıdır. Bu nedenle, tam web sayfası yolunu gerektirirler.

Ön bağlantı ve QUIC ipuçları kaynak düzeyinde çalıştığından, kullanıcının gideceği belirli içeriği veya sayfayı bilmeden bunları çağırabilirsiniz.

Aşağıdaki tabloda, kullanım alanınıza uygun olanı seçmenize yardımcı olmak için bu üç strateji karşılaştırılmaktadır:

Özellik Önceden bağlanma Önceden getirme Önceden oluşturma
Birincil hedef Bağlantıyı ısıtma Yalnızca HTML'yi (JavaScript veya CSS olmadan) önbelleğe alma Sayfanın tamamını önceden oluşturma
Kapsam Profil düzeyi (WebView'larda paylaşılır) Profil düzeyi (WebView'larda paylaşılır) WebView düzeyi (belirli bir WebView'a bağlı)
Jetpack WebKit API androidx.webkit.Profile androidx.webkit.Profile androidx.webkit.WebViewCompat
Temel API yöntemleri preconnect(...) prefetchUrlAsync(...) prerenderUrlAsync(...)
Yapılandırma Yok PrefetchCache.setMaxPrefetches()
PrefetchCache.setPrefetchTtlSeconds()
setMaxPrerenders()
Kaynak kullanımı Düşük (ağ) Orta (ağ, bellek) Yüksek (CPU, bellek, ağ)
Kullanılacağı zaman Hedef kaynak biliniyor ancak belirli URL henüz belirlenmediğinde. Tam URL bilindiğinde ve gezinme olasılığı yüksek olduğunda, önbellek WebViews arasında paylaşılır. Tam URL bilindiğinde ve belirli bir WebView'da gezinme işlemi büyük ölçüde kesin olduğunda.
Avantajlar Kaynakta bulunan tüm URL'ler için daha hızlı bağlantı kurulumu Eşleşen URL'ler için daha hızlı ağ yükü Etkinleştirildikten sonra anında navigasyon

Kaynaklara önceden bağlanma

Ön bağlantı, belirtilen bir kaynak için DNS aramaları ve TCP/TLS veya QUIC el sıkışmaları önceden gerçekleştirerek gelecekteki yüklemeleri hızlandırır.

Tam hedef URL gerektiren önceden getirme ve önceden oluşturma işlemlerinin aksine, ön bağlantı kesinlikle kaynak tabanlıdır. Bu, tam URL'yi bilmeden önce Preconnect'i çağırmanıza olanak tanır. Ne zaman arama yapacağınızla ilgili bilgi için Uygulama bölümündeki ipucuna bakın.

Bu düşük kaynaklı, profil düzeyindeki strateji, kaynak daha önce ziyaret edilmediği sürece profili paylaşan tüm WebView'ler için ilk gecikmeyi azaltır. Bağlantı yaklaşık 30 saniye açık kalır. Bu sayede, el sıkışma ek yükünü ortadan kaldırarak sonraki tüm kaynaklar arası HTTP istekleri, gezinmeler veya alt kaynaklar avantaj sağlar. DNS arama sonucu, bağlantıdan daha uzun süre önbelleğe alınır. Bu nedenle, bağlantı kapatıldıktan sonra da kaynağa yapılan sonraki isteklerde arama atlanabilir.

Uygulama

Ön bağlantı başlatmak için Profile örneğinde preconnect(String url) hizmetini arayın. Bu API, kullanıcı arayüzü iş parçacığında çağrılmalı ve WebViewFeature.PRECONNECT'nın desteklenmesini gerektirir.

API, kaynak üzerinde çalışır ancak kolaylık sağlamak için tam bir URL (ör. https://www.example.com/index.html) sağlanabilir. Bu, otomatik olarak kaynağa yapılan bir çağrı (ör. https://www.example.com) olarak değerlendirilir. Bu API birden çok kez çağrılarak birden fazla kaynağa bağlanılabilir.

Kotlin

// Must be called on the @UiThread
if (WebViewFeature.isFeatureSupported(WebViewFeature.PRECONNECT)) {
    profile.preconnect("https://www.example.com/index.html")
    // This initiates a connection to the origin https://www.example.com
}

Java

// Must be called on the @UiThread
if (WebViewFeature.isFeatureSupported(WebViewFeature.PRECONNECT)) {
    profile.preconnect("https://www.example.com/index.html");
    // This initiates a connection to the origin https://www.example.com
  }

QUIC ipuçlarıyla QUIC protokolü desteğini belirtme

HTTP/3 (QUIC taşıma protokolü üzerinden çalışır), HTTP/2'ye kıyasla önemli gecikme iyileştirmeleri sunar. Bunlar arasında 0-RTT el sıkışmaları, bağlantı esnekliğinin iyileştirilmesi ve paket kaybı sırasında satır başı engellemenin ortadan kaldırılması yer alır.

Varsayılan olarak WebView, yalnızca kaynağın QUIC'i desteklediğine dair bir belirti varsa (ör. önceki etkileşimden gelen bir Alt-Svc üstbilgisi veya DNS HTTPS kaydı) QUIC bağlantısı kurmaya çalışır. Bu ön bilgi olmadan WebView, ilk bağlantı için HTTP/2 veya HTTP/1.1 kullanır.

Calling addQuicHints bu protokol desteği bilgilerini önceden doldurarak WebView'ın belirtilen kaynaklara ilk bağlantıdan itibaren hemen QUIC kullanarak bağlanmasına olanak tanır.

QUIC ipuçlarıyla önceden bağlanma

Hem ön bağlantı hem de QUIC ipuçları, Profile üzerinde kaynak düzeyinde optimizasyonlar olsa da farklı ve tamamlayıcı rollere hizmet eder:

  • preconnect: Yaklaşık 30 saniye boyunca etkin bir şekilde ağ bağlantısı (DNS araması ve TCP/TLS veya QUIC el sıkışması) açar ve sürdürür. Etkin ağ bağlantılarını açık tuttuğu için cihaz ve ağ kaynaklarını tüketir ve yüksek olasılıklı hedef kaynaklar için ayrılmalıdır.
  • addQuicHints: Anında ağ trafiğine neden olmaz. Protokol desteğini kaydetmek için Profile ağ yığınının bellekteki sunucu özelliklerini günceller. QUIC ipuçları, ihmal edilebilir bir ek yüke sahip olduğundan uygulama başlatılırken bilinen tüm HTTP/3 özellikli kaynaklar için güvenle yapılandırılabilir.

Optimum performans için preconnect, prefetchUrlAsync veya loadUrl'ü çağırmadan önce addQuicHints'ı çağırın. Bu sayede, sonraki tüm ön bağlantılar veya sayfa istekleri HTTP/3'ü en baştan itibaren kullanır.

Uygulama

QUIC ipuçlarını yapılandırmak için Profile örneğinde addQuicHints(Set<String> urls) işlevini çağırın. Bu API'yi kullanıcı arayüzü iş parçacığında çağırmalı ve WebView'ın WebViewFeature.ADD_QUIC_HINTS_V1 özelliğini desteklediğini doğrulamalısınız.

preconnect gibi, addQuicHints de kaynaklar üzerinde çalışır ancak tam URL'ler (ör. https://www.example.com/index.html) sağlanabilir ve otomatik olarak kaynaklarına (https://www.example.com) göre normalleştirilir.

Bu yöntem eklenerek çalışır: Birden çok kez çağrıldığında, sağlanan kaynaklar Profile genelinde birleştirilir.

Kotlin

// Must be called on the @UiThread
@OptIn(Profile.ExperimentalAddQuicHints::class)
if (WebViewFeature.isFeatureSupported(WebViewFeature.ADD_QUIC_HINTS_V1)) {
    val quicOrigins = setOf(
        "https://www.example.com",
        "https://api.example.com"
    )
    profile.addQuicHints(quicOrigins)
    // WebView now prioritizes HTTP/3 over QUIC for connections to these origins
}

Java

// Must be called on the @UiThread
// Requires @Profile.ExperimentalAddQuicHints annotation or suppression
if (WebViewFeature.isFeatureSupported(WebViewFeature.ADD_QUIC_HINTS_V1)) {
    Set<String> quicOrigins = new HashSet<>(Arrays.asList(
        "https://www.example.com",
        "https://api.example.com"
    ));
    profile.addQuicHints(quicOrigins);
    // WebView now prioritizes HTTP/3 over QUIC for connections to these origins
}

Genel yapılandırma: PrefetchParameters ve PrerenderParameters

Hem önceden getirme hem de önceden oluşturma, isteği özelleştirmek için PrefetchParameters veya PrerenderParameters kullanır. Bu sınıflar, No-Vary-Search yapılandırmaları gibi URL eşleştirme için ek başlıklar ve ipuçları sağlamanıza olanak tanır.

Kotlin

// Isolated configuration specifically for Cache-Level Prefetching
val prefetchParams = PrefetchParameters.Builder()
    .addAdditionalHeader("X-Custom-Client", "Android-App-V2")
    .setExpectedNoVarySearchHeader(
        NoVarySearchHeader.varyExcept(true, listOf("session_id", "click_ref"))
    )
    .build()

Java

PrefetchParameters prefetchParams = new PrefetchParameters.Builder()
    .addAdditionalHeader("X-Custom-Header", "value")
    /**
     * Hint to ignore specific query parameters during cache matching.
     * This allows the cache to match even if the tracking_id differs.
     */
    .setExpectedNoVarySearchHeader(
        NoVarySearchHeader.varyExcept(true, Arrays.asList("tracking_id"))
    )
    /**
     * Determines if Client Hints are sent.
     * NOTE: This is ignored for Prerendering API requests, which default to
     * the WebView's WebSettings.getJavaScriptEnabled() value.
     */
    .setJavaScriptEnabled(true)
    .build();

İçeriği önceden getirme

Önceden getirme, bir URL'nin ana HTML kaynağını indirip profilin ağ önbelleğinde saklar. WebView'da Profile, çerezler, HTTP önbelleği ve hizmet çalışanları dahil olmak üzere tarayıcı verileri için kapsayıcı görevi görür. Önceden getirme, profil düzeyinde bir işlem olduğundan bu profille ilişkili tüm WebView, önbelleğe alınmış yanıttan yararlanabilir.

Uygulama

Önceden getirme işlemini başlatmak için bir Profile örneğinde prefetchUrlAsync() işlevini çağırın. Bu işlem yalnızca HTTPS şemasını destekler.

Kotlin

profile.prefetchUrlAsync(
    url,
    prefetchParams,
    cancellationSignal,
    executor,
    object : WebViewOutcomeReceiver<PrefetchResult, PrefetchException> {
        override fun onResult(result: PrefetchResult) {
            if (result.wasDuplicate()) {
                // URL and No-Vary-Search permutations already exist in the cache layer
            } else {
                // The HTML payload has been successfully secured in the HTTP cache
            }
        }

        override fun onError(error: PrefetchException) {
            when (error) {
                is PrefetchNetworkException -> {
                    // Isolates network layer or server-side HTTP anomalies
                    val code = error.httpStatusCode
                    // Facilitates rapid diagnosis of 4xx or 5xx server responses
                }
                else -> {
                    // Catches generalized execution failures and system constraints
                }
            }
        }
    }
)

Java

profile.prefetchUrlAsync(
    url,
    prefetchParams,
    cancellationSignal,
    executor,
    new WebViewOutcomeReceiver<PrefetchResult, PrefetchException>() {
        @Override
        public void onResult(PrefetchResult result) {
            if (result.wasDuplicate()) {
                // URL and No-Vary-Search permutations already exist in the cache layer
            } else {
                // The HTML payload has been successfully secured in the HTTP cache
            }
        }

        @Override
        public void onError(PrefetchException error) {
            if (error instanceof PrefetchNetworkException) {
                // Isolates network layer or server-side HTTP anomalies
                int code = ((PrefetchNetworkException) error).httpStatusCode;
                // Facilitates rapid diagnosis of 4xx or 5xx server responses
            } else {
                // Catches generalized execution failures and system constraints
            }
        }
    }
);

Pas arası yaşam döngüsü

WebView önceden getirme isteği, shouldInterceptRequest() geri çağırma işleminin ne zaman ve nasıl tetikleneceğini değiştirir. Bu durum, önceden getirilmiş içeriğinizin başarılı bir şekilde kullanılıp kullanılmayacağını doğrudan etkilediğinden iki adımlı yaşam döngüsünü anlamak çok önemlidir:

Spekülasyon ve gezinme aşamalarında iki adımlı WebView önceden getirme yakalama yaşam döngüsünü gösteren diyagram.
Şekil 1. WebView önceden getirme istekleri ve gezinmeleri için iki adımlı yakalama yaşam döngüsü.

1. Spekülatif aşama (önceden getirme isteği)

prefetchUrlAsync() çağrıldığında WebView, ana HTML kaynağını arka planda indirir. Bu arka plan isteği için shouldInterceptRequest() tamamen atlanır. Genellikle önleyici işlevinizde işlenen özel mantıklar, yetkilendirme jetonları veya üstbilgi eklemeleri, önceden getirilmiş HTML kaynağına uygulanmaz.

2. Gezinme aşaması (kullanıcı etkinleştirme)

Uygulama URL'ye açıkça gittiğinde (örneğin, WebViewCompat.navigate veya loadUrl kullanılarak) ya da kullanıcı eşleşen bir bağlantıyı tıkladığında WebView, önceden getirilmiş önbelleği kullanıp kullanamayacağını belirler:

  • Ana HTML değerlendirmesi: WebView, bu noktada ana HTML için shouldInterceptRequest() tetikleyecektir. Sayfanın önceden getirme önbelleğinden başarıyla sunulması için kesicinizin null değerini döndürmesi gerekir. Özel bir WebResourceResponse döndürürseniz WebView, kesicinizin isteğini karşılar ve önceden getirme önbelleğini tamamen atlar.

  • Alt kaynak değerlendirmesi: Önceden getirilmiş HTML'nin kullanıma uygun olduğu onaylandıktan sonra, shouldInterceptRequest() sayfanın oluşturulmasını tamamlamak için gereken tüm sonraki alt kaynaklar (ör. resimler, komut dosyaları ve CSS) için normal şekilde tetiklenir.

Önemli davranışlar

Aşağıdaki operasyonel özellikler ve uygunluk kontrolleri, WebView'ın önceden getirme isteklerini nasıl başlattığını ve yönettiğini belirler:

  • İş parçacığı güvenliği: İstekler herhangi bir iş parçacığından başlatılabilir.
  • Uygunluk: WebView, getirme işlemi başlatmadan önce aşağıdaki kontrolleri yaparak isteğin güvenli ve bağlama uygun olduğundan emin olur:
    • Mevcut çerezler: WebView, kullanıcı gizliliğini korumak ve CSRF benzeri yan etkileri önlemek için istek, sunucuda durum değişikliğini tetikleyebilecek belirli kimliği doğrulanmış çerezler gerektiriyorsa önceden getirme işlemini atlayabilir.
    • Hizmet çalışanı varlığı: Bir hizmet çalışanı, URL'nin kapsamını zaten kontrol ediyorsa WebView, standart bir ağ önceden getirme işlemi başlatmak yerine hizmet çalışanının getirme işleyicisini kullanabilir.
    • Proxy kullanılabilirliği: WebView, karmaşık ağ yapılandırmaları altında spekülatif isteklerin başarısız olmasını önlemek için mevcut ağ yolunun (yapılandırılmış tüm proxy'ler dahil) kararlı olduğunu doğrular.
  • Önceden getirme işlemi (geçerli parametrelerle bile) başlatılamazsa bunun nedeni genellikle WebView'ın, arka plan isteğinin kullanıcının mevcut oturumuna veya güvenlik durumuna müdahale edebileceğini belirlemesidir.
  • İptal: Devam eden bir isteği sonlandırmak ve önbelleğe alınmasını önlemek için CancellationSignal kullanın.

Sayfaları önceden oluşturma

Önceden işleme, komut dosyası yürütme ve alt kaynak getirme dahil olmak üzere bir sayfayı arka planda tam olarak oluşturmak için gizli "web içeriği" oluşturur. Önceden oluşturma, önceden getirme ile aynı temel altyapıyı kullanır. Bir uygulama önceden oluşturma işlemi başlatırsa WebView, önceden oluşturma gezinmesine hizmet vermek için önce yanıtı önceden getirir ve gereksiz ağ etkinliğini önler.

Uygulama

Önceden oluşturma, WebView örneği düzeyinde bir işlemdir. Kullanıcı arayüzü iş parçacığından prerenderUrlAsync() işlevini WebViewCompat ile çağırın.

Kotlin

WebViewCompat.prerenderUrlAsync(
    webView,
    url,
    cancellationSignal,
    executor,
    params,
    object : PrerenderOperationCallback {
        override fun onPrerenderActivated() {
            // Called when the user navigates to the URL and the hidden page is swapped in
        }

        override fun onError(exception: Throwable) {
            // exception is an instance of PrerenderException
            // Handle prerender failure (for example, memory pressure or disallowed JavaScript APIs)
        }
    }
)

Java

WebViewCompat.prerenderUrlAsync(webView, url, cancellationSignal, executor, params, new PrerenderOperationCallback() {
    @Override
    public void onPrerenderActivated() {
        // Called when the user navigates to the URL and the hidden page is swapped in.
    }

    @Override
    public void onError(@NonNull Throwable exception) {
        // Handle prerender failure (for example, resource constraints or disallowed APIs).
    }
});

Hem önceden getirme hem de önceden oluşturma tamamen eşzamansızdır. prefetchUrlAsync() herhangi bir iş parçacığından çağrılabilirken prerenderUrlAsync(), kullanıcı arayüzü iş parçacığından başlatılmalıdır.

Teknik kısıtlamalar

WebView, anında gezinme ile sistem sağlığı arasında denge kurmak için aşağıdaki çalışma zamanı kısıtlamalarını uygular:

  • Bellek baskısı: Cihazın RAM'i düşükse WebView, önceden oluşturulmuş URL'leri iptal eder.
  • İzin verilmeyen API'ler: JavaScript'in arka plan bağlamında belirli API'lere (ör. ses çalma, uyarılar) erişme girişimleri, önceden oluşturma işlemini anında sonlandırır.
  • Örnek sınırı: WebView başına izin verilen etkin önceden oluşturulmuş URL'lerin sayısı sınırlıdır.

URL eşleşmesi ve No-Vary-Search (NVS)

WebView, önceden yüklenmiş bir kaynağın yalnızca amaçlanan gezinme için sunulmasını sağlamak üzere güvenilir bir eşleştirme algoritması gerektirir.

Tam eşleme ve NVS eşleşmesi

Varsayılan olarak, önceden getirme ve önceden oluşturma için tam URL eşleşmesi gerekir. Gidilen URL, önceden yüklenen URL ile aynıysa hemen önbellekten sunulur. Sorgu parametreleri farklıysa WebView, aşağıdaki No-Vary-Search (NVS) kurallarını kullanır:

  • İpucu: Geliştiriciler, başlatma sırasında setExpectedNoVarySearchHeader() ipucu verir. Gidilen URL, ipucu verilen parametreler hariç istek URL'siyle eşleşirse WebView, sunucunun gerçek başlıklarını beklemek için kısa bir süre engellenir.
  • Sunucu başlığı: Sunucudan gelen NVS yanıt başlığı nihai yetkilidir. Sunucu, sorgu farklılıklarının yoksayılması gerektiğini onaylarsa eşleşme önbellekten sunulur. Aksi takdirde WebView, soğuk ağ yüklemesine geri döner.

No-Vary-Search (NVS), ileri düzey kullanım içindir ve çoğu geliştirici, hem önceden getirme hem de gezinme için tam olarak aynı URL'yi ilettiğinden (WebViewCompat.navigate veya loadUrl) bu özelliği kullanmak zorunda kalmayabilir. Bu kılavuz yalnızca önceden getirme URL'si ile gezinilen URL arasında sorgu parametrelerinde farklılıklar varsa gereklidir.

Genel yapılandırma

PrefetchCache sınırlarını ve maksimum önceden oluşturma sayısını yapılandırarak tahmine dayalı içerik yükleme davranışını profil düzeyinde ayarlayın. Özel önceden getirme sınırlarını sistem varsayılanlarına da sıfırlayabilirsiniz:

Kotlin

// Configure prefetch cache limits
profile.prefetchCache.setMaxPrefetches(10)
profile.prefetchCache.setPrefetchTtlSeconds(60)

// Reset to system defaults when needed
profile.prefetchCache.clearMaxPrefetches()

// Configure maximum active prerenders
profile.setMaxPrerenders(2)

Java

// Configure prefetch cache limits
PrefetchCache prefetchCache = profile.getPrefetchCache();
prefetchCache.setMaxPrefetches(10);
prefetchCache.setPrefetchTtlSeconds(60);

// Reset to system defaults when needed
prefetchCache.clearMaxPrefetches();

// Configure maximum active prerenders
profile.setMaxPrerenders(2);

Hata işleme ve istisnalar

Tahmini işlemler, sonuçları bildirmek için OutcomeReceiverCompat veya PrerenderOperationCallback kullanır.

Birincil istisnalar

Tahmine dayalı içerik yükleme işlemi başarısız olduğunda, hata işleyiciniz belirli hata senaryolarını teşhis etmenize yardımcı olmak için aşağıdaki temel istisna türlerinden birini bildirir:

  • PrefetchException: Tüm eşzamansız önceden getirme hataları için temel sınıf.
  • PrefetchNetworkException: Ağ veya sunucu düzeyinde bir hata olduğunu gösterir. Sunucu tarafındaki sorunların teşhis edilmesine yardımcı olmak için httpStatusCode alanı (ör. 404 veya 503) içerebilir.
  • PrerenderException: Bellek baskısı veya arka planda izin verilmeyen API'lerin (ör. ses oynatma) kullanılması nedeniyle oluşan hatalar gibi önceden oluşturmayla ilgili tüm hataların üst sınıfı.

Optimizasyon stratejileri

Sistem kaynaklarını korurken tahmine dayalı içeriğin avantajlarından en iyi şekilde yararlanmak için aşağıdaki önerileri uygulayın:

  • Erken başlatın: Uygulama başlatılırken veya bir gezinme hedefi olası olduğu anda önceden getirme işlemine başlayın.
  • QUIC ipuçlarını bağlantı ön ısıtmasıyla eşleştirin: WebView'ın HTTP/3 kullanarak bağlantı oluşturmaya çalışmasını sağlamak için preconnect(), prefetchUrlAsync() veya standart gezinmeler başlatılmadan önce addQuicHints() çağrısı yapın.
  • Entegre strateji: Önceden getirme önbelleğinde bulunan bir URL'yi önceden oluşturursanız önceden oluşturma gezinmesi bu önbellekten sunulur ve gereksiz ağ istekleri önlenir.
  • Kotaları izleme: Önceden oluşturma, kaynak açısından yoğundur. Birkaç olası aday için önceden getirmeyi tercih edin ve tek bir olası gezinme için önceden oluşturmayı ayırın.
  • Şema desteği: Tüm URL'lerin zorunlu HTTPS şemasını kullandığından emin olun. Geçersiz şemalar veya boş girişler, senkron IllegalArgumentException tetikler.

Ek kaynaklar

Web uygulamalarında hata ayıklama, WebView başlatma performansını optimize etme ve oluşturma işlemi sonlandırmayı işleme hakkında daha fazla bilgi edinmek için aşağıdaki kaynaklara bakın: