Criar apps da Web no WebView

Use 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 mostrar páginas da Web como parte do layout da atividade. Ele 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 você 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 um Activity que contenha um WebView e usá-lo para exibir seu documento hospedado on-line.

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

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

Trabalhar com o WebView em versões anteriores do Android

Para usar com segurança os recursos mais recentes do WebView no dispositivo em que o app está executado, adicione a biblioteca AndroidX 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-o ao arquivo build.gradle da seguinte maneira:

Kotlin

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

Groovy

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

Confira o exemplo WebView (em inglês) no GitHub para mais detalhes.

Adicionar uma WebView ao app

Para adicionar uma WebView ao app, você pode incluir o elemento <WebView> no layout da atividade ou definir toda a janela Activity como um WebView em onCreate().

Adicionar uma WebView ao layout da atividade

Para adicionar uma WebView ao app no layout, adicione o seguinte código ao arquivo XML de 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 mostrado no exemplo a seguir:

Kotlin

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

Java

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

Adicionar uma WebView a onCreate()

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

Kotlin

val myWebView = WebView(activityContext)
setContentView(myWebView)

Java

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

Em seguida, carregue a página:

Kotlin

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

Java

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

Ou carregue o URL a partir de uma string HTML:

Kotlin

// 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")

Java

// 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 a permissão INTERNET no arquivo de manifesto, conforme mostrado no exemplo abaixo:

<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. Essa classe também é chamada quando uma WebView precisa de permissão para mudar a interface do app host, por exemplo, para 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 apps da Web.
  • Processar eventos que afetam a renderização de conteúdo, como erros no envio de formulários ou na navegação, usando WebViewClient. Também é possível usar essa subclasse para interceptar o carregamento de URLs.
  • Ative o JavaScript modificando WebSettings.
  • Usar o JavaScript para acessar objetos do framework do Android que você injetou em um WebView.

Usar JavaScript na WebView

Se a página da Web que você quer carregar na WebView usar JavaScript, ative-o para a 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 ativá-lo pelo WebSettings anexado ao WebView. Recupere WebSettings com getSettings() e ative o JavaScript com setJavaScriptEnabled().

Confira este exemplo:

Kotlin

val myWebView: WebView = findViewById(R.id.webview)
myWebView.settings.javaScriptEnabled = true

Java

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

WebSettings fornece acesso a várias outras configurações que podem ser úteis. Por exemplo, se você estiver desenvolvendo um aplicativo da Web projetado especificamente para a WebView no seu app Android, defina uma string personalizada do user agent com setUserAgentString() e consulte o user agent personalizado na página da Web para verificar se o cliente que solicita a página é seu 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 Android, você pode criar interfaces entre o código JavaScript e o código Android do lado do cliente. Por exemplo, o código JavaScript pode chamar um método no código do Android para exibir 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(), transmitindo uma instância de classe para vinculação ao JavaScript e um nome de interface que o JavaScript possa chamar para acessar a classe.

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

Kotlin

/** 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()
    }
}

Java

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();
    }
}

Nesse 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 abaixo:

Kotlin

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

Java

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. Neste ponto, seu aplicativo da Web terá acesso à classe WebAppInterface. Por exemplo, veja abaixo alguns HTML e JavaScript que criam 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. O WebView o disponibiliza automaticamente para sua página da Web. Portanto, 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 inicia um app que processa URLs. Normalmente, o navegador da Web padrão é aberto e carrega o URL de destino. No entanto, é possível substituir esse comportamento para seu WebView para que os links sejam abertos no WebView. Você pode permitir que o usuário navegue para trás e para frente no histórico de páginas da Web mantido pelo WebView.

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

Kotlin

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
    }
}

Java

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:

Kotlin

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

Java

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

Agora, quando o usuário tocar em um link, o sistema chamará 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 retornará "false" e não modificará o carregamento do URL. Permite que o WebView carregue o URL normalmente. Se o host do URL não corresponder, um Intent será criado para iniciar a Activity padrão de processamento de URLs, que será resolvida para o navegador da Web padrão do usuário.

Processar URLs personalizados

O 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(), o WebView vai invocá-los 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>

Os URLs inválidos, como o mostrado no exemplo anterior, são processados de maneira inconsistente em WebView. Portanto, recomendamos usar um URL bem formado. É possível usar um esquema personalizado ou um URL HTTPS para um domínio controlado pela sua organização.

Em vez de usar uma string simples em um link, como no exemplo anterior, você pode usar um esquema personalizado como o seguinte:

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

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

Kotlin

// 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
    }
}

Java

// 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() se destina principalmente a iniciar intents para URLs específicos. Ao implementá-la, retorne false para URLs processados por WebView. No entanto, você não está limitado a iniciar intents. Você pode substituir a inicialização de intents por qualquer comportamento personalizado nos exemplos de código anteriores.

Quando WebView substitui o carregamento do URL, ele acumula automaticamente um histórico de páginas da Web visitadas. É possível navegar para trás e para frente no histórico com goBack() e goForward().

O exemplo abaixo mostra como a Activity pode usar o botão "Voltar" do dispositivo para navegar para trás:

Kotlin

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)
}

Java

@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 ainda mais o snippet anterior:

Kotlin

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

Java

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

O método canGoBack() retornará "true" se houver um histórico de páginas da Web para o usuário acessar. Da mesma forma, você pode usar canGoForward() para verificar se há um histórico de encaminhamento. Se você não realizar essa verificação, goBack() e goForward() não farão nada depois que o usuário chegar ao final do histórico.

Gerenciar mudanças de configuração do dispositivo

Durante o tempo de execução, as mudanças de estado da atividade ocorrem quando a configuração de um dispositivo muda, como 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 nova atividade seja criada, o que também cria um novo objeto WebView que carrega o URL do objeto destruído. Para modificar o comportamento padrão da atividade, você pode mudar a forma como ela processa mudanças de orientation no manifesto. Para saber mais sobre como processar mudanças de configuração durante a execução, leia Gerenciar mudanças de configuração.

Gerenciar janelas

Por padrão, as solicitações para abrir novas janelas são ignoradas. Isso acontece independentemente de eles serem abertos por JavaScript ou pelo atributo de destino em um link. Você pode personalizar o WebChromeClient para fornecer seu próprio comportamento ao abrir várias 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" para setSupportMultipleWindows(), mas não substituir o método onCreateWindow(), de que setSupportMultipleWindows() depende. Essa lógica impede que qualquer página que use target="_blank" nos links seja carregada.