Możesz udostępniać treści internetowe, np. HTML, JavaScript CSS – na potrzeby aplikacji kompilowany statycznie, a nie niż pobieranie przez internet.
Treści w aplikacji nie wymagają dostępu do internetu i nie obciążą łącza użytkownika. Jeśli
treść jest przeznaczona tylko dla usługi WebView
– to znaczy
zależy od komunikacji z aplikacją natywną – wtedy użytkownicy nie mogą
otwórz go w przeglądarce.
Są jednak pewne wady treści znajdujących się w aplikacji. Aktualizowanie treści internetowych wymaga wysłania nowej aktualizacji aplikacji, co może powodować niezgodność między zawartością strony a zawartością aplikacji na urządzeniu że użytkownicy mają nieaktualne wersje aplikacji.
Komponent WebViewAssetLoader
WebViewAssetLoader
to
elastyczny i wydajny sposób ładowania treści w aplikacji
WebView
. Te zajęcia wspierają:
:
- Wczytywanie treści z adresem URL HTTP(S) w celu zapewnienia zgodności z tagiem same-origin .
- Wczytuję zasoby podrzędne, takie jak JavaScript, CSS, obrazy i elementy iframe.
Uwzględnij WebViewAssetLoader
w głównym pliku aktywności. Oto
przykład wczytywania prostej treści internetowej 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
Działanie funkcji WebViewAssetLoader
zależy od
PathHandler
.
w celu wczytywania zasobów odpowiadających danej ścieżce zasobów. Chociaż
może zaimplementować ten interfejs, aby pobierać zasoby zgodnie z potrzebami aplikacji,
Pakiety bibliotek Webkit
AssetsPathHandler
oraz
ResourcesPathHandler
do wczytywania zasobów Androida.
Na początek utwórz zasoby aplikacji. Ogólnie parametr następujące 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, wykonaj te czynności:
- W Android Studio kliknij prawym przyciskiem myszy aplikację > src > folder główny a następnie wybierz Nowy > Katalog.
- Nadaj folderowi nazwę „assets”.
- Kliknij prawym przyciskiem myszy folder assets, a następnie kliknij Nowy > Plik.
Wpisz
index.html
i naciśnij Return lub Enter. - Powtórz poprzedni krok, aby utworzyć pusty plik dla:
stylesheet.css
- Wypełnij puste pliki utworzone przez siebie przy użyciu zawartości następnych 2 kodów przykłady.
```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 z obrazem, wykonaj te czynności:
Pobierz
Android_symbol_green_RGB.png
na komputer lokalny.Zmień nazwę pliku na
android_robot.png
.Przenieś ręcznie plik do katalogu
main/res/drawable
projektu dysku twardego.
Rysunek 4 przedstawia dodany obraz i tekst z poprzednich przykładów kodu renderowanych w aplikacji.
.Aby to zrobić:
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));
Wczytywanie treści przez dodanie tego kodu do metody
onCreate()
:Kotlin
webView.loadUrl("https://appassets.androidplatform.net/assets/index.html")
Java
mWebView.loadUrl("https://appassets.androidplatform.net/assets/index.html");
Łączenie treści w aplikacji z zasobami ze swojej strony internetowej
Być może aplikacja będzie musiała wczytać zarówno zawartość aplikacji, jak i zawartość
np. strona HTML w aplikacji stylizowana na kod CSS Twojej witryny.
WebViewAssetLoader
obsługuje ten przypadek użycia. Jeśli żadna z zarejestrowanych
Liczba instancji, które mogą znaleźć zasób dla określonej ścieżki (PathHandler
), wynosi WebView
do wczytywania treści z internetu. Jeśli połączysz zawartość aplikacji z
zasobów z witryny, zarezerwuj ścieżki do katalogów, np. /assets/
lub
/resources/
na zasoby w aplikacji. Unikaj przechowywania zasobów z
witrynę w tych lokalizacjach.
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);
Zobacz wersję demonstracyjną WebView
w
GitHub
znajdziesz przykład strony HTML w aplikacji, która pobiera dane JSON hostowane w internecie.
loadDataWithBaseURL
Gdy aplikacja musi wczytywać tylko stronę HTML i nie musi przechwytywać
zasobów podrzędnych, rozważ użycie
loadDataWithBaseURL()
które nie wymagają komponentów z linkiem do aplikacji. Można go użyć w sposób pokazany w poniższym kodzie
przykład:
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 dobieraj z rozwagą. Weź pod uwagę następujące kwestie:
baseUrl
: adres URL, pod którym są ładowane treści HTML. Musi to być Adres URL HTTP(S).data
: zawartość HTML, którą chcesz wyświetlić w formie ciągu znaków.mimeType
: zwykle należy ustawić wartośćtext/html
.encoding
: ten element nie jest używany, gdybaseUrl
to adres URL HTTP(S), więc może być ustawiono nanull
.historyUrl
: ustawiona jest taka sama wartość jakbaseUrl
.
Zdecydowanie zalecamy użycie adresu URL HTTP(S) w roli baseUrl
, ponieważ pomaga to
sprawdź, czy Twoja aplikacja jest zgodna z zasadami dotyczącymi tej samej domeny.
Jeśli nie możesz znaleźć odpowiedniego pola baseUrl
dla swoich treści i wolisz użyć
loadData()
,
musisz zakodować treść za pomocą parametru
kodowanie procentowe
lub
Base64
.
Zdecydowanie zalecamy kodowanie Base64 i kodowanie interfejsów API Androida
to automatycznie, jak pokazujemy w tym przykładowym kodzie:
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 warto unikać
Treści można wczytywać w aplikacji na kilka innych sposobów, ale zdecydowanie zalecamy przeciwko nim:
- Adresy URL typu
file://
i adresy URL (data:
) są uznawane za nieprzejrzyste źródła, co oznacza, że nie mogą korzystać z zaawansowanych interfejsów API, takich jakfetch()
lubXMLHttpRequest
.loadData()
używa wewnętrzniedata:
adresów URL, dlatego zachęcamy do stosowaniaWebViewAssetLoader
lubloadDataWithBaseURL()
. - Chociaż
WebSettings.setAllowFileAccessFromFileURLs()
orazWebSettings.setAllowUniversalAccessFromFileURLs()
możesz obejść problemy z adresami URLfile://
, odradzamy ustawianie natrue
, ponieważ zwiększa to podatność aplikacji na ataki wykorzystujące luki w zabezpieczeniach. Zalecamy bezpośrednie ustawienie wartościfalse
na wszystkich poziomach interfejsu API . - Z tych samych powodów odradzamy korzystanie z tagów
file://android_assets/
orazfile://android_res/
adresy URL.AssetsHandler
iResourcesHandler
klasy są zwykłymi zamiennikami. - Unikaj stosowania
MIXED_CONTENT_ALWAYS_ALLOW
To ustawienie zwykle nie jest konieczne i zmniejsza bezpieczeństwo aplikacji. Zalecamy ładowanie treści w aplikacji, korzystając z tego samego schematu – HTTP lub HTTPS – jako zasoby witrynyMIXED_CONTENT_COMPATIBILITY_MODE
lubMIXED_CONTENT_NEVER_ALLOW
, w razie potrzeby.