Anda dapat menyediakan konten berbasis web—seperti HTML, JavaScript, dan CSS—untuk digunakan aplikasi Anda yang dikompilasi secara statis ke dalam aplikasi, bukan diambil melalui internet.
Konten dalam aplikasi tidak memerlukan akses internet atau menghabiskan bandwidth pengguna. Jika
konten didesain khusus untuk WebView
saja—yaitu, bergantung pada komunikasi dengan aplikasi native—pengguna tidak akan dapat memuatnya secara
tidak sengaja di browser web.
Namun, ada beberapa kelemahan dari konten dalam aplikasi. Mengupdate konten berbasis web memerlukan pengiriman update aplikasi baru, dan ada kemungkinan konten yang tidak cocok antara konten yang ada di situs dan yang ada di aplikasi di perangkat Anda jika pengguna memiliki versi aplikasi yang sudah tidak berlaku.
WebViewAssetLoader
WebViewAssetLoader
adalah
cara yang fleksibel dan berperforma tinggi untuk memuat konten dalam aplikasi di
objek WebView
. Class ini mendukung
hal berikut:
- Memuat konten dengan URL HTTP(S) untuk kompatibilitas dengan kebijakan origin yang sama.
- Memuat subresource seperti JavaScript, CSS, gambar, dan iframe.
Sertakan WebViewAssetLoader
dalam file aktivitas utama Anda. Berikut adalah
contoh pemuatan konten web sederhana dari folder aset:
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)); } }
Aplikasi Anda harus mengonfigurasi instance WebViewAssetLoader
agar sesuai dengan kebutuhannya. Bagian
berikutnya memiliki contoh.
Membuat aset dan resource dalam aplikasi
WebViewAssetLoader
bergantung pada instance
PathHandler
untuk memuat resource yang sesuai dengan jalur resource tertentu. Walaupun Anda
dapat menerapkan antarmuka ini untuk mengambil resource sesuai kebutuhan aplikasi,
library Webkit memaketkan
AssetsPathHandler
dan
ResourcesPathHandler
untuk memuat aset dan resource Android.
Untuk memulai, buat aset dan resource untuk aplikasi Anda. Secara umum, hal-hal berikut berlaku:
- File teks seperti HTML, JavaScript, dan CSS termasuk dalam aset.
- Gambar dan file biner lainnya berada dalam resource.
Untuk menambahkan file web berbasis teks ke sebuah project, lakukan hal berikut:
- Di Android Studio, klik kanan folder app > src > main, lalu pilih New > Directory.
- Beri nama folder "assets".
- Klik kanan folder assets, lalu klik New > File.
Masukkan
index.html
, lalu tekan tombol Return atau Enter. - Ulangi langkah sebelumnya untuk membuat file kosong bagi
stylesheet.css
. - Isi file kosong yang Anda buat dengan konten di dua contoh kode berikutnya.
```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;
}
```
Untuk menambahkan file web berbasis gambar ke project Anda, lakukan hal berikut:
Download file
Android_symbol_green_RGB.png
ke komputer lokal Anda.Ganti nama file menjadi
android_robot.png
.Pindahkan file secara manual ke direktori
main/res/drawable
project di hard drive Anda.
Gambar 4 menunjukkan gambar yang Anda tambahkan dan teks dari contoh kode sebelumnya yang dirender dalam aplikasi.
Untuk menyelesaikan aplikasi, lakukan hal berikut:
Daftarkan pengendali dan konfigurasikan
AssetLoader
dengan menambahkan kode berikut ke metodeonCreate()
: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));
Muat konten dengan menambahkan kode berikut ke metode
onCreate()
:Kotlin
webView.loadUrl("https://appassets.androidplatform.net/assets/index.html")
Java
mWebView.loadUrl("https://appassets.androidplatform.net/assets/index.html");
Menggabungkan konten dalam aplikasi dengan referensi dari situs Anda
Aplikasi Anda mungkin perlu memuat campuran konten dalam aplikasi dan konten dari
internet, seperti halaman HTML dalam aplikasi yang diberi gaya oleh CSS situs Anda.
WebViewAssetLoader
mendukung kasus penggunaan ini. Jika tidak ada instance PathHandler
terdaftar yang dapat menemukan resource untuk jalur tertentu, WebView
akan kembali
memuat konten dari internet. Jika Anda menggabungkan konten dalam aplikasi dengan
resource dari situs Anda, cadangkan jalur direktori, seperti /assets/
atau
/resources/
, untuk resource dalam aplikasi. Hindari menyimpan resource apa pun dari
situs Anda di lokasi tersebut.
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);
Lihat demo WebView
di GitHub untuk mengetahui contoh halaman HTML dalam aplikasi yang mengambil data JSON yang dihosting web.
loadDataWithBaseURL
Jika aplikasi Anda hanya perlu memuat halaman HTML dan tidak perlu mencegat
subresource, sebaiknya gunakan
loadDataWithBaseURL()
,
yang tidak memerlukan aset aplikasi. Anda dapat menggunakannya seperti yang ditunjukkan pada contoh kode berikut:
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);
Pilih nilai argumen dengan hati-hati. Pertimbangkan hal berikut:
baseUrl
: ini adalah URL tempat konten HTML Anda dimuat. Ini harus berupa URL HTTP(S).data
: ini adalah konten HTML yang ingin Anda tampilkan sebagai string.mimeType
: ini biasanya harus ditetapkan ketext/html
.encoding
: tidak digunakan jikabaseUrl
adalah URL HTTP(S), sehingga dapat ditetapkan kenull
.historyUrl
: ini ditetapkan ke nilai yang sama denganbaseUrl
.
Sebaiknya gunakan URL HTTP(S) sebagai baseUrl
karena hal ini membantu memastikan aplikasi Anda mematuhi kebijakan origin yang sama.
Jika tidak dapat menemukan baseUrl
yang sesuai untuk konten Anda dan lebih memilih untuk menggunakan
loadData()
,
Anda harus mengenkode konten dengan
encoding persen
atau
encoding Base64.
Sebaiknya pilih encoding Base64 dan gunakan Android API untuk mengenkode
hal ini secara terprogram, seperti ditunjukkan dalam contoh kode berikut:
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");
Hal yang perlu dihindari
Ada beberapa cara lain untuk memuat konten dalam aplikasi, tetapi sebaiknya Anda tidak melakukannya:
- URL
file://
dan URLdata:
dianggap sebagai asal buram, yang berarti URL tersebut tidak dapat memanfaatkan API web yang canggih sepertifetch()
atauXMLHttpRequest
.loadData()
secara internal menggunakan URLdata:
, jadi sebaiknya gunakanWebViewAssetLoader
atauloadDataWithBaseURL()
sebagai gantinya. - Meskipun
WebSettings.setAllowFileAccessFromFileURLs()
danWebSettings.setAllowUniversalAccessFromFileURLs()
dapat mengatasi masalah dengan URLfile://
, sebaiknya jangan menetapkannya ketrue
karena akan membuat aplikasi Anda rentan terhadap eksploitasi berbasis file. Sebaiknya tetapkan setelan ini secara eksplisit kefalse
pada semua API level untuk keamanan terkuat. - Untuk alasan yang sama, sebaiknya jangan gunakan URL
file://android_assets/
danfile://android_res/
. ClassAssetsHandler
danResourcesHandler
dimaksudkan untuk menjadi pengganti langsung. - Hindari penggunaan
MIXED_CONTENT_ALWAYS_ALLOW
. Setelan ini umumnya tidak diperlukan dan melemahkan keamanan aplikasi Anda. Sebaiknya muat konten dalam aplikasi Anda menggunakan skema yang sama—HTTP atau HTTPS—sebagai resource situs Anda dan gunakanMIXED_CONTENT_COMPATIBILITY_MODE
atauMIXED_CONTENT_NEVER_ALLOW
, sebagaimana diperlukan.