Crea app web in WebView

Utilizza WebView per pubblicare un'applicazione web o una pagina web come parte di un'app client. La classe WebView è un'estensione della classe View di Android che ti consente di visualizzare le pagine web come parte del layout della tua attività. Non include le funzionalità di un browser web completamente sviluppato, come i controlli di navigazione o una barra degli indirizzi. Per impostazione predefinita, WebView mostra solo una pagina web.

WebView può aiutarti a fornire informazioni nella tua app che potresti dover aggiornare, ad esempio un contratto con l'utente finale o una guida dell'utente. All'interno della tua app per Android, puoi creare un Activity che contiene un WebView, quindi utilizzarlo per visualizzare il documento ospitato online.

WebView può essere utile anche quando la tua app fornisce all'utente dati che richiedono una connessione a internet per essere recuperati, ad esempio le email. In questo caso, potresti scoprire che è più facile creare un WebView nella tua app per Android che mostri una pagina web con tutti i dati utente, anziché eseguire una richiesta di rete, quindi analizzare i dati ed eseguirne il rendering in un layout Android. Puoi invece progettare una pagina web personalizzata per i dispositivi Android e poi implementare un WebView nella tua app per Android che carica la pagina web.

Questo documento descrive come iniziare a utilizzare WebView, come associare JavaScript dalla tua pagina web al codice lato client nella tua app per Android, come gestire la navigazione nelle pagine e come gestire le finestre quando utilizzi WebView.

Utilizza WebView con le versioni precedenti di Android

Per utilizzare in sicurezza le funzionalità di WebView più recenti sul dispositivo su cui è in esecuzione la tua app, aggiungi la libreria Jetpack Webkit. Si tratta di una libreria statica che puoi aggiungere alla tua applicazione per utilizzare le API android.webkit non disponibili per le versioni precedenti della piattaforma.

Aggiungilo al file build.gradle come segue:

Kotlin

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

Alla moda

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

Per maggiori dettagli, esplora l'esempio WebView su GitHub.

Aggiungi una WebView alla tua app

Per aggiungere un WebView alla tua app, puoi includere l'elemento <WebView> nel layout dell'attività o impostare l'intera finestra Activity come WebView in onCreate.

Aggiungi una WebView nel layout dell'attività

Per aggiungere un WebView alla tua app nel layout, aggiungi il seguente codice al file XML del layout dell'attività:

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

Per caricare una pagina web in WebView, utilizza loadUrl, come mostrato nell'esempio seguente:

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

Aggiungi una WebView in onCreate()

Per aggiungere un WebView alla tua app nel metodo onCreate() di un'attività, utilizza una logica simile alla seguente:

Kotlin

val myWebView = WebView(activityContext)
setContentView(myWebView)

Java

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

Quindi carica la pagina:

Kotlin

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

Java

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

In alternativa, carica l'URL da una stringa 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");

L'app deve avere accesso a internet. Per ottenere l'accesso a internet, richiedi l'autorizzazione INTERNET nel file manifest, come mostrato nell'esempio seguente:

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

Puoi personalizzare il tuo WebView eseguendo una delle seguenti operazioni:

  • Abilitazione del supporto per lo schermo intero tramite WebChromeClient. Questa classe viene chiamata anche quando un WebView richiede l'autorizzazione per modificare l'interfaccia utente dell'app host, ad esempio per creare o chiudere finestre o inviare finestre di dialogo JavaScript all'utente. Per scoprire di più sul debug in questo contesto, leggi Esegui il debug delle app web.
  • Gestione di eventi che influiscono sul rendering dei contenuti, come errori negli invii di moduli o nella navigazione utilizzando WebViewClient. Puoi anche utilizzare questa sottoclasse per intercettare il caricamento degli URL.
  • Attivazione di JavaScript modificando WebSettings.
  • Utilizzo di JavaScript per accedere agli oggetti del framework Android che hai inserito in un WebView.

Utilizza JavaScript in WebView

Se la pagina web che vuoi caricare nella WebView utilizza JavaScript, devi attivare JavaScript per la WebView. Dopo aver attivato JavaScript, puoi creare interfacce tra il codice dell'app e il codice JavaScript.

Attiva JavaScript

JavaScript è disattivato in un WebView per impostazione predefinita. Puoi attivarla tramite WebSettings collegato al tuo WebView. Recupera WebSettings con getSettings, quindi attiva JavaScript con setJavaScriptEnabled.

Vedi l'esempio di seguito:

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 fornisce l'accesso a una serie di altre impostazioni che potresti trovare utili. Ad esempio, se stai sviluppando un'applicazione web progettata specificamente per WebView nella tua app per Android, puoi definire una stringa user agent personalizzata con setUserAgentString, quindi eseguire una query sullo user agent personalizzato nella tua pagina web per verificare che il client che richiede la tua pagina web sia la tua app per Android.

Associa il codice JavaScript al codice Android

Quando sviluppi un'applicazione web progettata specificamente per WebView nella tua app per Android, puoi creare interfacce tra il codice JavaScript e il codice Android lato client. Ad esempio, il codice JavaScript può chiamare un metodo nel codice Android per visualizzare un Dialog, anziché utilizzare la funzione alert() di JavaScript.

Per associare una nuova interfaccia tra il codice JavaScript e Android, chiama addJavascriptInterface, passando un'istanza di classe da associare al tuo JavaScript e un nome di interfaccia che il tuo JavaScript può chiamare per accedere alla classe.

Per scoprire di più sulla comunicazione tra JavaScript e il codice nativo, incluse API più moderne e sicure, consulta Accedi alle API native con JSBridge.

Ad esempio, puoi includere la seguente classe nella tua app per 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();
    }
}

In questo esempio, la classe WebAppInterface consente alla pagina web di creare un messaggio Toast utilizzando il metodo showToast().

Puoi associare questa classe al codice JavaScript eseguito in WebView con addJavascriptInterface(), come mostrato nell'esempio seguente:

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

Viene creata un'interfaccia denominata Android per JavaScript in esecuzione in WebView. A questo punto, la tua applicazione web ha accesso alla classe WebAppInterface. Ad esempio, ecco un codice HTML e JavaScript che crea un messaggio toast utilizzando la nuova interfaccia quando l'utente tocca un pulsante:

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

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

Non è necessario inizializzare l'interfaccia Android da JavaScript. WebView lo rende automaticamente disponibile per la tua pagina web. Quindi, quando un utente tocca il pulsante, la funzione showAndroidToast() utilizza l'interfaccia Android per chiamare il metodo WebAppInterface.showToast().

Gestisci la navigazione nelle pagine

Quando l'utente tocca un link da una pagina web nella tua WebView, per impostazione predefinita Android avvia un'app che gestisce gli URL. In genere, il browser web predefinito si apre e carica l'URL di destinazione. Tuttavia, puoi eseguire l'override di questo comportamento per il tuo WebView in modo che i link si aprano all'interno del tuo WebView. Puoi quindi consentire all'utente di navigare avanti e indietro nella cronologia delle pagine web gestita dal tuo WebView.

Per aprire i link toccati dall'utente, fornisci un WebViewClient per WebView utilizzando setWebViewClient. Tutti i link toccati dall'utente vengono caricati nella tua WebView. Se vuoi avere un maggiore controllo su dove viene caricato un link selezionato, crea il tuo WebViewClient che esegue l'override del metodo shouldOverrideUrlLoading. L'esempio seguente presuppone che MyWebViewClient sia una classe interna di 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;
  }
}

Quindi crea un'istanza di questo nuovo WebViewClient per WebView:

Kotlin

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

Java

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

Ora, quando l'utente tocca un link, il sistema chiama il metodo shouldOverrideUrlLoading, che controlla se l'host dell'URL corrisponde a un dominio specifico, come definito nell'esempio precedente. Se corrisponde, il metodo restituisce false e non esegue l'override del caricamento dell'URL. Consente al WebView di caricare l'URL come di consueto. Se l'host dell'URL non corrisponde, viene creato un Intent per avviare l'Activity predefinito per la gestione degli URL, che si risolve nel browser web predefinito dell'utente.

URL personalizzati degli handle

WebView applica limitazioni quando richiede risorse e risolve link che utilizzano uno schema URL personalizzato. Ad esempio, se implementi callback come shouldOverrideUrlLoading o shouldInterceptRequest, WebView li richiama solo per gli URL validi.

Ad esempio, WebView potrebbe non chiamare il metodo shouldOverrideUrlLoading per link come questo:

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

Gli URL non validi, come quello mostrato nell'esempio precedente, vengono gestiti in modo incoerente in WebView, pertanto ti consigliamo di utilizzare un URL con un formato corretto. Puoi utilizzare uno schema personalizzato o un URL HTTPS per un dominio controllato dalla tua organizzazione.

Anziché utilizzare una stringa semplice in un link, come nell'esempio precedente, puoi utilizzare uno schema personalizzato come il seguente:

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

Puoi quindi gestire questo URL nel metodo shouldOverrideUrlLoading in questo modo:

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

L'API shouldOverrideUrlLoading è destinata principalmente all'avvio di intent per URL specifici. Durante l'implementazione, assicurati di restituire false per gli URL gestiti da WebView. Tuttavia, non sei limitato al lancio di intent. Puoi sostituire gli intent di avvio con qualsiasi comportamento personalizzato negli esempi di codice precedenti.

Quando WebView esegue l'override del caricamento dell'URL, accumula automaticamente una cronologia delle pagine web visitate. Puoi navigare avanti e indietro nella cronologia con goBack e goForward.

Ad esempio, di seguito viene mostrato come l'app Activity può utilizzare il pulsante Indietro del dispositivo per tornare indietro:

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 la tua app utilizza Jetpack AppCompat 1.6.0 o versioni successive, puoi semplificare ulteriormente lo snippet precedente:

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

Il metodo canGoBack restituisce true se esiste una cronologia delle pagine web che l'utente può visitare. Analogamente, puoi utilizzare canGoForward per verificare se esiste una cronologia di navigazione in avanti. Se non esegui questo controllo, dopo che l'utente raggiunge la fine della cronologia, goBack e goForward non fanno nulla.

Per conservare la cronologia di navigazione durante la ricreazione dell'attività o il recupero del processo in background, utilizza saveState per serializzare la cronologia di navigazione di WebView in un Bundle e restoreState per ripristinarla. Per indicazioni su come gestire in sicurezza i limiti di dimensione dello stato salvato ed evitare TransactionTooLargeException, consulta Gestisci lo stato di WebView in modo efficiente.

Gestisci le modifiche alla configurazione dispositivo

Durante il runtime, le modifiche allo stato dell'attività si verificano quando la configurazione di un dispositivo cambia, ad esempio quando gli utenti ruotano il dispositivo o chiudono un editor del metodo di immissione (IME). Queste modifiche causano l'eliminazione dell'attività di un oggetto WebView e la creazione di una nuova attività, che crea anche un nuovo oggetto WebView che carica l'URL dell'oggetto eliminato. Puoi utilizzare saveState all'interno di onSaveInstanceState() e restoreState al momento della ricreazione per ripristinare il contesto di navigazione dell'utente. Per strategie su come gestire le dimensioni dello stato in modo sicuro, consulta Gestisci lo stato di WebView in modo efficiente.

Per modificare il comportamento predefinito dell'attività, puoi cambiare il modo in cui gestisce le modifiche di orientation nel manifest. Per scoprire di più sulla gestione delle modifiche alla configurazione durante il runtime, leggi Gestisci le modifiche alla configurazione.

Gestisci finestre

Per impostazione predefinita, le richieste di apertura di nuove finestre vengono ignorate. Questo vale sia che vengano aperte da JavaScript sia dall'attributo target in un link. Puoi personalizzare il tuo WebChromeClient per fornire il tuo comportamento per l'apertura di più finestre.

Per mantenere l'app più sicura, è meglio impedire l'apertura di popup e nuove finestre. Il modo più sicuro per implementare questo comportamento è passare "true" a setSupportMultipleWindows, ma non eseguire l'override del metodo onCreateWindow, da cui dipende setSupportMultipleWindows(). Questa logica impedisce il caricamento di qualsiasi pagina che utilizza target="_blank" nei propri link.

Gestisci la memoria e le prestazioni

Poiché WebView viene eseguito su un motore basato su Chromium con processi separati e codice nativo, la memoria utilizzata di base è superiore a quella delle visualizzazioni Android standard. Il riutilizzo delle istanze WebView e la loro corretta eliminazione sono essenziali per mantenere un'app stabile.

Per ulteriori informazioni su come diagnosticare e ottimizzare il footprint della memoria della tua app quando utilizzi contenuti web, consulta Gestisci ed esegui la diagnostica della memoria di WebView.