Tworzenie aplikacji internetowych w komponencie WebView

Użyj narzędzia WebView, aby udostępnić 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 obejmuje funkcji w pełni opracowanych przeglądarek internetowych, takich jak elementy sterujące nawigacji czy pasek adresu. Domyślnie WebView pokazuje stronę internetową.

WebView może ułatwić Ci podanie w aplikacji informacji, które być może trzeba będzie zaktualizować, np. umowy użytkownika lub przewodnika użytkownika. W aplikacji na Androida możesz utworzyć obiekt Activity zawierający WebView, a następnie używać go do wyświetlania dokumentu hostowanego 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 następnie zaimplementować w aplikacji na Androida obiekt WebView, który będzie ją wczytywać.

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 najnowszych funkcji WebView na 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")
}

Odlotowe

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 uwzględnić element <WebView> w układzie aktywności lub ustawić całe okno Activity jako WebView w onCreate().

Dodawanie komponentu WebView w układzie aktywności

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

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

Dodaj komponent WebView w onCreate()

Aby zamiast tego dodać WebView do aplikacji w metodzie onCreate() aktywności, użyj funkcji logicznej podobnej do tego:

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ż wczytać adres URL z ciągu 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 uprawnienie INTERNET w pliku manifestu, jak w tym przykładzie:

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

Aby dostosować WebView, wykonaj jedną z tych czynności:

  • Włączanie obsługi pełnego ekranu za pomocą funkcji 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. Więcej informacji o debugowaniu w tym kontekście znajdziesz w artykule 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żywać tej podklasy do przechwytywania wczytywania adresu URL.
  • Aby włączyć JavaScript, zmodyfikuj metodę WebSettings.
  • Dostęp za pomocą JavaScriptu do obiektów platformy Androida wstrzykniętych do obiektu WebView.

Używanie JavaScriptu w komponencie WebView

Jeśli strona internetowa, którą chcesz wczytać w elemencie WebView, korzysta z JavaScriptu, musisz włączyć JavaScript na swoim koncie WebView. Po włączeniu JavaScriptu możesz tworzyć interfejsy między kodem aplikacji a JavaScriptem.

Włączanie JavaScript

W WebView domyślnie JavaScript jest wyłączony. Możesz ją włączyć za pomocą WebSettings dołączonego do urządzenia 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 daje dostęp do wielu innych ustawień, które mogą Ci się przydać. Jeśli np. tworzysz aplikację internetową stworzoną specjalnie pod kątem usługi WebView w aplikacji na Androida, możesz zdefiniować niestandardowy ciąg znaków klienta użytkownika za pomocą parametru setUserAgentString(), a następnie wysłać do niego zapytanie na stronie internetowej, aby sprawdzić, czy klient, który chce wyświetlić stronę, to Twoja aplikacja na Androida.

Powiąż kod JavaScript z kodem Androida

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

Aby powiązać nowy interfejs między kodem JavaScript a kodem Androida, wywołaj addJavascriptInterface(), przekazując do niej instancję klasy w celu powiązania z JavaScriptem oraz nazwę interfejsu, którą JavaScript może wywołać w celu uzyskania dostępu do klasy.

Możesz na przykład umieścić w swojej aplikacji na Androida 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 pozwala stronie internetowej utworzyć wiadomość Toast przy użyciu metody showToast().

Możesz powiązać tę klasę z JavaScriptem, który działa w WebView za pomocą addJavascriptInterface(), jak 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 JavaScriptu uruchomionego w środowisku WebView. W tym momencie Twoja aplikacja internetowa ma dostęp do klasy WebAppInterface. Oto przykładowy kod HTML i JavaScript, który po kliknięciu przycisku przez użytkownika tworzy w nowym interfejsie powiadomienie z komunikatem:

<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. Dzięki temu, gdy użytkownik klika przycisk, funkcja showAndroidToast() wykorzystuje interfejs Android do wywołania metody WebAppInterface.showToast().

Uchwyć nawigację po stronie

Gdy użytkownik kliknie link na stronie internetowej w narzędziu WebView, Android domyślnie uruchomi aplikację, która obsługuje adresy URL. Zwykle domyślna przeglądarka otwiera się 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 wstecz i do przodu w historii stron internetowych zarządzaną przez WebView.

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

Teraz, gdy użytkownik klika link, system wywołuje metodę shouldOverrideUrlLoading(), która sprawdza, czy host adresu URL pasuje do określonej domeny, jak zdefiniowano w poprzednim przykładzie. Jeśli tak, metoda zwraca wartość „false” (fałsz) 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 jest zgodny, tworzony jest obiekt Intent, który uruchamia domyślną przeglądarkę Activity do obsługi adresów URL, która otwiera domyślną przeglądarkę użytkownika.

Obsługa niestandardowych adresów URL

WebView stosuje ograniczenia podczas żądania zasobów i usuwania linków, które korzystają z niestandardowego schematu adresu URL. Jeśli np. wdrożysz wywołania zwrotne, takie jak shouldOverrideUrlLoading() lub shouldInterceptRequest(), WebView będzie wywoływać je 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 stosowanie prawidłowego formatu. 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 jak:

<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() służy przede wszystkim do uruchamiania intencji związanych z określonymi adresami URL. Podczas wdrażania pamiętaj, aby w przypadku adresów URL, które obsługuje WebView, zwracał on pole false. Nie musisz jednak ograniczać się do wprowadzania intencji. Intencje uruchamiania możesz zastąpić dowolnymi zachowaniami niestandardowymi z poprzednich przykładów kodu.

Jeśli reguła WebView zastąpi wczytanie adresu URL, automatycznie zostanie utworzona historia odwiedzonych stron internetowych. Możesz przechodzić do przodu i do tyłu w historii za pomocą goBack() i 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 używasz AndroidaX AppCompat w wersji 1.6.0 lub nowszej, możesz jeszcze bardziej uprościć poprzedni fragment:

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ę strony internetowej, którą chce odwiedzić. Podobnie możesz użyć canGoForward(), aby sprawdzić, czy istnieje historia przekazywania dalej. Jeśli nie sprawdzisz tego, goBack() i goForward() nie będą podejmować żadnych działań, gdy użytkownik dotrze do końca historii.

Obsługa zmian w konfiguracji urządzenia

W czasie działania stan aktywności zmienia się, gdy zmieni się konfiguracja urządzenia, na przykład gdy użytkownik obróci urządzenie lub zamknie edytor metody wprowadzania (IME). Zmiany te powodują zniszczenie aktywności obiektu WebView i utworzenie nowej aktywności, co powoduje też utworzenie nowego obiektu WebView, który wczytuje adres URL zniszczonego 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łudze zmian konfiguracji w czasie działania znajdziesz w artykule Obsługiwanie zmian konfiguracji.

Zarządzaj oknami

Domyślnie żądania otwarcia nowych okien są ignorowane. Dzieje się tak niezależnie od tego, czy otwierają je za pomocą JavaScriptu, czy przez atrybut ustalony w linku. Możesz dostosować WebChromeClient, by odpowiadał potrzebom otwierania wielu okien.

Aby zwiększyć bezpieczeństwo aplikacji, najlepiej unikać otwierania wyskakujących okienek i nowych okien. Najbezpieczniejszym sposobem wdrożenia tego działania jest przekazanie "true" do setSupportMultipleWindows(), ale bez zastąpienia metody onCreateWindow(), od której zależy wartość setSupportMultipleWindows(). Ta logika uniemożliwia wczytywanie stron, których linki używają target="_blank".