É possível fornecer ao seu app conteúdo baseado na Web, como HTML, JavaScript e CSS, que você compila estaticamente no app em vez de buscar na Internet.
O conteúdo no app não precisa de acesso à Internet nem consome a largura de banda do usuário. Se
o conteúdo for projetado especificamente para WebView
, ou seja,
depender da comunicação com um app nativo, os usuários não poderão carregá-lo
acidentalmente em um navegador da Web.
No entanto, o conteúdo no app tem algumas desvantagens. Atualizar o conteúdo baseado na Web exige o envio de uma nova atualização do app. Além disso, existe a possibilidade de conteúdo incompatível entre o que está em um site e o que está no app no dispositivo, caso os usuários tenham versões desatualizadas do app.
WebViewAssetLoader
WebViewAssetLoader
é uma
maneira flexível e com alto desempenho de carregar conteúdo no app em um
objeto WebView
. Essa classe é compatível com o
seguinte:
- Carregar conteúdo com um URL HTTP(S) para compatibilidade com a política de mesma origem.
- Carregando sub-recursos, como JavaScript, CSS, imagens e iframes.
Inclua WebViewAssetLoader
no seu arquivo de atividade principal. Confira a seguir um
exemplo de carregamento de conteúdo simples da Web da pasta de recursos:
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)); } }
Seu app precisa configurar uma instância de WebViewAssetLoader
para atender às necessidades. A próxima seção tem um exemplo.
Criar recursos no app
WebViewAssetLoader
depende de instâncias
PathHandler
para carregar recursos correspondentes a um determinado caminho de recurso. Embora você
possa implementar essa interface para extrair recursos conforme necessário pelo app, mas a
biblioteca Webkit agrupa
AssetsPathHandler
e
ResourcesPathHandler
para carregar recursos e recursos Android, respectivamente.
Para começar, crie recursos para o app. Geralmente, o seguinte se aplica:
- Arquivos de texto como HTML, JavaScript e CSS pertencem aos recursos.
- As imagens e outros arquivos binários pertencem aos recursos.
Para adicionar arquivos da Web baseados em texto a um projeto, faça o seguinte:
- No Android Studio, clique com o botão direito do mouse na pasta app > src > main e escolha New > Directory.
- Nomeie a pasta como "Recursos".
- Clique com o botão direito do mouse na pasta assets e depois em Novo > Arquivo.
Digite
index.html
e pressione a tecla Return ou Enter. - Repita a etapa anterior para criar um arquivo vazio para a
stylesheet.css
. - Preencha os arquivos vazios que você criou com o conteúdo nos próximos dois exemplos de código.
```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;
}
```
Para adicionar um arquivo da Web baseado em imagem ao projeto, faça o seguinte:
Faça o download do arquivo
Android_symbol_green_RGB.png
para sua máquina local.Renomeie o arquivo como
android_robot.png
.Mova manualmente o arquivo para o diretório
main/res/drawable
do projeto no seu disco rígido.
A Figura 4 mostra a imagem que você adicionou e o texto dos exemplos de código anteriores renderizados em um app.
Para concluir o app, faça o seguinte:
Registre os gerenciadores e configure o
AssetLoader
adicionando o seguinte código ao métodoonCreate()
: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));
Carregue o conteúdo adicionando o seguinte código ao método
onCreate()
:Kotlin
webView.loadUrl("https://appassets.androidplatform.net/assets/index.html")
Java
mWebView.loadUrl("https://appassets.androidplatform.net/assets/index.html");
Combine o conteúdo no app com os recursos do seu site
Talvez o app precise carregar uma combinação de conteúdo dele e da
Internet, como uma página HTML no app estilizada pelo CSS do site.
WebViewAssetLoader
oferece suporte a esse caso de uso. Se nenhuma das instâncias
PathHandler
registradas conseguir encontrar um recurso para o caminho especificado, WebView
vai
voltar ao carregamento de conteúdo da Internet. Se você misturar conteúdo no app com
recursos do seu site, reserve caminhos de diretório, como /assets/
ou
/resources/
, para recursos no app. Evite armazenar recursos do
site nesses locais.
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);
Confira a demonstração de WebView
no GitHub (em inglês) para um exemplo de uma página HTML no app que busca dados JSON hospedados na Web.
loadDataWithBaseURL
Quando o app só precisa carregar uma página HTML e não precisa interceptar
subrecursos, use o
loadDataWithBaseURL()
,
que não requer recursos de app. Você pode usá-lo conforme mostrado neste exemplo
de código:
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);
Escolha os valores do argumento com cuidado. Considere o seguinte:
baseUrl
: é o URL para o qual seu conteúdo HTML é carregado. Precisa ser um URL HTTP(S).data
: é o conteúdo HTML que você quer mostrar, como uma string.mimeType
: geralmente precisa ser definido comotext/html
.encoding
: não é utilizado quandobaseUrl
é um URL HTTP(S). Portanto, ele pode ser definido comonull
.historyUrl
: definido como o mesmo valor quebaseUrl
.
Recomendamos usar um URL HTTP(S) como baseUrl
. Isso ajuda
a garantir que seu app obedeça à política de mesma origem.
Se você não encontrar um baseUrl
adequado para seu conteúdo e preferir usar
loadData()
,
codifique o conteúdo com
codificação por cento
ou
codificação em Base64.
É altamente recomendável escolher a codificação Base64 e usar APIs do Android para codificar
isso de forma programática, conforme mostrado neste exemplo de código:
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");
O que deve ser evitado
Há várias outras maneiras de carregar conteúdo no app, mas recomendamos que você faça isso:
- Os URLs
file://
edata:
são considerados origens opacas, o que significa que não podem aproveitar APIs eficientes da Web, comofetch()
ouXMLHttpRequest
. AloadData()
usa URLsdata:
internamente. Portanto, recomendamos o uso deWebViewAssetLoader
ouloadDataWithBaseURL()
. - Embora
WebSettings.setAllowFileAccessFromFileURLs()
eWebSettings.setAllowUniversalAccessFromFileURLs()
possam contornar os problemas com URLsfile://
, recomendamos não defini-los comotrue
porque isso deixa seu app vulnerável a explorações baseadas em arquivos. Recomendamos defini-las explicitamente comofalse
em todos os níveis da API para ter mais segurança. - Pelos mesmos motivos, recomendamos não usar URLs
file://android_assets/
efile://android_res/
. As classesAssetsHandler
eResourcesHandler
devem ser substituições simples. - Evite usar
MIXED_CONTENT_ALWAYS_ALLOW
. Em geral, essa configuração não é necessária e enfraquece a segurança do seu app. Recomendamos carregar o conteúdo do app no mesmo esquema (HTTP ou HTTPS) dos recursos do seu site e usarMIXED_CONTENT_COMPATIBILITY_MODE
ouMIXED_CONTENT_NEVER_ALLOW
, conforme apropriado.