Możesz udostępniać w aplikacji treści internetowe (np. HTML, JavaScript i CSS), które są statycznie kompilowane w aplikację, a nie pobierane przez internet.
Treści w aplikacji nie wymagają dostępu do internetu ani nie wykorzystują przepustowości użytkownika. Jeśli treści są przeznaczone tylko dla WebView
(czyli zależą od komunikacji z aplikacją natywną), użytkownicy nie mogą ich przypadkowo wczytać w przeglądarce.
Treści w aplikacji mają jednak pewne wady. Aktualizowanie treści w internecie wymaga przesłania nowej aktualizacji aplikacji. Jeśli użytkownicy mają nieaktualne wersje aplikacji, istnieje ryzyko, że informacje na stronie i w aplikacji na Twoim urządzeniu nie będą się zgadzać.
WebViewAssetLoader
WebViewAssetLoader
to elastyczny i wydajny sposób wczytywania treści w aplikacji do obiektu WebView
. Ta klasa obsługuje:
- Wczytywanie treści z adresem URL HTTP(S) w celu zapewnienia zgodności z zasadą tego samego pochodzenia.
- Wczytywanie zasobów podrzędnych takich jak JavaScript, CSS, obrazy i elementy iframe.
Umieść WebViewAssetLoader
w głównym pliku aktywności. Oto przykład wczytywania prostych treści internetowych z folderu zasobów:
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)); } }
Twoja aplikacja musi skonfigurować instancję WebViewAssetLoader
zgodnie ze swoimi potrzebami. W następnej sekcji znajdziesz przykład.
Tworzenie komponentów i zasobów w aplikacji
WebViewAssetLoader
korzysta z instancji PathHandler
do wczytywania zasobów odpowiadających danej ścieżce zasobu. Możesz wdrożyć ten interfejs, aby pobierać zasoby odpowiednio do potrzeb aplikacji, ale pakiety biblioteki Webkit AssetsPathHandler
i ResourcesPathHandler
służą do wczytywania zasobów i zasobów Androida.
Na początek utwórz zasoby i zasoby swojej aplikacji. Ogólnie obowiązują te zasady:
- Pliki tekstowe, takie jak HTML, JavaScript i CSS, należą do zasobów.
- Obrazy i inne pliki binarne należą do zasobów.
Aby dodać tekstowe pliki internetowe do projektu:
- W Android Studio kliknij prawym przyciskiem myszy folder app > src > main (aplikacja), a następnie wybierz New > Directory (Nowy > Katalog).
- Nazwij folder „assets”.
- Kliknij prawym przyciskiem myszy folder assets, a następnie kliknij Nowy > Plik.
Wpisz
index.html
i naciśnij klawisz Return lub Enter. - Powtórz poprzedni krok, aby utworzyć pusty plik dla
stylesheet.css
. - Wypełnij puste pliki utworzone przez siebie treściami podanymi w następnych 2 przykładach kodu.
```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;
}
```
Aby dodać do projektu plik internetowy oparty na obrazach, wykonaj te czynności:
Pobierz plik
Android_symbol_green_RGB.png
na swój komputer lokalny.Zmień nazwę pliku na
android_robot.png
.Przenieś ręcznie plik do katalogu
main/res/drawable
projektu na dysku twardym.
Rysunek 4 przedstawia dodany obraz i tekst z poprzedniego przykładowego kodu wyrenderowany w aplikacji.
Aby dokończyć proces tworzenia aplikacji, wykonaj te czynności:
Zarejestruj moduły obsługi i skonfiguruj
AssetLoader
, dodając ten kod do metodyonCreate()
: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));
Wczytaj treść, dodając ten kod do metody
onCreate()
:Kotlin
webView.loadUrl("https://appassets.androidplatform.net/assets/index.html")
Java
mWebView.loadUrl("https://appassets.androidplatform.net/assets/index.html");
Połącz treści w aplikacji z zasobami z Twojej strony
Aplikacja może wczytać zarówno treści w aplikacji, jak i treści z internetu, np. stronę HTML w aplikacji stylizowaną na kod CSS witryny.
WebViewAssetLoader
obsługuje ten przypadek użycia. Jeśli żadna z zarejestrowanych instancji PathHandler
nie może znaleźć zasobu na danej ścieżce, WebView
przełącza się na wczytywanie treści z internetu. Jeśli łączysz zawartość aplikacji z zasobami ze swojej witryny, zarezerwuj ścieżki do katalogu, np. /assets/
lub /resources/
, na potrzeby zasobów w aplikacji. Unikaj przechowywania w nich
zasobów ze swojej witryny.
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);
W prezentacji WebView
na GitHubie znajdziesz przykład strony HTML w aplikacji pobierającej dane JSON hostowane przez internet.
loadDataWithBaseURL
Jeśli Twoja aplikacja musi tylko wczytać stronę HTML i nie musi przechwytywać zasobów podrzędnych, możesz użyć metody loadDataWithBaseURL()
, która nie wymaga komponentów z linkiem do aplikacji. Możesz go użyć w sposób przedstawiony w tym przykładowym kodzie:
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);
Wartości argumentów należy dobierać z rozwagą. Weź pod uwagę następujące kwestie:
baseUrl
: to adres URL, pod którym są wczytywane treści HTML. Musi to być adres URL HTTP(S).data
: treść HTML, która ma być wyświetlana w postaci ciągu znaków.mimeType
: zazwyczaj należy ustawić wartośćtext/html
.encoding
: ta wartość nie jest używana, gdybaseUrl
jest adresem URL HTTP(S), więc może mieć wartośćnull
.historyUrl
: ustawiona jest ta sama wartość cobaseUrl
.
Zdecydowanie zalecamy używanie adresu URL HTTP(S) jako adresu baseUrl
, ponieważ pomaga to mieć pewność, że aplikacja jest zgodna z zasadami dotyczącymi tego samego źródła.
Jeśli nie możesz znaleźć odpowiedniego parametru baseUrl
dla swoich treści i wolisz używać loadData()
, musisz zakodować treści za pomocą kodowania procentowego lub standardowego Base64.
Zdecydowanie zalecamy wybór kodowania Base64 i korzystanie z interfejsów API Androida do programowego kodowania, jak pokazano w poniższym przykładzie kodu:
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");
Czego unikać
Istnieje kilka innych sposobów wczytywania treści w aplikacji, ale zdecydowanie zalecamy korzystanie z nich:
- Adresy URL
file://
idata:
są uważane za nieprzejrzyste źródła, co oznacza, że nie można w nich korzystać z zaawansowanych internetowych interfejsów API, takich jakfetch()
czyXMLHttpRequest
. FunkcjaloadData()
wewnętrznie używa adresów URLdata:
, dlatego zalecamy, aby zamiast nich używaćWebViewAssetLoader
lubloadDataWithBaseURL()
. - Chociaż metody
WebSettings.setAllowFileAccessFromFileURLs()
iWebSettings.setAllowUniversalAccessFromFileURLs()
umożliwiają rozwiązanie problemów z adresami URLfile://
, odradzamy ustawianie w tych wartościach wartościtrue
, ponieważ w ten sposób aplikacja może być podatna na wykorzystywanie plików. Aby zapewnić najsilniejsze zabezpieczenia, zalecamy jawne ustawienie ich nafalse
na wszystkich poziomach interfejsu API. - Z tych samych powodów nie zalecamy stosowania adresów URL
file://android_assets/
ifile://android_res/
. KlasyAssetsHandler
iResourcesHandler
powinny być zamiennikami dodawanymi. - Unikaj używania właściwości
MIXED_CONTENT_ALWAYS_ALLOW
. To ustawienie zasadniczo nie jest konieczne i zmniejsza bezpieczeństwo aplikacji. Zalecamy ładowanie treści w aplikacji przy użyciu tego samego schematu (HTTP lub HTTPS) co w przypadku zasobów witryny oraz stosowania odpowiednioMIXED_CONTENT_COMPATIBILITY_MODE
lubMIXED_CONTENT_NEVER_ALLOW
.