Sie können webbasierte Inhalte wie HTML, JavaScript und CSS bereitstellen, damit Ihre Anwendung diese statisch in die App kompiliert, anstatt sie über das Internet abzurufen.
Für In-App-Inhalte ist kein Internetzugriff erforderlich und es wird keine Bandbreite in Anspruch genommen. Wenn die Inhalte speziell für WebView
entwickelt wurden – das heißt, dass sie von der Kommunikation mit einer nativen App abhängig sind –, können Nutzer sie nicht versehentlich in einem Webbrowser laden.
In-App-Inhalte haben jedoch auch Nachteile. Wenn du webbasierte Inhalte aktualisieren möchtest, musst du ein neues App-Update veröffentlichen. Außerdem besteht die Möglichkeit, dass Inhalte auf einer Website und in der App auf deinem Gerät nicht übereinstimmen, wenn Nutzer veraltete App-Versionen haben.
WebViewAssetLoader
WebViewAssetLoader
ist eine flexible und leistungsfähige Möglichkeit, In-App-Inhalte in ein WebView
-Objekt zu laden. Diese Klasse unterstützt Folgendes:
- Laden von Inhalten mit einer HTTP(S)-URL aus Gründen der Kompatibilität mit der Same-Origin-Policy.
- Laden von untergeordneten Ressourcen wie JavaScript, CSS, Bildern und iFrames
Füge WebViewAssetLoader
in deine Hauptaktivitätsdatei ein. Im Folgenden finden Sie ein Beispiel für das Laden einfacher Webinhalte aus dem Ordner „Assets“:
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)); } }
Ihre Anwendung muss entsprechend ihren Anforderungen eine WebViewAssetLoader
-Instanz konfigurieren. Der nächste Abschnitt enthält ein Beispiel.
In-App-Assets und -Ressourcen erstellen
WebViewAssetLoader
benötigt PathHandler
-Instanzen, um Ressourcen zu laden, die einem bestimmten Ressourcenpfad entsprechen. Sie können diese Schnittstelle zwar implementieren, um Ressourcen nach Bedarf für Ihre App abzurufen, aber die Webkit-Bibliothek Bundles AssetsPathHandler
und ResourcesPathHandler
zum Laden von Android-Assets bzw. -Ressourcen.
Erstellen Sie zuerst Assets und Ressourcen für Ihre Anwendung. Im Allgemeinen gilt Folgendes:
- Textdateien wie HTML, JavaScript und CSS gehören zu Assets.
- Bilder und andere Binärdateien gehören in die Ressourcen.
So fügen Sie einem Projekt textbasierte Webdateien hinzu:
- Klicken Sie in Android Studio mit der rechten Maustaste auf den Ordner app > src > main und wählen Sie New > Directory aus.
- Nennen Sie den Ordner „Assets“.
- Klicken Sie mit der rechten Maustaste auf den Ordner Assets und dann auf Neu > Datei.
Geben Sie
index.html
ein und drücken Sie die Eingabetaste oder die Eingabetaste. - Wiederholen Sie den vorherigen Schritt, um eine leere Datei für
stylesheet.css
zu erstellen. - Füllen Sie die leeren Dateien, die Sie erstellt haben, mit den Inhalten aus den nächsten beiden Codebeispielen aus.
```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;
}
```
So fügen Sie Ihrem Projekt eine bildbasierte Webdatei hinzu:
Laden Sie die Datei
Android_symbol_green_RGB.png
auf Ihren lokalen Computer herunter.Benennen Sie die Datei in
android_robot.png
um.Verschieben Sie die Datei manuell in das
main/res/drawable
-Verzeichnis Ihres Projekts auf Ihrer Festplatte.
Abbildung 4 zeigt das von Ihnen hinzugefügte Bild und den Text aus den vorherigen Codebeispielen, der in einer App gerendert wurde.
So stellen Sie die App fertig:
Registrieren Sie die Handler und konfigurieren Sie
AssetLoader
, indem Sie der MethodeonCreate()
den folgenden Code hinzufügen: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));
Laden Sie den Inhalt, indem Sie der Methode
onCreate()
den folgenden Code hinzufügen:Kotlin
webView.loadUrl("https://appassets.androidplatform.net/assets/index.html")
Java
mWebView.loadUrl("https://appassets.androidplatform.net/assets/index.html");
In-App-Inhalte mit Ressourcen von Ihrer Website kombinieren
Ihre App muss möglicherweise eine Mischung aus In-App-Inhalten und Inhalten aus dem Internet laden, z. B. eine In-App-HTML-Seite, die mit dem CSS Ihrer Website gestaltet wurde.
WebViewAssetLoader
unterstützt diesen Anwendungsfall. Wenn keine der registrierten PathHandler
-Instanzen eine Ressource für den angegebenen Pfad finden kann, greift WebView
auf das Laden von Inhalten aus dem Internet zurück. Wenn Sie In-App-Inhalte mit Ressourcen von Ihrer Website mischen, reservieren Sie Verzeichnispfade wie /assets/
oder /resources/
für In-App-Ressourcen. Speichern Sie an diesen Orten keine Ressourcen von Ihrer Website.
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);
In der WebView
-Demo auf GitHub finden Sie ein Beispiel für eine In-App-HTML-Seite, die im Web gehostete JSON-Daten abruft.
LoadDataWithBaseURL
Wenn Ihre Anwendung nur eine HTML-Seite laden und keine Unterressourcen abfangen muss, sollten Sie loadDataWithBaseURL()
verwenden, für das keine App-Assets erforderlich sind. Sie können es wie im folgenden Codebeispiel gezeigt verwenden:
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);
Wählen Sie Argumentwerte sorgfältig aus. Hier einige Tipps:
baseUrl
: Das ist die URL, unter der Ihre HTML-Inhalte geladen werden. Dies muss eine HTTP(S)-URL sein.data
: Dies ist der HTML-Inhalt, der als String angezeigt werden soll.mimeType
: Muss normalerweise auftext/html
festgelegt werden.encoding
: Wird nicht verwendet, wennbaseUrl
eine HTTP(S)-URL ist, kann sie also aufnull
festgelegt werden.historyUrl
: Wird auf denselben Wert wiebaseUrl
festgelegt.
Wir empfehlen dringend, eine HTTP(S)-URL als baseUrl
zu verwenden, damit Ihre App der Richtlinie für denselben Ursprung entspricht.
Wenn Sie keinen geeigneten baseUrl
für Ihren Inhalt finden und lieber loadData()
verwenden möchten, müssen Sie den Inhalt mit Prozentcodierung oder Base64-Codierung codieren.
Wir empfehlen dringend, die Base64-Codierung zu wählen und Android APIs zu verwenden, um dies programmatisch zu codieren, wie im folgenden Codebeispiel gezeigt:
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");
Was du vermeiden solltest
Es gibt mehrere andere Möglichkeiten, In-App-Inhalte zu laden, die wir Ihnen jedoch ausdrücklich empfehlen:
file://
-URLs unddata:
-URLs gelten als opake Ursprünge, d. h. sie können keine leistungsstarken Web-APIs wiefetch()
oderXMLHttpRequest
nutzen.loadData()
verwendet interndata:
-URLs. Wir empfehlen daher, stattdessenWebViewAssetLoader
oderloadDataWithBaseURL()
zu verwenden.- Obwohl
WebSettings.setAllowFileAccessFromFileURLs()
undWebSettings.setAllowUniversalAccessFromFileURLs()
Probleme mitfile://
-URLs umgehen können, raten wir davon ab, sie auftrue
zu setzen, da Ihre Anwendung dann anfällig für dateibasierte Exploits wird. Für höchste Sicherheit empfehlen wir, sie auf allen API-Ebenen explizit auffalse
festzulegen. - Aus denselben Gründen raten wir von
file://android_assets/
- undfile://android_res/
-URLs ab. Die KlassenAssetsHandler
undResourcesHandler
sind als Drop-in-Ersatzwerte gedacht. - Vermeiden Sie die Verwendung von
MIXED_CONTENT_ALWAYS_ALLOW
. Diese Einstellung ist in der Regel nicht erforderlich und beeinträchtigt die Sicherheit Ihrer App. Wir empfehlen, Ihre In-App-Inhalte über das gleiche Schema (HTTP oder HTTPS) wie die Ressourcen Ihrer Website zu laden und je nach BedarfMIXED_CONTENT_COMPATIBILITY_MODE
oderMIXED_CONTENT_NEVER_ALLOW
zu verwenden.