Puoi fornire contenuti basati sul web, ad esempio HTML, JavaScript e CSS, da utilizzare per la tua app e che hai compilato in modo statico nell'app anziché recuperarli tramite internet.
I contenuti in-app non richiedono l'accesso a Internet né consumano la larghezza di banda dell'utente. Se i contenuti sono progettati specificamente solo per WebView
, ovvero dipendono dalla comunicazione con un'app nativa, gli utenti non potranno caricarli accidentalmente in un browser web.
Tuttavia, i contenuti in-app presentano alcuni svantaggi. L'aggiornamento di contenuti basati sul web richiede l'invio di un nuovo aggiornamento dell'app ed esiste la possibilità che i contenuti non corrispondano tra i contenuti su un sito web e quelli nell'app sul dispositivo se gli utenti hanno versioni dell'app obsolete.
WebViewAssetLoader
WebViewAssetLoader
è un modo flessibile ed efficace per caricare contenuti in-app in un oggetto WebView
. Questo corso supporta quanto segue:
- Caricamento di contenuti con un URL HTTP(S) per la compatibilità con il criterio same-origin.
- Caricamento di risorse secondarie come JavaScript, CSS, immagini e iframe.
Includi WebViewAssetLoader
nel file delle attività principale. Di seguito è riportato un esempio di caricamento di contenuti web semplici dalla cartella degli asset:
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)); } }
La tua app deve configurare un'istanza WebViewAssetLoader
in base alle sue esigenze. La
sezione successiva contiene un esempio.
Creare asset e risorse in-app
WebViewAssetLoader
si basa sulle istanze
PathHandler
per caricare le risorse corrispondenti a un determinato percorso della risorsa. Sebbene sia possibile implementare questa interfaccia per recuperare le risorse in base alle esigenze della tua app, i bundle della libreria Webkit AssetsPathHandler
e ResourcesPathHandler
per caricare rispettivamente asset e risorse Android.
Per iniziare, crea asset e risorse per la tua app. In genere, si applica quanto segue:
- I file di testo come HTML, JavaScript e CSS appartengono agli asset.
- Le immagini e altri file binari appartengono alle risorse.
Per aggiungere file web basati su testo a un progetto:
- In Android Studio, fai clic con il pulsante destro del mouse sulla cartella app > src > principale, quindi scegli Nuovo > Directory.
- Assegna alla cartella il nome "assets".
- Fai clic con il pulsante destro del mouse sulla cartella assets, quindi fai clic su Nuovo > File.
Inserisci
index.html
e premi il tasto Invio o Invio. - Ripeti il passaggio precedente per creare un file vuoto per
stylesheet.css
. - Compila i file vuoti che hai creato con i contenuti nei prossimi due esempi di codice.
```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;
}
```
Per aggiungere un file web basato su immagini al tuo progetto:
Scarica il file
Android_symbol_green_RGB.png
sulla tua macchina locale.Rinomina il file come
android_robot.png
.Sposta manualmente il file nella directory
main/res/drawable
del progetto sul disco rigido.
La Figura 4 mostra l'immagine che hai aggiunto e il testo degli esempi di codice precedenti visualizzato in un'app.
Per completare l'app:
Registra i gestori e configura
AssetLoader
aggiungendo il seguente codice al metodoonCreate()
: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));
Carica i contenuti aggiungendo il codice seguente al metodo
onCreate()
:Kotlin
webView.loadUrl("https://appassets.androidplatform.net/assets/index.html")
Java
mWebView.loadUrl("https://appassets.androidplatform.net/assets/index.html");
Combina i contenuti in-app con le risorse del tuo sito web
La tua app potrebbe dover caricare una combinazione di contenuti in-app e contenuti da internet, ad esempio una pagina HTML in-app definita dal CSS del tuo sito web.
WebViewAssetLoader
supporta questo caso d'uso. Se nessuna delle istanze PathHandler
registrate riesce a trovare una risorsa per il percorso specificato, WebView
torna a caricare i contenuti da internet. Se combini contenuti in-app con risorse del tuo sito web, prenota percorsi della directory, come /assets/
o /resources/
, per le risorse in-app. Evita di archiviare risorse
del tuo sito web in quelle posizioni.
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);
Consulta la demo di WebView
su GitHub per un esempio di pagina HTML in-app che recupera dati JSON ospitati sul web.
LoadDataWithBaseURL
Se la tua app deve caricare solo una pagina HTML e non deve intercettare
le risorse secondarie, valuta la possibilità di utilizzare
loadDataWithBaseURL()
,
che non richiede asset per app. Puoi utilizzarlo come mostrato nel seguente esempio di codice:
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);
Scegli con attenzione i valori degli argomenti. Tieni in considerazione:
baseUrl
: questo è l'URL con cui vengono caricati i contenuti HTML. Deve essere un URL HTTP(S).data
: si tratta del contenuto HTML che vuoi visualizzare sotto forma di stringa.mimeType
: di solito deve essere impostato sutext/html
.encoding
: non è utilizzato quandobaseUrl
è un URL HTTP(S), quindi può essere impostato sunull
.historyUrl
: è impostato sullo stesso valore dibaseUrl
.
Ti consigliamo vivamente di utilizzare un URL HTTP(S) come baseUrl
, poiché ciò contribuisce a garantire che la tua app rispetti le norme relative alla stessa origine.
Se non riesci a trovare un baseUrl
adatto ai tuoi contenuti e preferisci utilizzare
loadData()
,
devi codificare i contenuti con la
codifica a percentuale
o
la codifica Base64.
Ti consigliamo vivamente di scegliere la codifica Base64 e di utilizzare le API Android per codificarla in modo programmatico, come illustrato nel seguente esempio di codice:
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");
Cose da evitare
Esistono molti altri modi per caricare contenuti in-app, che ti consigliamo vivamente di utilizzare:
- Gli URL
file://
edata:
sono considerati origini opache, ossia non possono usufruire di potenti API web comefetch()
oXMLHttpRequest
.loadData()
utilizza internamentedata:
URL, quindi ti invitiamo a usareWebViewAssetLoader
oloadDataWithBaseURL()
. - Anche se
WebSettings.setAllowFileAccessFromFileURLs()
eWebSettings.setAllowUniversalAccessFromFileURLs()
possono risolvere i problemi relativi agli URLfile://
, ti consigliamo di non impostarli sutrue
perché così facendo la tua app diventa vulnerabile agli exploit basati su file. Ti consigliamo di impostarli esplicitamente sufalse
in tutti i livelli API per la massima sicurezza. - Per gli stessi motivi, sconsigliamo di utilizzare URL
file://android_assets/
efile://android_res/
. Le classiAssetsHandler
eResourcesHandler
sono pensate come sostituzioni automatiche. - Evita di utilizzare
MIXED_CONTENT_ALWAYS_ALLOW
. Questa impostazione generalmente non è necessaria e indebolisce la sicurezza della tua app. Ti consigliamo di caricare i contenuti in-app utilizzando lo stesso schema (HTTP o HTTPS) delle risorse del tuo sito web e di utilizzareMIXED_CONTENT_COMPATIBILITY_MODE
oMIXED_CONTENT_NEVER_ALLOW
, a seconda dei casi.