Criar apps da Web no WebView

Usar WebView para entregar um aplicativo da Web ou uma página da Web como parte de um aplicativo cliente. A classe WebView é uma extensão da classe View do Android que permite você exibe páginas da Web como parte do layout da sua atividade. Ela não inclui os recursos de um navegador da Web totalmente desenvolvido, como controles de navegação ou uma barra de endereço. Todo o WebView mostra, por padrão, uma página da Web.

O WebView pode ajudar a fornecer informações no app que talvez precisem ser atualizadas, como um contrato de usuário final ou um guia do usuário. No app Android, você pode criar uma Activity que contenha uma WebView e usá-la para mostrar o documento hospedado on-line.

A WebView também pode ajudar quando o app fornece dados ao usuário que exigem uma conexão de Internet para recuperar dados, como e-mails. Nesse caso, pode ser mais fácil criar no seu app para Android uma WebView que mostre uma página da Web com todos os dados do usuário em vez de executar uma solicitação de rede, analisar os dados e renderizá-los em um layout do Android. Em vez disso, você pode projetar uma página web personalizada para dispositivos com tecnologia Android e, em seguida, implementar uma WebView no seu app Android que carrega a página da Web.

Este documento descreve como começar a usar a WebView, como vincular o JavaScript da página da Web ao código do cliente no app Android, como gerenciar a navegação de páginas e como gerenciar janelas ao usar a WebView.

Trabalhar com o WebView em versões anteriores do Android

Para usar com segurança recursos mais recentes do WebView no dispositivo em que seu app está em execução, adicione a extensão AndroidX do Webkit. Essa é uma biblioteca estática que pode ser adicionada ao aplicativo para usar APIs android.webkit que não estão disponíveis para versões anteriores da plataforma.

Adicione ao arquivo build.gradle da seguinte maneira:

dependencies {
    implementation("androidx.webkit:webkit:1.8.0")
}
dependencies {
    implementation ("androidx.webkit:webkit:1.8.0")
}

Conheça o WebView exemplo no GitHub para mais detalhes.

Adicionar uma WebView ao app

Para adicionar um WebView ao app, inclua o elemento <WebView> no seu o layout da atividade ou defina toda a janela Activity como um WebView em onCreate()

Adicionar uma WebView no layout da atividade

Para adicionar uma WebView ao app no layout, adicione o seguinte código ao arquivo XML do layout da atividade:

<WebView
    android:id="@+id/webview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
/>

Para carregar uma página da Web no WebView, use loadUrl(), conforme como mostrado no exemplo a seguir:

val myWebView: WebView = findViewById(R.id.webview)
myWebView.loadUrl("http://www.example.com")
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.loadUrl("http://www.example.com");

Adicionar uma WebView em onCreate()

Para adicionar uma WebView ao app no método onCreate() de uma atividade, use uma lógica semelhante a esta:

val myWebView = WebView(activityContext)
setContentView(myWebView)
WebView myWebView = new WebView(activityContext);
setContentView(myWebView);

Em seguida, carregue a página:

myWebView.loadUrl("http://www.example.com")
myWebView.loadUrl("https://www.example.com");

Ou carregue o URL a partir de uma string HTML:

// Create an unencoded HTML string, then convert the unencoded HTML string into
// bytes. Encode it with base64 and load the data.
val unencodedHtml =
     "<html><body>'%23' is the percent code for ‘#‘ </body></html>";
val encodedHtml = Base64.encodeToString(unencodedHtml.toByteArray(), Base64.NO_PADDING)
myWebView.loadData(encodedHtml, "text/html", "base64")
// Create an unencoded HTML string, then convert the unencoded HTML string into
// bytes. Encode it with base64 and load the data.
String unencodedHtml =
     "<html><body>'%23' is the percent code for ‘#‘ </body></html>";
String encodedHtml = Base64.encodeToString(unencodedHtml.getBytes(),
        Base64.NO_PADDING);
myWebView.loadData(encodedHtml, "text/html", "base64");

O app precisa ter acesso à Internet. Para ter acesso à Internet, solicite o Permissão INTERNET em seu de manifesto do aplicativo, como mostrado no exemplo a seguir:

<manifest ... >
    <uses-permission android:name="android.permission.INTERNET" />
    ...
</manifest>

Para personalizar o WebView, siga um destes procedimentos:

  • Ativando o suporte a tela cheia usando WebChromeClient. Esta turma também é chamado quando uma WebView precisa de permissão para mudar a interface do app host. como criar ou fechar janelas ou enviar caixas de diálogo JavaScript ao usuário. Para saber mais sobre a depuração nesse contexto, leia Depurar a Web apps.
  • Tratamento de eventos que afetam a renderização de conteúdo, como erros no formulário envios ou navegação usando WebViewClient Você também pode usar essa subclasse para interceptar o carregamento do URL.
  • Ativar o JavaScript modificando WebSettings
  • Usando o JavaScript para acessar objetos do framework do Android que foram injetados em uma WebView.

Usar JavaScript na WebView

Se a página da Web que você quer carregar no WebView usar JavaScript, será preciso ativar o JavaScript para o WebView. Depois de ativar o JavaScript, você pode criar interfaces entre o código do app e o código JavaScript.

Ativar o JavaScript

Por padrão, o JavaScript fica desativado em uma WebView. É possível ativar esse recurso usando o WebSettings anexado ao WebView. Recuperar WebSettings com getSettings() e ative JavaScript com setJavaScriptEnabled()

Confira este exemplo:

val myWebView: WebView = findViewById(R.id.webview)
myWebView.settings.javaScriptEnabled = true
WebView myWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);

A WebSettings fornece acesso a uma variedade de outras configurações que podem ser úteis. Por exemplo, se você estiver desenvolvendo um aplicativo da Web projetado especificamente para o WebView no seu app Android, poderá definir uma string de agente do usuário personalizada com setUserAgentString(). Em seguida, consulte o agente do usuário personalizado na página da Web para verificar se o cliente que está solicitando a página é o app Android.

Vincular o código JavaScript ao código do Android

Ao desenvolver um aplicativo da Web projetado especificamente para a WebView no seu app para Android, você pode criar interfaces entre o código JavaScript e o código do Android do lado do cliente. Por exemplo, seu código JavaScript pode chamar um método no código do Android para mostrar uma Dialog, em vez de usar a função alert() do JavaScript.

Para vincular uma nova interface entre o código JavaScript e do Android, chame addJavascriptInterface(), passando uma instância de classe para vincular ao JavaScript e um nome de interface que o JavaScript pode chamar para acessar a classe.

Por exemplo, você pode incluir a seguinte classe no app para Android:

/** Instantiate the interface and set the context.  */
class WebAppInterface(private val mContext: Context) {

    /** Show a toast from the web page.  */
    @JavascriptInterface
    fun showToast(toast: String) {
        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show()
    }
}
public class WebAppInterface {
    Context mContext;

    /** Instantiate the interface and set the context. */
    WebAppInterface(Context c) {
        mContext = c;
    }

    /** Show a toast from the web page. */
    @JavascriptInterface
    public void showToast(String toast) {
        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
    }
}

Neste exemplo, a classe WebAppInterface permite que a página da Web crie uma mensagem Toast usando o método showToast().

Você pode vincular essa classe ao JavaScript executado no WebView com addJavascriptInterface(), conforme mostrado no exemplo a seguir:

val webView: WebView = findViewById(R.id.webview)
webView.addJavascriptInterface(WebAppInterface(this), "Android")
WebView webView = (WebView) findViewById(R.id.webview);
webView.addJavascriptInterface(new WebAppInterface(this), "Android");

Isso cria uma interface chamada Android para o JavaScript em execução no WebView. Nesse ponto, seu aplicativo da Web terá acesso à classe WebAppInterface. Por exemplo, aqui estão alguns códigos HTML e JavaScript cria uma mensagem de aviso usando a nova interface quando o usuário toca em um botão:

<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />

<script type="text/javascript">
    function showAndroidToast(toast) {
        Android.showToast(toast);
    }
</script>

Não é necessário inicializar a interface Android do JavaScript. A WebView disponibiliza a interface automaticamente para a página da Web. Assim, quando um usuário toca no botão, a função showAndroidToast() usa a interface Android para chamar o método WebAppInterface.showToast().

Gerenciar a navegação nas páginas

Quando o usuário toca em um link de uma página da Web no WebView, por padrão, o Android inicializa um aplicativo que lida com URLs. Normalmente, o navegador da Web padrão abre e carrega o URL de destino. No entanto, você pode modificar esse comportamento para sua WebView e fazer com que os links sejam abertos na WebView. Você pode permitir que o usuário navegar para trás e para frente pelo histórico da página da Web que é mantido pelo seu WebView.

Para abrir os links tocados pelo usuário, forneça um WebViewClient para o WebView usando setWebViewClient(). Todos os links em que o usuário tocar serão carregados na WebView. Se quiser ter mais controle sobre onde um link clicado será carregado, crie seu próprio WebViewClient, que modifica o método shouldOverrideUrlLoading(). O exemplo a seguir pressupõe que MyWebViewClient é uma classe interna de Activity.

private class MyWebViewClient : WebViewClient() {

    override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
        if (Uri.parse(url).host == "www.example.com") {
            // This is your website, so don't override. Let your WebView load
            // the page.
            return false
        }
        // Otherwise, the link isn't for a page on your site, so launch another
        // Activity that handles URLs.
        Intent(Intent.ACTION_VIEW, Uri.parse(url)).apply {
            startActivity(this)
        }
        return true
    }
}
private class MyWebViewClient extends WebViewClient {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
        if ("www.example.com".equals(request.getUrl().getHost())) {
      // This is your website, so don't override. Let your WebView load the
      // page.
      return false;
    }
    // Otherwise, the link isn't for a page on your site, so launch another
    // Activity that handles URLs.
    Intent intent = new Intent(Intent.ACTION_VIEW, request.getUrl());
    startActivity(intent);
    return true;
  }
}

Em seguida, crie uma instância desse novo WebViewClient para a WebView:

val myWebView: WebView = findViewById(R.id.webview)
myWebView.webViewClient = MyWebViewClient()
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new MyWebViewClient());

Agora, quando o usuário toca em um link, o sistema chama o método shouldOverrideUrlLoading(), que verifica se o host do URL corresponde a um domínio específico, conforme definido no exemplo anterior. Se houver correspondência, o método retorna falso e não substitui o carregamento do URL. Ela permite que WebView carrega o URL normalmente. Se o host do URL não for correspondente, um Intent será criado para iniciar o Activity padrão para processar URLs, que é resolvido no navegador da Web padrão do usuário.

Processar URLs personalizados

WebView aplica restrições ao solicitar recursos e resolver links que usam um esquema de URL personalizado. Por exemplo, se você implementar callbacks como shouldOverrideUrlLoading() ou shouldInterceptRequest(), WebView os invocará apenas para URLs válidos.

Por exemplo, WebView pode não chamar seu método shouldOverrideUrlLoading() para links como este:

<a href="showProfile">Show Profile</a>

URLs inválidos, como o mostrado no exemplo anterior, são processados de forma inconsistente em WebView. Por isso, recomendamos usar um URL bem formado. É possível usar um esquema personalizado ou um URL HTTPS para um domínio que sua organização controles de segurança.

Em vez de usar uma string simples em um link, como no exemplo anterior, é possível use um esquema personalizado como o seguinte:

<a href="example-app:showProfile">Show Profile</a>

Em seguida, você pode gerenciar esse URL no método shouldOverrideUrlLoading() desta forma:

// The URL scheme must be non-hierarchical, meaning no trailing slashes.
const val APP_SCHEME = "example-app:"

override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
    return if (url?.startsWith(APP_SCHEME) == true) {
        urlData = URLDecoder.decode(url.substring(APP_SCHEME.length), "UTF-8")
        respondToData(urlData)
        true
    } else {
        false
    }
}
// The URL scheme must be non-hierarchical, meaning no trailing slashes.
private static final String APP_SCHEME = "example-app:";

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    if (url.startsWith(APP_SCHEME)) {
        urlData = URLDecoder.decode(url.substring(APP_SCHEME.length()), "UTF-8");
        respondToData(urlData);
        return true;
    }
    return false;
}

A API shouldOverrideUrlLoading() é destinada principalmente a iniciar intents para URLs específicos. Ao implementá-la, retorne false para URLs que o WebView processa. No entanto, você não está limitado a iniciar intents. Você pode substituir a inicialização de intents por qualquer comportamento personalizado no código anterior; de amostra.

Quando a WebView modifica o carregamento do URL, ela acumula automaticamente um histórico de páginas da Web visitadas. Você pode voltar e avançar na histórico com o goBack() e goForward()

Por exemplo, o exemplo a seguir mostra como a Activity pode usar o botão "Voltar" do dispositivo para navegar para itens anteriores do histórico:

override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
    // Check whether the key event is the Back button and if there's history.
    if (keyCode == KeyEvent.KEYCODE_BACK && myWebView.canGoBack()) {
        myWebView.goBack()
        return true
    }
    // If it isn't the Back button or there isn't web page history, bubble up to
    // the default system behavior. Probably exit the activity.
    return super.onKeyDown(keyCode, event)
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    // Check whether the key event is the Back button and if there's history.
    if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) {
        myWebView.goBack();
        return true;
    }
    // If it isn't the Back button or there's no web page history, bubble up to
    // the default system behavior. Probably exit the activity.
    return super.onKeyDown(keyCode, event);
}

Se o app usa o AndroidX AppCompat 1.6.0 ou mais recente, é possível simplificar a versão anterior snippet ainda mais:

onBackPressedDispatcher.addCallback {
    // Check whether there's history.
    if (myWebView.canGoBack()) {
        myWebView.goBack()
    }
}
onBackPressedDispatcher.addCallback {
    // Check whether there's history.
    if (myWebView.canGoBack()) {
        myWebView.goBack();
    }
}

O método canGoBack() retorna verdadeiro se houver um histórico da página da Web para o usuário visitar. Da mesma forma, você pode usar canGoForward() para verificar se há um histórico de avanço. Se você não fizer essa verificação, depois que o usuário chega ao fim do histórico, goBack() e goForward() fazem nada.

Gerenciar mudanças de configuração do dispositivo

Durante a execução, mudanças no estado da atividade ocorrem quando a configuração de um dispositivo é modificada. Por exemplo, quando os usuários giram o dispositivo ou dispensam um editor de método de entrada (IME). Essas mudanças fazem com que a atividade de um objeto WebView seja destruída e uma uma nova atividade a ser criada, o que também cria um novo objeto WebView que é carregado o URL do objeto destruído. Para modificar o comportamento padrão da atividade, mude a forma como ela gerencia mudanças de orientation no manifesto. Para saber mais sobre como lidar com mudanças de configuração durante o tempo de execução, leia Processar configurações mudanças.

Gerenciar janelas

Por padrão, as solicitações para abrir novas janelas são ignoradas. Isso acontece independentemente de serem abertas por JavaScript ou pelo atributo desejado de um link. Você pode personalizar WebChromeClient para fornecer seu próprio comportamento ao abrir vários janelas.

Para manter seu app mais seguro, é melhor evitar que pop-ups e novas janelas sejam abertos. A maneira mais segura de implementar esse comportamento é transmitir "true" ao setSupportMultipleWindows() mas sem substituir o onCreateWindow() do qual setSupportMultipleWindows() depende. Essa lógica impede que qualquer página que use target="_blank" nos links seja carregada.