ハイブリッドな Android アプリを目指して WebView を使ってみる

この先、Webサイト+ハイブリッドアプリ公開が主流になるのではないかと予想して、WebView の使い方を勉強してみる。

ハイブリッドアプリとは、スマートフォン向けのアプリケーションだが、コンテンツ自体は通常のWebサイトを表示するようなアプリのことを指す(と思ってる)

8割ネイティブアプリ、2割がWebviewでサイト表示している、またはその逆でほとんどWebviewだけの外側だけのアプリなど、程度によりけりなんだろうけど、割合としてWebViewでサイトをレンダリングしているコンテンツが多くを占める場合はハイブリッドアプリと呼びそう。

ちなみに今回参考にするのは、Android公式ページのチュートリアル。

Building Web Apps in WebView 和訳

クライアントアプリケーションの一部としてウェブアプリケーション(または単にウェブページ)を表示させたい場合には、WebViewを使うと良いでしょう。

WebView クラスは View クラスを継承していて、アクティビティの一部としてウェブページを表示することができます。

ウェブブラウザを作る、ナビゲーションコントロールやアドレスバーなどの機能は含まれていません。

WebView がデフォルトでやることは、ウェブページの表示が全てです。

更新するかもしれない利用規約やユーザーガイドをアプリケーション内で提供したいような場合に WebView を使うと便利です。

Android アプリケーションにおいて、WebView を含んだアクティビティを作ることができ、それをオンラインのドキュメントの表示に使うことができます。

他のシナリオとしては、Eメールのようなデータを取得するためにインターネットの接続を常に必要とするユーザーに大して、アプリケーションがデータを提供するような場合です。

このケースの場合、ユーザーのデータとウェブページを表示するようなアプリケーションなら、ネットワークリクエストを送り、データをパースして Android のレイアウトの中にレンダリングするよりも、WebView を組み込むことのほうが簡単です。

代わりに、Android 用に調整されたウェブページをデザインして、WebView でそのページを読み込むために実装することもできます。

このドキュメントは WebView の使い方と、ページナビゲーションや javascript をウェブページからクライアントサイドコードの結びつける方法を掲載しています。

WebView を実装してみる

イントロダクションはだいたい上記のような感じ。WebView はただウェブページを表示するだけ。コントローラは別途実装する、というような感じ。

ここから、デフォルトの Android プロジェクトがある前提で行います。SDK は 4.0 です。

Adding a WebView to Your Application の項を参考に実装していきます。

まず WebView をレイアウトに追記します。

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

WebView の設置自体はこれで完了です。

onCreate で WebView オブジェクトを使って、URL を開きます。

次に、アクティビティの onCreate で WebView インスタンスとしてレイアウトを生成し、loadUrl() でウェブページをロードさせます。

コード自体はたったの2行です。

public class MyActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        WebView webView = (WebView)findViewById(R.id.webview);
        webView.loadUrl("http://www.google.co.jp/");
    }
}

サンプルでは http://example.com/ を開いていますが、アクセス先でリダイレクトされると標準ブラウザで開いてしまうので、http://www.google.co.jp/ にしました。

最後にインターネットに接続できなければいけないので、AndroidManifest.xml にユーザーパーミッションに以下を追加しておいてください。追加したらデバッグ実行してシミュレータ等でウェブページの読み込みを確認してください。

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

これでデバッグ実行してみて、google が開くかどうかを確認してください。

これが WebView の基本的な使い方です。

Using JavaScript in WebView 和訳

WebView で読み込むウェブページが javascript を使用するなら、WebView の javascript を有効にしなければなりません。
有効にすれば、アプリケーションとウェブサイトの javascript とを取り持つインターフェイスを作ることもできます。

javascript を有効にした実装

WebView オブジェクトから WebSetting オブジェクトを取得して設定します。

WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webView.loadUrl("http://www.google.co.jp/");

javascript が無効の場合にメッセージが出るサイトで試すとわかりやすいでしょう。

執筆時点で http://m.yahoo.co.jp にアクセスすると、わかりやすいメッセージがでたので、読み込みURLをかえてみるといいかもしれません。

WebSetting オブジェクトではユーザーエージェントの設定ができたり、他にもいろいろな設定が可能なので少し目を通しておくと良いかもしれません。

WebView とウェブサイトをつなぐ javascript インターフェイス

ウェブサイトの javascript からクライアントアプリのメソッドを呼び出すインターフェイスが実装できます。

例として、javascript からアプリにたいしてダイアログを表示させてみます。

まず、以下の様なクラスを作ります。

package com.example.DemoWebView;

import android.content.Context;
import android.widget.Toast;

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

この例では、ウェブページからの showToast(“HOGEHOGE”) で、アプリケーションに対して Toast を呼び出します。

WebView オブジェクトにこのクラスインスタンスを渡します。

webView.addJavascriptInterface(new WebAppInterface(this), "Android");

第二引数の “Android” がウェブサイトから呼び出すための javascript オブジェクトの変数になります。

呼び出す側の html コードです。これをどこかサーバに設置して、WebView からアクセスして、ボタンを押してみてください。

アプリ側の Toast が呼び出されます。

<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />
<script type="text/javascript">
    function showAndroidToast(toast) {
        Android.showToast(toast);
    }
</script>

WebView 内に読み込まれたサイトのボタンをタップすると、WebAppInterface クラスに実装したメソッドが呼ばれ、Toast が上がります。

github にアップした html のアドレスを指定すれば動作を確認出来ます。

https://raw.github.com/44uk/DemoWebView/master/doc/index.html

Handling Page Navigation 和訳

WebView 内のリンクをクリックした場合のデフォルトの動作は URL を扱うアプリケーションで処理されます。

大抵の場合、デフォルトのブラウザで開かれます。

しかし、この動作を変更し、WebView 内で表示することも可能です。

WebView によって管理されるページヒストリーで進む/戻るのナビゲーションをユーザに許可することができます。

ページ管理の実装

WebView インスタンスに WebViewClient インスタンスを渡します。

webView.setWebViewClient(new WebViewClient());

これだけで、WebView 内のリンクがすべて WebView 内で処理されるようになります。

ちなみに最初、リダイレクトされると標準ブラウザで開いてしまうというのは、この WebViewClient がセットされていないために、リンクがブラウザで処理されていたということになります。

もしクリックされたリンクについてコントロールしたいなら WebViewClient クラスのサブクラスで shouldOverrideUrlLoading() をオーバーライドして、そのインスタンスを渡します。

以下は、特定のドメインのリンクでなければURLを扱うアクティビティ(大抵は標準ブラウザ)をスタートさせるサンプルです。

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
            // もし自分のサイトじゃなかったらオーバーライドせず WebView で開く
            return false;
        }
        // Otherwise, the link is not for a page on my site, so launch another Activity that handles URLs
        // 自分のサイトドメイン外だったらURLを扱うアクティビティに渡す。
        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
        startActivity(intent);
        return true;
    }
}

WebViewClient によってヒストリー管理されるようになったので、goBack() / goForward() メソッドで戻る/進むを操作することができます。

実装

デバイスの戻るボタンが押下された場合に、WebView を「戻る」サンプルです。

@Override 
public boolean onKeyDown(int keyCode, KeyEvent event) {
    // Check if the key event was the Back button 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() は何もしません。

javascript からメソッド呼び出しできるのはなかなかおもしろそうです。(セキュリティの確保には気を付く必要がありますが)

サンプルのWebページのコードでは、Android という js オブジェクトが当然存在しないので、直接ページを開くとエラーが出ます。

WebView からでしか見せないというなら手を抜けそうですが、その辺もきちんとケアしたいところです。

逆に、WebView から javascript を呼ぶ場合はここが参考になりそう。

loadUrl で javascript: hoge(); のように ページに対して js を呼べます。ブラウザのアドレスバーで呼び出すのと同じです。

デモプロジェクトを github にアップしていますので、良ければご参考に、またツッコミも歓迎です。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする