WebView
を使用して、クライアント アプリケーションの一部としてウェブ アプリケーションまたはウェブページを配信します。WebView
クラスは、Android の View
クラスの拡張であり、アクティビティ レイアウトの一部としてウェブページを表示できます。ナビゲーション機能やアドレスバーなど、完全なウェブブラウザとしての機能は含まれません。WebView
は、デフォルトではウェブページを表示するだけです。
WebView
を使用すると、エンドユーザー契約やユーザーガイドなど、更新が必要になる可能性のある情報をアプリで提供できます。Android アプリ内で、WebView
を含む Activity
を作成し、これを使用してオンラインでホストされているドキュメントを表示できます。
WebView
は、取得にインターネット接続が必要なデータ(メールなど)をユーザーにアプリで提供する場合にも役立ちます。この場合、ネットワーク リクエストを行ってからデータを解析し、Android レイアウトでレンダリングするよりも、Android アプリで WebView
をビルドし、すべてのユーザーデータを含むウェブページを表示するほうが簡単な可能性があります。代わりに、Android デバイス用に調整したウェブページを設計し、ウェブページを読み込む Android アプリに WebView
を実装できます。
このドキュメントでは、WebView
の使用方法、ウェブページから Android アプリのクライアントサイド コードへの JavaScript のバインド方法、ページ ナビゲーションの処理方法、WebView
使用時のウィンドウの管理方法について説明します。
以前のバージョンの Android で WebView を操作する
アプリが実行されているデバイスで最新の WebView
機能を安全に使用するには、AndroidX Webkit ライブラリを追加します。これは、以前のプラットフォーム バージョンでは使用できない android.webkit
API を使用するようにアプリに追加できる静的ライブラリです。
次のように build.gradle
ファイルに追加します。
Kotlin
dependencies { implementation("androidx.webkit:webkit:1.8.0") }
Groovy
dependencies { implementation ("androidx.webkit:webkit:1.8.0") }
詳細については、GitHub の WebView
の例をご覧ください。
アプリに WebView を追加する
WebView
をアプリに追加するには、アクティビティ レイアウトに <WebView>
要素を設定するか、onCreate()
内で Activity
ウィンドウ全体を WebView
として設定します。
アクティビティ レイアウトで WebView を追加する
レイアウトでアプリに WebView
を追加するには、アクティビティのレイアウト XML ファイルに次のコードを追加します。
<WebView android:id="@+id/webview" android:layout_width="match_parent" android:layout_height="match_parent" />
WebView
でウェブページを読み込むには、次の例に示すように loadUrl()
を使用します。
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");
onCreate() で WebView を追加する
代わりに、アクティビティの onCreate()
メソッドでアプリに WebView
を追加するには、次のようなロジックを使用します。
Kotlin
val myWebView = WebView(activityContext) setContentView(myWebView)
Java
WebView myWebView = new WebView(activityContext); setContentView(myWebView);
次のように、ページを読み込みます。
Kotlin
myWebView.loadUrl("http://www.example.com")
Java
myWebView.loadUrl("https://www.example.com");
または、HTML 文字列から URL を読み込みます。
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");
アプリがインターネットにアクセスできる必要があります。インターネット アクセスを取得するには、次の例に示すように、マニフェスト ファイルで INTERNET
権限をリクエストします。
<manifest ... > <uses-permission android:name="android.permission.INTERNET" /> ... </manifest>
WebView
は、次のいずれかの方法でカスタマイズできます。
WebChromeClient
を使用して全画面表示のサポートを有効にする。このクラスは、WebView
でホストアプリの UI を変更する(ウィンドウの作成や終了、JavaScript ダイアログのユーザーへの送信など)権限を必要とするときにも呼び出されます。このコンテキストでのデバッグの詳細については、ウェブアプリをデバッグするをご覧ください。- フォーム送信のエラーや
WebViewClient
を使用したナビゲーションなど、コンテンツのレンダリングに影響を与えるイベントを処理する。このサブクラスを使用して URL の読み込みを傍受することもできます。 WebSettings
を変更して JavaScript を有効にする。- JavaScript を使用して
WebView
に組み込んだ Android フレームワーク オブジェクトにアクセスする。
WebView で JavaScript を使用する
WebView
で読み込むウェブページで JavaScript が使用されている場合、WebView
で JavaScript を有効にする必要があります。JavaScript を有効にすると、アプリコードと JavaScript コードの間にインターフェースを作成できます。
JavaScript を有効にする
デフォルトでは、JavaScript は WebView
で無効になっています。WebView
に接続された WebSettings
で有効にできます。getSettings()
で WebSettings
を取得してから、setJavaScriptEnabled()
で JavaScript を有効にします。
次の例をご覧ください。
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
により、他の便利な各種設定にアクセスできるようになります。たとえば、Android アプリの WebView
専用に設計されたウェブ アプリケーションを開発している場合は、setUserAgentString()
を使用してカスタム ユーザー エージェント文字列を定義し、ウェブページでカスタム ユーザー エージェントをクエリして、ウェブページをリクエストしているクライアントが Android アプリであることを確認できます。
JavaScript コードを Android コードにバインドする
Android アプリで WebView
専用のウェブ アプリケーションを開発する場合は、JavaScript コードとクライアント側 Android コードの間にインターフェースを作成できます。たとえば、JavaScript コードで、Android コードのメソッドを呼び出して、JavaScript の alert()
関数を使用する代わりに、Dialog
を表示できます。
JavaScript と Android のコードの間に新しいインターフェースをバインドするには、addJavascriptInterface()
を呼び出し、JavaScript にバインドするクラス インスタンスと、クラスにアクセスするために JavaScript が呼び出すことができるインターフェース名を渡します。
例として、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(); } }
この例では、WebAppInterface
クラスにより、showToast()
メソッドを使用してウェブページで Toast
メッセージを作成できます。
次の例に示すように、addJavascriptInterface()
を使用して WebView
で実行する JavaScript にこのクラスをバインドできます。
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");
これにより、WebView
で実行される JavaScript 用の Android
というインターフェースが生成されます。この時点で、ウェブ アプリケーションは WebAppInterface
クラスにアクセスできます。たとえば、次の HTML と JavaScript は、ユーザーがボタンをタップしたときに、新しいインターフェースを使用してトースト メッセージを作成します。
<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" /> <script type="text/javascript"> function showAndroidToast(toast) { Android.showToast(toast); } </script>
JavaScript から Android
インターフェースを初期化する必要はありません。WebView
により、自動的にウェブページで利用できるようになります。ユーザーがボタンをタップすると、showAndroidToast()
関数は Android
インターフェースを使用して WebAppInterface.showToast()
メソッドを呼び出します。
ページ ナビゲーションを処理する
ユーザーが WebView
のウェブページからリンクをタップすると、デフォルトでは、Android は URL を処理するアプリを起動します。通常は、デフォルトのウェブブラウザが開いてリンク先 URL を読み込みます。ただし、この WebView
の動作をオーバーライドして、WebView
内でリンクが開くようにできます。さらに、WebView
によって維持されるウェブページ履歴にそってユーザーが前後に移動できるようにも設定できます。
ユーザーがタップしたリンクを開くには、setWebViewClient()
を使用して WebView
に WebViewClient
を提供します。ユーザーがタップしたすべてのリンクが WebView
に読み込まれます。クリックしたリンクの読み込み先をさらに制御したい場合は、shouldOverrideUrlLoading()
メソッドをオーバーライドする独自の WebViewClient
を作成します。次の例では、MyWebViewClient
が 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; } }
次に、以下のとおり、WebView
用に新しい WebViewClient
のインスタンスを作成します。
Kotlin
val myWebView: WebView = findViewById(R.id.webview) myWebView.webViewClient = MyWebViewClient()
Java
WebView myWebView = (WebView) findViewById(R.id.webview); myWebView.setWebViewClient(new MyWebViewClient());
これで、ユーザーがリンクをタップすると、システムは shouldOverrideUrlLoading()
メソッドを呼び出し、URL ホストが前述の例で定義した特定のドメインに一致するかどうかを確認します。一致した場合、メソッドは false を返して URL の読み込みをオーバーライドしません。これにより、WebView
は通常どおり URL を読み込むことができます。URL ホストが一致しない場合、Intent
が作成され、URL 処理用のデフォルトの Activity
が起動されます。この Activity
は、ユーザーのデフォルトのウェブブラウザに解決されます。
カスタム URL を処理する
WebView
は、リソースをリクエストしたり、カスタム URL スキームを使用するリンクを解決したりするときに制限を適用します。たとえば、shouldOverrideUrlLoading()
や shouldInterceptRequest()
などのコールバックを実装すると、WebView
は有効な URL に対してのみコールバックを呼び出します。
たとえば、WebView
は、次のようなリンクに対して shouldOverrideUrlLoading()
メソッドを呼び出さない場合があります。
<a href="showProfile">Show Profile</a>
上記の例のような無効な URL は WebView
で不整合に処理されるため、代わりに適切な形式の URL を使用することをおすすめします。組織が管理するドメインには、カスタム スキームまたは HTTPS URL を使用できます。
上の例のようにリンクで単純な文字列を使用する代わりに、次のようなカスタム スキームを使用できます。
<a href="example-app:showProfile">Show Profile</a>
次に、この URL を shouldOverrideUrlLoading()
メソッドで以下のように処理できます。
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; }
shouldOverrideUrlLoading()
API は主に、特定の URL のインテントを起動することを目的としています。実装する際は、WebView
ハンドルの URL に対して false
を返すようにしてください。ただし、起動インテントに限定されません。上記のコードサンプルでは、起動インテントを任意のカスタム動作に置き換えることができます。
ウェブページ履歴を操作する
WebView
が URL の読み込みをオーバーライドすると、アクセスしたウェブページの履歴が自動的に蓄積されます。履歴を前後に移動するには、goBack()
と goForward()
を使用します。
たとえば、Activity
でデバイスの [戻る] ボタンを使用して後方に移動する方法は次のとおりです。
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); }
アプリで AndroidX AppCompat
1.6.0 以降を使用している場合は、前のスニペットをさらに簡素化できます。
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(); } }
canGoBack()
メソッドは、ユーザーがアクセスできるウェブページ履歴がある場合に true を返します。同様に、canGoForward()
を使用して、進むことが可能な履歴があるかどうかを確認できます。このチェックを行わない場合、ユーザーが履歴の最後に到達すると、goBack()
と goForward()
は何も行いません。
デバイス設定の変更を処理する
実行時に、ユーザーがデバイスを回転させたり、インプット メソッド エディタ(IME)を閉じたりするなど、デバイス設定が変更されると、アクティビティ状態が変更されます。これらの変更により、WebView
オブジェクトのアクティビティが破棄され、新しいアクティビティが作成されます。これにより、破棄されたオブジェクトの URL を読み込む新しい WebView
オブジェクトも作成されます。アクティビティのデフォルトの動作を変更するには、マニフェストで orientation
の変更処理方法を変更できます。実行時の構成変更の処理について詳しくは、構成の変更に対処するをご覧ください。
ウィンドウの管理
デフォルトでは、新しいウィンドウを開くリクエストは無視されます。これは、開かれるのが JavaScript によるものでも、リンクのターゲット属性によるものでも同じです。WebChromeClient
をカスタマイズして、複数のウィンドウを開く動作をご自身で提供できます。
アプリをより安全に保つには、ポップアップや新しいウィンドウが開かないようにすることをおすすめします。この動作を最も安全に実装する方法は、setSupportMultipleWindows()
に "true"
を渡しつつ、setSupportMultipleWindows()
が依存する onCreateWindow()
メソッドをオーバーライドしないことです。このロジックにより、リンクで target="_blank"
を使用するページは読み込まれなくなります。