Uygulama içi içeriği yükleme

Uygulamanızın internet üzerinden getirmek yerine statik olarak derlediğiniz içerikleri kullanması için web tabanlı içerik (ör. HTML, JavaScript ve CSS) sağlayabilirsiniz.

Uygulama içi içerikler internet erişimi gerektirmez veya kullanıcının bant genişliğini kullanmaz. İçerik yalnızca WebView için özel olarak tasarlanmışsa, yani yerel bir uygulamayla iletişim kurulması gerekiyorsa kullanıcılar içeriği bir web tarayıcısında yanlışlıkla yükleyemezler.

Ancak uygulama içi içeriğin bazı dezavantajları vardır. Web tabanlı içeriği güncellemek için yeni bir uygulama güncellemesinin gönderilmesi gerekir ve kullanıcıların eski uygulama sürümleri varsa web sitesindekilerle cihazınızdaki uygulamanın içeriği arasında uyuşmazlık olma ihtimali vardır.

WebViewÖğeYükleyicisi

WebViewAssetLoader, uygulama içi içeriği bir WebView nesnesine yüklemenin esnek ve etkili bir yoludur. Bu sınıf aşağıdakileri destekler:

  • Aynı kaynak politikasıyla uyumluluk için HTTP(S) URL'si ile içerik yükleme.
  • JavaScript, CSS, resimler ve iframe'ler gibi alt kaynaklar yükleme.

WebViewAssetLoader uygulamasını ana etkinlik dosyanıza ekleyin. Aşağıda, items klasöründen basit web içeriği yüklemeye ilişkin bir örnek verilmiştir:

Kotlin

private class LocalContentWebViewClient(private val assetLoader: WebViewAssetLoader) : WebViewClientCompat() {
    @RequiresApi(21)
    override fun shouldInterceptRequest(
        view: WebView,
        request: WebResourceRequest
    ): WebResourceResponse? {
        return assetLoader.shouldInterceptRequest(request.url)
    }

    // To support API < 21.
    override fun shouldInterceptRequest(
        view: WebView,
        url: String
    ): WebResourceResponse? {
        return assetLoader.shouldInterceptRequest(Uri.parse(url))
    }
}

Java

private static class LocalContentWebViewClient extends WebViewClientCompat {

    private final WebViewAssetLoader mAssetLoader;

    LocalContentWebViewClient(WebViewAssetLoader assetLoader) {
        mAssetLoader = assetLoader;
    }

    @Override
    @RequiresApi(21)
    public WebResourceResponse shouldInterceptRequest(WebView view,
                                     WebResourceRequest request) {
        return mAssetLoader.shouldInterceptRequest(request.getUrl());
    }

    @Override
    @SuppressWarnings("deprecation") // To support API < 21.
    public WebResourceResponse shouldInterceptRequest(WebView view,
                                     String url) {
        return mAssetLoader.shouldInterceptRequest(Uri.parse(url));
    }
}

Uygulamanız, ihtiyaçlarına uygun bir WebViewAssetLoader örneği yapılandırmalıdır. Sonraki bölümde bir örnek verilmiştir.

Uygulama içi öğeler ve kaynaklar oluşturun

WebViewAssetLoader, belirli bir kaynak yoluna karşılık gelen kaynakları yüklemek için PathHandler örneklerinden yararlanır. Uygulamanızın ihtiyaç duyduğu kaynakları almak için bu arayüzü kullanabilirsiniz. Ancak Webkit kitaplığı, Android öğelerini ve kaynaklarını yüklemek için sırasıyla AssetsPathHandler ve ResourcesPathHandler paketlerini kullanabilir.

Başlamak için uygulamanız için öğeler ve kaynaklar oluşturun. Genellikle aşağıdakiler geçerlidir:

  • HTML, JavaScript ve CSS gibi metin dosyaları öğelere aittir.
  • Görüntüler ve diğer ikili dosyalar kaynaklara aittir.

Bir projeye metin tabanlı web dosyaları eklemek için şunları yapın:

  1. Android Studio'da uygulama > src > ana klasörü sağ tıklayın ve Yeni > Dizin'i seçin.
    Android Studio dizin oluşturma menülerini gösteren resim
    Şekil 1. Projeniz için bir öğe klasörü oluşturun.
  2. Klasöre "assets" adını verin.
    Öğe klasörünü gösteren bir resim
    Şekil 2. Varlıklar klasörüne bir ad verin.
  3. assets klasörünü sağ tıklayın, ardından Yeni > Dosya'yı tıklayın. index.html yazıp Return veya Enter tuşuna basın.
  4. stylesheet.css için boş bir dosya oluşturmak üzere önceki adımı tekrarlayın.
  5. Oluşturduğunuz boş dosyaları sonraki iki kod örneğindeki içerikle doldurun.
```html
<!-- index.html content -->

<html>
  <head>
    <!-- Tip: Use relative URLs when referring to other in-app content to give
              your app code the flexibility to change the scheme or domain as
              necessary. -->
    <link rel="stylesheet" href="/assets/stylesheet.css">
  </head>
  <body>
    <p>This file is loaded from in-app content.</p>
    <p><img src="/res/drawable/android_robot.png" alt="Android robot" width="100"></p>
  </body>
</html>
```

```css
<!-- stylesheet.css content -->

body {
  background-color: lightblue;
}
```

Projenize görüntü tabanlı bir web dosyası eklemek için aşağıdakileri yapın:

  1. Android_symbol_green_RGB.png dosyasını yerel makinenize indirin.

  2. Dosyanın adını android_robot.png olarak değiştirin.

  3. Dosyayı, projenizin sabit diskinizdeki main/res/drawable dizinine manuel olarak taşıyın.

Şekil 4'te, eklediğiniz resim ve bir uygulamada oluşturulmuş önceki kod örneklerindeki metin gösterilmektedir.

Uygulama tarafından oluşturulan çıkışı gösteren resim
Şekil 4. Uygulamada oluşturulan uygulama içi HTML dosyası ve resim dosyası.

Uygulamayı tamamlamak için aşağıdakileri yapın:

  1. İşleyicileri kaydedin ve aşağıdaki kodu onCreate() yöntemine ekleyerek AssetLoader özelliğini yapılandırın:

    Kotlin

    val assetLoader = WebViewAssetLoader.Builder()
                           .addPathHandler("/assets/", AssetsPathHandler(this))
                           .addPathHandler("/res/", ResourcesPathHandler(this))
                           .build()
    webView.webViewClient = LocalContentWebViewClient(assetLoader)
    

    Java

    final WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
             .addPathHandler("/assets/", new WebViewAssetLoader.AssetsPathHandler(this))
             .addPathHandler("/res/", new WebViewAssetLoader.ResourcesPathHandler(this))
             .build();
    mWebView.setWebViewClient(new LocalContentWebViewClient(assetLoader));
    
  2. Aşağıdaki kodu onCreate() yöntemine ekleyerek içeriği yükleyin:

    Kotlin

    webView.loadUrl("https://appassets.androidplatform.net/assets/index.html")
    

    Java

    mWebView.loadUrl("https://appassets.androidplatform.net/assets/index.html");
    

Uygulama içi içeriği web sitenizdeki kaynaklarla birlikte kullanın

Uygulamanızın, uygulama içi ve internetteki içeriğin (ör. web sitenizin CSS'si tarafından stilize edilmiş bir uygulama içi HTML sayfası) bir karışımını yüklemesi gerekebilir. WebViewAssetLoader bu kullanım alanını destekler. Kayıtlı PathHandler örneklerinden hiçbiri belirtilen yol için bir kaynak bulamazsa WebView, internetten içerik yüklemeye geri döner. Uygulama içi içeriği web sitenizdeki kaynaklarla karışık olarak kullanıyorsanız uygulama içi kaynaklar için /assets/ veya /resources/ gibi dizin yollarını ayırın. Web sitenizdeki kaynakları bu konumlarda depolamaktan kaçının.

Kotlin

val assetLoader = WebViewAssetLoader.Builder()
                        .setDomain("example.com") // Replace this with your website's domain.
                        .addPathHandler("/assets/", AssetsPathHandler(this))
                        .build()

webView.webViewClient = LocalContentWebViewClient(assetLoader)
val inAppHtmlUrl = "https://example.com/assets/index.html"
webView.loadUrl(inAppHtmlUrl)
val websiteUrl = "https://example.com/website/data.json"

// JavaScript code to fetch() content from the same origin.
val jsCode = "fetch('$websiteUrl')" +
        ".then(resp => resp.json())" +
        ".then(data => console.log(data));"

webView.evaluateJavascript(jsCode, null)

Java

final WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
           .setDomain("example.com") // Replace this with your website's domain.
           .addPathHandler("/assets/", new AssetsPathHandler(this))
           .build();

mWebView.setWebViewClient(new LocalContentWebViewClient(assetLoader));
String inAppHtmlUrl = "https://example.com/assets/index.html";
mWebView.loadUrl(inAppHtmlUrl);
String websiteUrl = "https://example.com/website/data.json";

// JavaScript code to fetch() content from the same origin.
String jsCode = "fetch('" + websiteUrl + "')" +
      ".then(resp => resp.json())" +
      ".then(data => console.log(data));";

mWebView.evaluateJavascript(jsCode, null);

Web tarafından barındırılan JSON verilerini getiren bir uygulama içi HTML sayfası örneği için GitHub'daki WebView demosuna göz atın.

Taban URL'si ile birlikteyüklenenVeriler

Uygulamanızın yalnızca bir HTML sayfası yüklemesi ve alt kaynaklara müdahale etmesi gerekmiyorsa uygulama öğeleri gerektirmeyen loadDataWithBaseURL()'ı kullanmayı düşünün. Bunu aşağıdaki kod örneğinde gösterildiği gibi kullanabilirsiniz:

Kotlin

val html = "<html><body><p>Hello world</p></body></html>"
val baseUrl = "https://example.com/"

webView.loadDataWithBaseURL(baseUrl, html, "text/html", null, baseUrl)

Java

String html = "<html><body><p>Hello world</p></body></html>";
String baseUrl = "https://example.com/";

mWebView.loadDataWithBaseURL(baseUrl, html, "text/html", null, baseUrl);

Bağımsız değişken değerlerini dikkatli bir şekilde seçin. Aşağıdakileri göz önünde bulundurun:

  • baseUrl: HTML içeriğinizin yüklendiği URL'dir. Bu bir HTTP(S) URL'si olmalıdır.
  • data: Dize olarak görüntülemek istediğiniz HTML içeriğidir.
  • mimeType: Bu genellikle text/html olarak ayarlanmalıdır.
  • encoding: baseUrl bir HTTP(S) URL'si olduğunda kullanılmaz. Bu nedenle null olarak ayarlanabilir.
  • historyUrl: baseUrl ile aynı değere ayarlandı.

Uygulamanızın aynı kaynak politikasına uyduğundan emin olmanıza yardımcı olduğundan, baseUrl olarak HTTP(S) URL'si kullanmanızı önemle tavsiye ederiz.

İçeriğiniz için uygun bir baseUrl bulamıyorsanız ve loadData() kullanmayı tercih ediyorsanız yüzde kodlaması veya Base64 kodlaması ile içeriği kodlamanız gerekir. Aşağıdaki kod örneğinde gösterildiği gibi bunu programatik olarak kodlamak için Base64 kodlamasını seçmenizi ve Android API'lerini kullanmanızı önemle tavsiye ederiz:

Kotlin

val encodedHtml: String = Base64.encodeToString(html.toByteArray(), Base64.NO_PADDING)

webView.loadData(encodedHtml, mimeType, "base64")

Java

String encodedHtml = Base64.encodeToString(html.getBytes(), Base64.NO_PADDING);

mWebView.loadData(encodedHtml, mimeType, "base64");

Kaçınılması gerekenler

Uygulama içi içerik yüklemenin başka yolları da vardır, ancak bunlara karşı şiddetle davranmanızı öneririz:

  • file:// URL'ler ve data: URL'ler, opak kaynaklar olarak kabul edilir. Dolayısıyla fetch() veya XMLHttpRequest gibi güçlü web API'lerinden yararlanamazlar. loadData() dahili olarak data: URL'si kullandığından bunun yerine WebViewAssetLoader veya loadDataWithBaseURL() kullanmanızı öneririz.
  • WebSettings.setAllowFileAccessFromFileURLs() ve WebSettings.setAllowUniversalAccessFromFileURLs() file:// URL'leriyle ilgili sorunlar giderilebiliyor olsa da, bu sorunları true olarak ayarlamanız önerilmez. Bunu yaparsanız uygulamanız dosya tabanlı istismarlara karşı savunmasız hale gelir. En güçlü güvenlik için bunları tüm API düzeylerinde açıkça false olarak ayarlamanızı öneririz.
  • Aynı nedenlerle file://android_assets/ ve file://android_res/ URL'lerini kullanmamanızı öneririz. AssetsHandler ve ResourcesHandler sınıfları, bunların yerini alacak şekilde tasarlanmıştır.
  • MIXED_CONTENT_ALWAYS_ALLOW kullanmaktan kaçının. Bu ayar genellikle gerekli değildir ve uygulamanızın güvenliğini zayıflatır. Uygulama içi içeriğinizi web sitenizin kaynaklarıyla aynı şema (HTTP veya HTTPS) üzerinden yüklemenizi ve uygun şekilde MIXED_CONTENT_COMPATIBILITY_MODE veya MIXED_CONTENT_NEVER_ALLOW kullanmanızı öneririz.