Tworzenie aplikacji internetowych w komponencie WebView

Użyj WebView, aby dostarczyć aplikację internetową lub stronę internetową jako część aplikacji klienckiej. Klasa WebView jest rozszerzeniem klasy View na Androidzie, które umożliwia wyświetlanie stron internetowych w ramach układu działań. Nie zawiera ona funkcji pełnej przeglądarki internetowej, takich jak elementy sterujące nawigacją czy pasek adresu. Domyślnie WebView wyświetla tylko stronę internetową.

WebView może pomóc Ci w przekazaniu w aplikacji informacji, które mogą wymagać aktualizacji, takich jak umowa użytkownika końcowego czy instrukcja użytkownika. W aplikacji na Androida możesz utworzyć Activity zawierający WebView, a następnie wyświetlić za jego pomocą dokument hostowany online.

WebView może też być przydatne, gdy Twoja aplikacja udostępnia dane użytkownikowi, który wymaga połączenia z internetem do pobrania danych, np. e-maili. W takim przypadku łatwiej jest utworzyć w aplikacji na Androida obiekt WebView, który wyświetla stronę internetową ze wszystkimi danymi użytkownika, zamiast wykonywać żądanie sieciowe, a następnie analizować dane i wyrenderować je w układzie Androida. Zamiast tego możesz zaprojektować stronę internetową dostosowaną do urządzeń z Androidem, a potem wdrożyć w aplikacji na Androida element WebView, który wczytuje tę stronę.

Z tego dokumentu dowiesz się, jak zacząć korzystać z narzędzia WebView, jak powiązać kod JavaScript ze strony internetowej z kodem po stronie klienta w aplikacji na Androida, jak obsługiwać nawigację po stronie i jak zarządzać oknami w usłudze WebView.

Korzystanie z komponentu WebView we wcześniejszych wersjach Androida

Aby bezpiecznie korzystać z nowszych funkcji WebViewna urządzeniu, na którym działa Twoja aplikacja, dodaj bibliotekę AndroidX Webkit. Jest to biblioteka statyczna, którą możesz dodać do swojej aplikacji, aby korzystać z interfejsów API android.webkit, które nie są dostępne dla starszych wersji platformy.

Dodaj go do pliku build.gradle w ten sposób:

Kotlin

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

Groovy

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

Aby dowiedzieć się więcej, przejrzyj przykład WebView na GitHubie.

Dodawanie komponentu WebView do aplikacji

Aby dodać WebView do aplikacji, możesz umieścić element <WebView> w układzie aktywności lub ustawić całe okno Activity jako WebViewonCreate().

Dodawanie WebView w układzie aktywności

Aby dodać WebView do układu aplikacji, dodaj do pliku XML układu aktywności ten kod:

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

Aby wczytać stronę internetową w WebView, użyj loadUrl() w następujący sposób:

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

Dodawanie WebView w metodzie onCreate()

Aby zamiast tego dodać WebView do aplikacji w metodie onCreate() aktywności, użyj takiej logiki:

Kotlin

val myWebView = WebView(activityContext)
setContentView(myWebView)

Java

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

Następnie wczytaj stronę:

Kotlin

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

Java

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

Możesz też załadować adres URL z łańcucha 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");

Aplikacja musi mieć dostęp do internetu. Aby uzyskać dostęp do internetu, poproś o przyznanie uprawnienia INTERNET w pliku manifestu, jak pokazano w tym przykładzie:

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

Możesz dostosować WebView, wykonując jedną z tych czynności:

  • Włączanie obsługi pełnego ekranu za pomocąWebChromeClient. Ta klasa jest również wywoływana, gdy WebView potrzebuje uprawnień do zmiany interfejsu aplikacji hosta, np. do tworzenia lub zamykania okien lub wysyłania do użytkownika okien JavaScript. Aby dowiedzieć się więcej o debugowaniu w tym kontekście, przeczytaj artykuł Debugowanie aplikacji internetowych.
  • Obsługiwanie zdarzeń, które mają wpływ na renderowanie treści, takich jak błędy podczas przesyłania formularzy lub nawigacji za pomocą WebViewClient. Możesz też użyć tej podklasy do przechwytywania wczytywania adresu URL.
  • Włączanie JavaScriptu przez zmodyfikowanie pliku WebSettings.
  • Używanie JavaScriptu do uzyskiwania dostępu do obiektów platformy Androida, które zostały wstrzyknięte do WebView.

Korzystanie z JavaScriptu w komponencie WebView

Jeśli strona internetowa, którą chcesz wczytać w urządzeniu WebView, używa JavaScriptu, musisz włączyć JavaScript w urządzeniu WebView. Po włączeniu JavaScript możesz tworzyć interfejsy między kodem aplikacji a kodem JavaScript.

Włącz obsługę języka JavaScript

W WebView domyślnie JavaScript jest wyłączony. Możesz go włączyć za pomocą WebSettings dołączonego do WebView. Pobierz WebSettings za pomocą getSettings(), a następnie włącz JavaScript za pomocą setJavaScriptEnabled().

Zobacz ten przykład:

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 zapewnia dostęp do wielu innych ustawień, które mogą Ci się przydać. Jeśli na przykład opracowujesz aplikację internetową przeznaczoną specjalnie do obsługi WebView w aplikacji na Androida, możesz zdefiniować niestandardowy ciąg danych użytkownika za pomocą setUserAgentString(), a następnie zapytać o niestandardowe dane użytkownika na stronie internetowej, aby sprawdzić, czy klient, który wysyła żądanie strony internetowej, to Twoja aplikacja na Androida.

Wiązanie kodu JavaScript z kodem Androida

Tworząc aplikację na Androida stworzoną specjalnie pod kątem WebView, możesz tworzyć interfejsy między kodem JavaScript a kodem Androida po stronie klienta. Kod JavaScript może np. wywołać metodę w kodzie Androida, aby wyświetlić Dialog, zamiast używać funkcji alert() w JavaScript.

Aby powiązać nowy interfejs między kodem JavaScript a kodem Androida, wywołaj funkcję addJavascriptInterface(), przekazując jej instancję klasy do powiązania z JavaScriptem i nazwę interfejsu, do którego JavaScript może się odwoływać, aby uzyskać dostęp do klasy.

W aplikacji na Androida możesz na przykład umieścić tę klasę:

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

W tym przykładzie klasa WebAppInterface umożliwia stronie internetowej tworzenie wiadomości Toast za pomocą metody showToast().

Możesz powiązać tę klasę z kodem JavaScript, który działa w Twoim WebView, za pomocą funkcji addJavascriptInterface(), jak pokazano w tym przykładzie:

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

Spowoduje to utworzenie interfejsu o nazwie Android dla kodu JavaScript uruchamianego w kontekście WebView. W tym momencie Twoja aplikacja internetowa ma dostęp do klasy WebAppInterface. Oto przykład kodu HTML i JavaScriptu, który tworzy komunikat typu toast za pomocą nowego interfejsu, gdy użytkownik kliknie przycisk:

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

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

Nie trzeba inicjować interfejsu Android za pomocą JavaScriptu. WebView automatycznie udostępnia je na Twojej stronie internetowej. Gdy użytkownik kliknie przycisk, funkcja showAndroidToast() wywoła metodę WebAppInterface.showToast() za pomocą interfejsu Android.

Obsługa nawigacji po stronie

Gdy użytkownik kliknie link na stronie internetowej w Twojej aplikacji WebView, Android domyślnie uruchamia aplikację, która obsługuje adresy URL. Zazwyczaj otwiera się domyślna przeglądarka internetowa i wczytuje docelowy adres URL. Możesz jednak zmienić to działanie w przypadku elementu WebView, aby linki otwierały się w WebView. Następnie możesz pozwolić użytkownikowi na przechodzenie w przód i w tył po historii stron internetowych przechowywanej przez WebView.

Aby otworzyć linki kliknięte przez użytkownika, podaj WebViewClient dla WebView za pomocą setWebViewClient(). Wszystkie linki, które użytkownik kliknie, wczytują się w Twoim WebView. Jeśli chcesz mieć większą kontrolę nad tym, gdzie otwiera się kliknięty link, utwórz własny WebViewClient, który zastąpi metodę shouldOverrideUrlLoading(). W tym przykładzie zakładamy, że MyWebViewClient jest klasą wewnętrzną klasy 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;
  }
}

Następnie utwórz instancję nowego WebViewClient dla środowiska WebView:

Kotlin

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

Java

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

Gdy użytkownik kliknie link, system wywoła metodę shouldOverrideUrlLoading(), która sprawdza, czy host adresu URL pasuje do określonej domeny zdefiniowanej w poprzednim przykładzie. Jeśli pasuje, metoda zwraca wartość false i nie zastępuje wczytywania adresu URL. Dzięki niemu WebView może ładować adres URL w zwykły sposób. Jeśli host adresu URL nie pasuje, tworzony jest element Intent, aby uruchomić domyślny element Activity do obsługi adresów URL, który przekierowuje do domyślnej przeglądarki użytkownika.

Obsługa niestandardowych adresów URL

WebView stosuje ograniczenia podczas żądania zasobów i rozwiązywania linków, które używają niestandardowego schematu adresu URL. Jeśli na przykład zaimplementujesz wywołania zwrotne takie jak shouldOverrideUrlLoading() lub shouldInterceptRequest(), funkcja WebView będzie je wywoływać tylko w przypadku prawidłowych adresów URL.

Na przykład WebView może nie wywoływać metody shouldOverrideUrlLoading() w przypadku linków takich jak:

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

Nieprawidłowe adresy URL, takie jak ten z poprzedniego przykładu, są obsługiwane w zasadzie WebView w sposób niespójny, dlatego zalecamy użycie poprawnego adresu URL. Możesz użyć schematu niestandardowego lub adresu URL HTTPS w domenie kontrolowanej przez Twoją organizację.

Zamiast prostego ciągu znaków w linku, jak w poprzednim przykładzie, możesz użyć schematu niestandardowego takiego:

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

Następnie możesz obsługiwać ten adres URL w metodzie shouldOverrideUrlLoading() w ten sposób:

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

Interfejs API shouldOverrideUrlLoading() jest przeznaczony głównie do uruchamiania intencji w przypadku określonych adresów URL. Podczas jego wdrażania pamiętaj, aby zwracać false w przypadku adresów URL, których uchwyty WebView. Nie musisz jednak ograniczać się do uruchamiania intencji. W powyższych przykładach kodu możesz zastąpić intencje uruchamiania dowolnym zachowaniem niestandardowym.

Gdy WebView zastąpi wczytywanie adresu URL, automatycznie będzie gromadzić historię odwiedzonych stron internetowych. Możesz poruszać się wstecz i do przodu po historii za pomocą goBack()goForward().

Na przykład poniżej pokazujemy, jak Activity może używać przycisku Wstecz do przechodzenia wstecz:

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

Jeśli Twoja aplikacja używa AndroidX AppCompat w wersji 1.6.0 lub nowszej, możesz jeszcze bardziej uprościć poprzedni fragment kodu:

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

Metoda canGoBack() zwraca wartość „prawda”, jeśli użytkownik ma historię stron internetowych do odwiedzenia. Podobnie możesz użyć canGoForward(), aby sprawdzić, czy istnieje historia do przodu. Jeśli nie wykonasz tej czynności, po osiągnięciu końca historii goBack() i goForward() nic nie robią.

Obsługa zmian konfiguracji urządzenia

Podczas działania stan aktywności zmienia się, gdy zmienia się konfiguracja urządzenia, np. gdy użytkownik obróci urządzenie lub zamknie edytor metody wprowadzania (IME). Te zmiany powodują zniszczenie aktywności obiektu WebView i utworzenie nowej aktywności, która tworzy też nowy obiekt WebView, który wczytuje adres URL usuniętego obiektu. Aby zmienić domyślne działanie aktywności, możesz zmienić sposób, w jaki obsługuje ona zmiany orientation w pliku manifestu. Więcej informacji o obsługiwaniu zmian konfiguracji w czasie wykonywania znajdziesz w artykule Obsługa zmian konfiguracji.

Zarządzaj oknami

Domyślnie prośby o otwieranie nowych okien są ignorowane. Dzieje się tak niezależnie od tego, czy są otwierane przez JavaScript czy przez atrybut docelowy w linku. Możesz dostosować WebChromeClient, aby określić własne zachowanie podczas otwierania wielu okien.

Aby zwiększyć bezpieczeństwo aplikacji, najlepiej uniemożliwić otwieranie wyskakujących okienek i nowych okien. Najbezpieczniejszym sposobem implementacji tego zachowania jest przekazanie wartości "true" do metody setSupportMultipleWindows(), ale nie zastąpienie metody onCreateWindow(), od której zależy setSupportMultipleWindows(). Ta logika uniemożliwia wczytywanie stron, które zawierają znak target="_blank" w linkach.