3. ウェブアプリの WebView への組み込み


概略

  • WebView を使ってAndroid アプリケーションのレイアウトにウェブページを表示します。
  • JavaScript からクライアント側の Android のコードへのインターフェイスを作成することができます。

このドキュメントの内容

  1. アプリケーションへの WebView 追加
  2. WebView での JavaScript の使用
    1. JavaScript の有効化
    2. JavaScript コードの Android コードへのバインド
  3. ページナビゲーションのハンドリング 
    1. ウェブページ履歴のナビゲーション

主なクラス

  1. WebView
  2. WebSettings
  3. WebViewClient

関連するチュートリアル

  1. ウェブビュー

クライアントのアプリケーションの一部としてウェブアプリケーション ( または単にウェブページ ) を配信したい場合、WebView を使ってそれを実現することができます。WebView クラスは Android の View クラスの拡張で、アクティビティのレイアウトの一部としてウェブページを表示することができます。これには完成されたウェブブラウザにあるようなナビゲーション制御やアドレスバーといった機能は含まれていません。ウェブページを表示することがデフォルトで WebView がやれることのすべてです。

WebView を使うと便利なよくある状況は、アプリケーションで更新が必要な情報、例えばエンドユーザ同意やユーザガイドなどを提供するときです。Android アプリケーション内で、 WebView を含む Activity を作成することができ、オンラインで提供するドキュメントを表示するためにそれを使います。

WebView を使うと便利な状況はもうひとつあり、email などのデータを取得するために、常にインターネット接続を必要とするユーザにアプリケーションがデータを提供する場合です。この場合、Android アプリケーションでネットワークにリクエストを送信し、データを解析し、Android のレイアウトにレンダリングするよりは、Android アプリケーションに WebView を組み込んで、すべてのユーザデータでウェブページを表示してしまう方がより簡単であることに気づくと思います。それを可能にするためには、Android デバイス専用にウェブページをデザインし、ウェブページをロードする Android アプリケーションに WebView を実装します。

このドキュメントでは、WebView の使い方の基本知識と、Android アプリケーションでのナビゲーションのハンドリングや、ウェブページからクライアントのコードへの JavaScript のバインドといった付加的な機能の操作方法を示します。


アプリケーションへの WebView の追加

アプリケーションに WebView を追加するには、アクティビティのレイアウトで単純に <WebView> 要素を追加するだけです。例えば、以下のレイアウトファイルでは、WebView が画面全体に埋められます。

<?xml version="1.0" encoding="utf-8"?>
<WebView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/webview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>

WebView にウェブページをロードするには、loadUrl() を使います。以下はその例です。

WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.loadUrl("http://www.example.com");

ですが、これを動かす前にアプリケーションがインターネットにアクセスする必要があります。インターネットにアクセスするには、マニフェストファイルで INTERNET 許可を要求します。以下はその例です。

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

...
</manifest>

ウェブページを表示する WebView のために必要な準備はこれがすべてです。


WebView での JavaScript の使用

WebView にロードする予定のウェブページで JavaScript を使用する場合は、WebView に対し JavaScript を有効にする必要があります。いちど JavaScript が有効になればアプリケーションと JavaScript コード間のインターフェイスを作成することも可能になります。

JavaScript の有効化

WebView では、デフォルトで JavaScript が無効です。これを WebView に付属している WebSettings で有効にすることができます。WebSettingsgetSettings() で取得でき、それから setJavaScriptEnabled() で JavaScript を有効にします。

以下はその例です。

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 コードにあるメソッドを呼び出して Dialog を表示すれば、JavaScript の alert() 関数の代わりとして使えるようになります。

JavaScript と Android コード間のインターフェイスを新たにバインドするには、バインドする JavaScript をバインドするためのクラスのインスタンスと、そのクラスにアクセスするために JavaScript が呼び出すことのできるインターフェイス名を渡して addJavascriptInterface() を呼び出します。

例えば、Android アプリケーションで以下のクラスを追加することができます。

public class JavaScriptInterface {
Context mContext;

/** Instantiate the interface and set the context */
JavaScriptInterface(Context c) {
mContext = c;
}

/** Show a toast from the web page */
public void showToast(String toast) {
Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
}
}

この例では、JavaScriptInterface クラスによりウェブページが Toast メッセージを showToast() メソッドを使って作成できるようになります。

addJavascriptInterface()Android というインターフェイス名を使って、このクラスと WebView で実行される JavaScript をバインドすることができます。 以下はその例です。

WebView webView = (WebView) findViewById(R.id.webview);
webView.addJavascriptInterface(new JavaScriptInterface(this), "Android");

これにより、Android という名前で WebView で実行する JavaScript のインターフェイスが作成されます。この時点から、ウェブアプリケーションが JavaScriptInterface クラスにアクセスできるようになります。ユーザがクリックしたときにこの新しいインターフェイスを使ってトーストメッセージを表示する JavaScript を持つ HTML の例が以下です。

<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 インターフェイスを使って JavaScriptInterface.showToast() メソッドを呼び出します。

注意: JavaScript にバインドされたオブジェクトはそれが生成されたスレッドではない別スレッドで実行します。

警戒: addJavascriptInterface() を使うと JavaScript で Android アプリケーションを制御できるようになります。これはとても便利ではありますがセキュリティ的に問題があり危険です。WebView の HTML が信頼できないと ( 例えば、HTML の一部または全部が提供元が不明な人物や行為により提供されているもの ) 、攻撃者によりクライアント側のコードや、もしかすると攻撃者が選別したコードを実行するような HTML を埋め込むことができてしまいます。WebView に表示させる HTML と JavaScript のすべてが記述されていない場合は、そういった用途で addJavascriptInterface() を使用すべきではありません。また、WebView の内で自分が作成したウェブページ以外にユーザがアクセスできるようにすべきではありません ( その代わり、ユーザにはデフォルトのブラウザアプリケーションで外部のリンクを開かせるようにします。ユーザのウェブブラウザは、デフォルトですべての URL リンクを開くようになっているのでいいのですが、以下のセクションで説明する際のページのナビゲーションのハンドリングの場合のみ注意が必要です ) 。


ページナビゲーションのハンドリング

ユーザが WebView 内でリンクをクリックしたとき、URL をハンドリングするアプリケーションを起動するのが Android のデフォルトの振る舞いになります。通常はデフォルトのウェブブラウザが開き、宛先の URL をロードします。しかしながら、この振る舞いを WebView に優先させるようにすることができ、それにより WebView 内でリンクが開くようになります。そのあとユーザはウェブページの WebView により保持されたウェブページの履歴を前後にナビゲーションすることができるようになります。

ユーザがクリックしたリンクを開くには、単純に setWebViewClient() を使って、WebViewWebViewClient を提供します。以下はその例です。

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

これだけです。これでユーザが WebView でリンクをクリックするとすべてのリンクをロードするようになりました。

クリックされたリンクのロードをさらに場所で管理したい場合は、独自の WebViewClient を作成し、 shouldOverrideUrlLoading() メソッドをオーバーライドします。以下はその例です。

private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (Uri.parse(url).getHost().equals("www.example.com")) {
// This is my web site, so do not override; let my WebView load the page
return false;
}
// Otherwise, the link is not for a page on my site, so launch another Activity that handles URLs
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
return true;
}
}

それから、この新しい WebViewClient のインスタンスを WebView 用に作成します。

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

これでユーザがリンクをクリックしたときに、システムが shouldOverrideUrlLoading() を呼び出し、URL のホストが特定のドメイン ( 上で定義されたもの ) と一致しているかどうかをチェックするようになりました。一致した場合は、URL のロードを優先しないようにするためにメソッドが false を返します  ( これにより WebView が通常通りに URL をロードできるようにします ) 。URL ホストが一致しない場合は、Intent が作られ、URL ( ユーザのデフォルトのウェブブラウザを解決する ) をハンドリングするデフォルトのアクティビティを起動します。

ウェブページ履歴のナビゲーション

WebView が URL のロードを優先したときは、自動的に訪問したウェブページの履歴が蓄積されます。履歴の前と後へは goBack()goForward() を使ってナビゲーションすることができます。

以下は Activity でデバイスの BACK キーを使って前の履歴にナビゲーションする方法の例です。

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// Check if the key event was the BACK key and if there's history
if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack() {
myWebView.goBack();
return true;
}
// If it wasn't the BACK key or there's no web page history, bubble up to the default
// system behavior (probably exit the activity)
return super.onKeyDown(keyCode, event);
}

canGoBack() メソッドはユーザが訪問したウェブページが実際に存在していれば true を返します。同様に、canGoForward() を使って後の履歴があるかどうかをチェックすることができます。このチェックを行わない場合は、ユーザが履歴の最後に到達し、 goBack()goForward() を実行しても何も起こりません。