WebView
を使用して、ウェブ アプリケーションまたはウェブページをクライアント アプリケーションの一部として配信します。WebView
クラスは Android の View
クラスの拡張機能で、アクティビティ レイアウトの一部としてウェブページを表示できるようにします。ナビゲーション コントロールやアドレスバーなど、完全に開発されたウェブブラウザの機能は含まれません。デフォルトでは、WebView
はすべてウェブページを表示します。
WebView
は、エンドユーザー契約やユーザーガイドなど、更新する必要がある情報をアプリ内で提供するうえで役立ちます。Android アプリ内で、WebView
を含む Activity
を作成し、それを使用してオンラインでホストされているドキュメントを表示できます。
WebView
は、メールなどのデータの取得にインターネット接続を必要とするユーザーにデータを提供する場合にも役立ちます。この場合、ネットワーク リクエストを実行してデータを解析して Android レイアウトにレンダリングするよりも、すべてのユーザーデータを含むウェブページを表示する WebView
を Android アプリで作成する方が簡単です。代わりに、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 コードでは、JavaScript の alert()
関数を使用する代わりに、Android コード内のメソッドを呼び出して 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
内のウェブページからリンクをタップすると、デフォルトでは、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
が起動します。これはユーザーのデフォルトのウェブブラウザに解決されます。
カスタム 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 のインテントを起動することを主な目的としています。この API を実装する際は、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 で行われた場合も、リンク内の target 属性で開かれた場合でも同じです。WebChromeClient
をカスタマイズして、複数のウィンドウを開くための独自の動作を指定できます。
アプリのセキュリティを高めるには、ポップアップや新しいウィンドウが開かないようにすることをおすすめします。この動作を実装する最も安全な方法は、"true"
を setSupportMultipleWindows()
に渡しますが、setSupportMultipleWindows()
が依存する onCreateWindow()
メソッドをオーバーライドしないことです。このロジックにより、リンクで target="_blank"
を使用しているページの読み込みがブロックされます。