Android で XML と JSON を使用する: 第 2 回 JSON を使用してハイブリッド Android アプリケーションを実現する

JavaScript、JSON、コールバック関数、Android-SDK Java コードを組み合わせて柔軟なモバイル・アプリケーションを構築する

この全 2 回の連載記事では、最近のインターネットで最もよく使われている 2 つのデータ・フォーマット、XML と JSON (JavaScript Object Notation) を Android プラットフォームで処理する場合の手法を探ります。第 1 回では、XML と JSON の基本を説明しました。第 2 回では、Webkit でホストされた JavaScript コードと Android アプリケーションの Java™ コードとの間でデータを交換する方法について詳しく説明します。この記事では極めて有能で柔軟な手法の例として、JSON に焦点を当てます。

Frank Ableson, Entrepreneur, MSI Services, Inc.

W. Frank Ableson は、妻の Nikki と子供たちと一緒にニュージャージー州北部に住む起業家です。モバイル・ソフトウェア、組み込み設計などを専門分野としています。彼は、『Unlocking Android』(Manning Publications、2010年) の著者であり、Linux Magazine のモバイル関連のエディターでもあります。



2010年 8月 24日

この記事に付属のサンプル・コードを実行するには、Android SDK バージョン 1.5 以降および Eclipse をインストールする必要があります。環境を構築する方法についての詳細は、Android Developers Web サイトにアクセスして調べてください。関連するリンクは、「参考文献」に記載されています。

はじめに

技術分野として携帯電話よりも人気がある分野を想像するのは難しいことです。数えきれないほどの携帯電話向けプラットフォームが売り上げや人々の興味という点で業界の頂点を競い合っています。モバイル機器は高度なエンジニアリングの見本ですが、実際にその人気の源となっているのは、モバイル・プラットフォームで使用できる膨大な数のアプリケーションによるユーザー・エクスペリエンスです。特に iPhone、そして Android プラットフォーム搭載機器は、ユーザー・エクスペリエンスの点でビジネス・ユーザーと一般ユーザーの別なくクライアントの心と財布をつかむ争いをしている最新のモバイル機器です。

よく使われる頭字語

  • API: Application Programming Interface
  • CSS: Cascading Style Sheets
  • HTML: HyperText Markup Language
  • IDE: Integrated Development Environment
  • SDK: Software Developer Kit
  • UI: User Interface
  • XML: Extensible Markup Language

モバイル・ユーザーが使用できるアプリケーションの大半は、モバイル開発者によって、各プラットフォーム・ベンダーが提供する主要な SDK を使用して作成されています。モバイル機器の人気と、過去 10 年間にわたって Web の世界の仕事をし続けてきた多数の有能な Web 技術プログラマーたちとの組み合わせは、新しいアプリケーション・モデルの誕生という結果につながりました。それは、Web ブラウザー・インターフェースとネイティブ・モバイル・コンポーネントの両方を利用するハイブリッド・アプリケーションです。iPhone と Android のどちらにもハイブリッド・アプリケーションはありますが、この記事では Android のハイブリッド・アプリケーションと JavaScript および JSON の使用という点に焦点を絞ります。

Android のハイブリッド・アプリケーションは、Android の WebView コントロールにある WebKit エンジンを中心に構築されます。WebView コントロールは、Android プログラマーに対して WebKit の機能を公開するユーザー・インターフェース・ウィジェットです。このコントロールを使用することで、アプリケーション内でリモート Web ページをレンダリングすることも、開発者とユーザーの両方に使い慣れたユーザー・インターフェース・エクスペリエンスを提供することも、さらにはネイティブ Android アプリケーション内で強力かつ柔軟な JavaScript 環境を利用することも可能になります。

ハイブリッド・アプリケーションは多くの場合、WebKit の能力を主にユーザー・インターフェース要素の作成に役立てるために WebView ウィジェットを使用しますが、ハイブリッド・アプリケーションは WebView ウィジェットに HTML を表示するだけのものではありません。ハイブリッド・アプリケーションは幅広い用途に使うことができます。Android SDK に含まれる幅広い機能に HTML、CSS、そして JavaScript といった Web 技術を組み合わせれば、考え得るあらゆることを実現可能なハイブリッド・アプリケーションが作成されます。この記事ではハイブリッド・アプリケーションの概念を具体的なものにするために、AndroidJSON というサンプル・アプリケーションについて詳しく見ていきます。このアプリケーションは、Activity と WebView との間のさまざまなやりとりを実装し、JSON を使用してデータを交換します。このアプリケーションでは JavaScript 計算機という主な機能を例に、WebView がホストする HTML および JavaScript と、Activity との間で行われるさまざまなやりとりの例を示します。

それでは早速、Android アプリケーションに直接組み込まれる WebKit エンジンについて説明します。


Android に組み込まれる JavaScript 計算機

SDK をベースとした Android アプリケーションの大半には、少なくとも 1 つの Activity クラスが実装されます。Activity クラスは基本的に、アプリケーション・ユーザーが体験するユーザー・インターフェース要素を含む画面、またはページです。

Activity はプログラマーが定義した一連のユーザー・インターフェース要素を表示します。ユーザー・インターフェース要素には、例えばボタン、ラベル、テキスト入力ボックス、ラジオ・ボタンのリストなどがありますが、想定されるすべてのアイテムは Android SDK に用意されています。さらにこれらのユーザー・インターフェース要素に加え、WebView と呼ばれる特殊なウィジェットがあります。

この JavaScript 計算機が具体的に示すのは、Activity の Java 環境と WebView の JavaScript 環境との共生関係です。サンプル・アプリケーションは WebView に HTML コンテンツを表示するよう要求するだけではありません。JavaScript 環境に機能を提供するために、実際に Java 環境を接続します。このように 2 つの環境を緊密に統合することで、他に類のないユーザー・エクスペリエンスが可能になります。2 つの環境が接続された後は、各種の機能を実現するために、データは JSON という形で交換されます。記事ではこのすべての機能について詳しく説明しますが、まずは JavaScript 計算機が WebView ウィジェットをどのように利用するのかを見ていきましょう。

アプリケーションの構成に関する詳細に入る前に、このアプリケーションが持つ各種の機能を簡単に説明しておきます。図 1 に、アプリケーションの画面を示します。

図 1. 実行中の JavaScript 計算機のデモ
実行中のJavaScript 計算機のスクリーン・キャプチャー

AndroidJSON と名付けたサンプルのネイティブ Android アプリケーションでは、Activity コンポーネントを使用して画面を定義しています。画面の上半分には従来のユーザー・インターフェース要素があります。具体的には、「TextView」(静的ラベル)、「EditText」(ユーザーが式を入力するテキスト・ボックス)、そして「Simple」、「Complex」、「Make Red」という 3 つのボタンです。Activity には WebView コントロールのインスタンスも 1 つあり、このインスタンスが画面の下半分を表示します。

WebView が画面の下半分に表示するのは、サンプル Android アプリケーションに含まれている HTML ファイル (index.html) です (このファイルは、インターネットからもダウンロードすることもできます)。この Web ページには、見出し、サンプル・テキスト、計算結果、そしてさまざまな機能を実行するための 6 つのボタン (「Log Info」、「Log Error」、「Dynamic」、「How Many Calls」、「History」、「Kill This App」) があります。

このプロジェクトに必要なファイルは、AndroidJSON.java (Android アプリケーション・コード)、index.html (Web ページ)、main.xml (後で説明する UI レイアウト用ファイル) の 3 つです。それぞれのファイルへのリンクについては、「ダウンロード」を参照してください。

まず始めに、Activity に含まれる 3 つのボタンの機能から説明します。

Simple
「Simple」ボタンをクリックすると、「EditText」に入力された内容が数式として評価されます。「EditText」の内容 (式) は WebView コントロールに渡されて JavaScript で評価されることに注意してください。
Complex
「Complex」ボタンは JSON オブジェクトを評価するために、WebView に JSON オブジェクトを送信します。これが複雑 (complex) な機能とされているのは、JSON オブジェクトは送信後に JavaScript コードで解釈され、数学的に操作されるためです。このボタンは、整数の配列の要素を加算する機能と、同じ整数の配列の要素を乗算する機能との間で切り替わります。
Make Red
この 3 番目のボタンは、ほぼ面白半分で追加されたものです。このボタンをクリックすると、スタイルが組み込み WebView のコンテンツに適用されて、<body> タグ内に含まれるテキスト要素が赤色になります。

次に説明するのは、組み込み WebView コントロールによって実行時に有効にされる index.html ファイルに含まれる機能です。

Log Info
このボタンは、エントリーを Info カテゴリーとしてアプリケーション・ログに書き込むために、Android アプリケーションでコールバック関数を呼び出します。
Error Info
このボタンは、エントリーを Error カテゴリーとしてアプリケーション・ログに書き込むために、Android アプリケーションでコールバック関数を呼び出します。
Dynamic
このボタンは、有効な JavaScript コードのテキストを取得するために、Android アプリケーションでコールバック関数を呼び出します。WebView に返されて実行されるこの JavaScript コードに、アプリケーションの両サイドの間で行われるやりとりが記述されています。この手法は、無条件に JavaScript の eval 関数を使用することから、一部のセキュリティー侵害に対して脆弱であることに注意してください。ただし、ここでは本番対応の完全なアプリケーションを作成することに焦点をあてるのではなく、アプリケーションで行われるやりとりの部分に焦点をあてます。
How Many Calls
いずれかのコールバック関数が呼び出されるたびに、カウンターがインクリメントされます。このボタンは、そのカウンターを単純に表示するだけです。
History
いずれかの JavaScript 関数が呼び出されるたびに、その関数名を表すストリングが JavaScript 配列に追加されます。「History」ボタンがクリックされると、この配列が JSON に変換され、Android アプリケーション固有の部分に渡されます。配列は Java コードでオブジェクトとして再構成され、配列の各要素が列挙されてログに書き込まれます。
Kill This App
このボタンも、アプリケーションの単なる面白い機能として追加されています。このボタンがコールバック関数を呼び出すと、finish() の呼び出しよって Android のアクティビティーが強制終了されます。

開発中の多くのアプリケーションと同じく、この Android アプリケーションも Android 内に組み込まれたロギング機能を利用します。この記事に記載するスクリーン・キャプチャーの一部は、LogCat ウィンドウが表示される、Eclipse 内の DDMS (Dalvik Debug Monitor Service) ビューから取得したものです。Android 開発ツールの使用方法についての詳細は、「参考文献」に記載したリンクを参照してください。

アプリケーションの機能についての説明は以上です。次は、ユーザー・インターフェースを組み立てる方法を説明します。


ユーザー・インターフェースの作成

このアプリケーションのユーザー・インターフェースを作成するには、前に紹介した 3 つすべてのファイルが必要です。まずは、レイアウト用ファイルの main.xml から記載します (リスト 1 を参照)。

リスト 1. ユーザー・インターフェースのレイアウト用ファイル、main.xml
<?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"
    >
    <TextView android:layout_width="fill_parent"  
android:layout_height="wrap_content" android:text="@string/title" />
    <EditText android:id="@+id/formula" android:layout_width="fill_parent" 
android:layout_height="wrap_content" android:text="" android:visible="False" />
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">
        <Button android:text="Simple" android:id="@+id/btnSimple" 
android:layout_width="wrap_content" android:layout_height="wrap_content">
</Button>
        <Button android:text="Complex" android:id="@+id/btnComplex"
 android:layout_width="wrap_content" android:layout_height="wrap_content">
</Button>
        <Button android:text="Make Red" android:id="@+id/btnRed" 
android:layout_width="wrap_content" android:layout_height="wrap_content">
</Button>    
    </LinearLayout>
    <WebView android:layout_width="fill_parent" android:layout_height="fill_parent"
 android:id="@+id/calculator" android:layout_weight="1" />
</LinearLayout>

リスト 1 のレイアウトには、さまざまなユーザー・インターフェース要素が含まれていますが、アプリケーションは android:id 属性のおかげでレイアウト内の特定のウィジェットを参照することができます。例えば、WebView には calculatorid が含まれているといった具合です。ただし、TextView の値はアプリケーションのライフタイム全体をとおして変更されることがないため、ここには id が含まれていません。

AndroidJSON.java に含まれる onCreate() メソッドは、リスト 2 のようにレイアウトを拡張します。

リスト 2. ユーザー・インターフェースの作成
public class AndroidJSON extends Activity {
    private final String tag = "AndroidJSON";
    private WebView browser = null;
    private int flipflop = 0;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);


        final EditText formula = (EditText) this.findViewById(R.id.formula);
        final Button btnSimple = (Button) this.findViewById(R.id.btnSimple);
        final Button btnComplex = (Button) this.findViewById(R.id.btnComplex);
        final Button btnRed = (Button) this.findViewById(R.id.btnRed);
    // remaining code removed for brevity - shown in next listings
}

上記では、レイアウトを拡張するために setContentView() を呼び出しています。ユーザー・インターフェース要素を設定するには、findViewById() メソッドを呼び出すことに注意してください。一方、R.java ファイルは、main.xml ファイルが保存されるたびに自動的に生成されます。android:id 属性が含まれるレイアウト要素が、R.id クラス内の値になります (リスト 3 を参照)。

リスト 3. R.java
/* AUTO-GENERATED FILE.  DO NOT MODIFY.
 *
 * This class was automatically generated by the
 * aapt tool from the resource data it found.  It
 * should not be modified by hand.
 */

package com.msi.androidjson;

public final class R {
    public static final class attr {
    }
    public static final class drawable {
        public static final int icon=0x7f020000;
    }
    public static final class id {
        public static final int btnComplex=0x7f050002;
        public static final int btnRed=0x7f050003;
        public static final int btnSimple=0x7f050001;
        public static final int calculator=0x7f050004;
        public static final int formula=0x7f050000;
    }
    public static final class layout {
        public static final int main=0x7f030000;
    }
    public static final class string {
        public static final int app_name=0x7f040001;
        public static final int title=0x7f040000;
    }
}

ボタンを作成するコードについては後で再び取り上げるとして、とりあえずは WebView コントロール、つまりウィジェットを作成するコードに注目してください。ボタンやその他のユーザー・インターフェース要素は比較的単純ですが、WebView にはかなりの作業が必要になります。けれども心配はご無用です。実証済みのカット・アンド・ペースト手法を適用できるケースが多くあることを考えれば、それほど難しい作業ではありません。リスト 4 のスニペットを見てください。これも前述の AndroidJSON.java に含まれる onCreate() メソッドから抜粋したものです。

リスト 4. WebView ウィジェットの作成
        // connect to our browser so we can manipulate it
        browser = (WebView) findViewById(R.id.calculator);

        // set a webview client to override the default functionality
        browser.setWebViewClient(new wvClient());

        // get settings so we can config our WebView instance
        WebSettings settings = browser.getSettings();

        // JavaScript?  Of course!
        settings.setJavaScriptEnabled(true);

        // clear cache
        browser.clearCache(true);

        // this is necessary for "alert()" to work
        browser.setWebChromeClient(new WebChromeClient());

        // add our custom functionality to the javascript environment
        browser.addJavascriptInterface(new CalculatorHandler(), "calc");

        // uncomment this if you want to use the webview as an invisible calculator!
        //browser.setVisibility(View.INVISIBLE);

        // load a page to get things started
        browser.loadUrl("file:///android_asset/index.html");

        // allows the control to receive focus
        // on some versions of Android the webview doesn't handle input focus properly
        // this seems to make things work with Android 2.1, but not 2.2
       // browser.requestFocusFromTouch();

リスト 4 で注目すべき点は、Activity スコープが設定された browser という名前の変数が WebView コントロールに関連付けられていることです。WebView はかなり込み入ったクラスであり、大幅にカスタマイズすることができます。例えば、Web ブラウザーと関連付けられた要求通りの関数を取得するように、いくつかのクラスを作成する必要がある場合を考えてみてください。この作業は、プログラマーが最小限の作業量で有効な関数を取得できるようにしなければならない作業の 1 つです。しかし、どこまでカスタマイズするかには上限がありません。このアプリケーションの場合には、なるべく最小限の WebView コントロールがデプロイされるにとどめておきます。

WebViewClient は、ページのロードの開始および終了、フォームの再送信、キーボードの割り込み操作など、イベント・プログラマーがトラップして操作したいと思うさまざまなイベントをキャプチャーするためのフックを提供します。同様に、WebChromeClient のインスタンスも必要です。このインスタンスによって、非常に役立つ alert() などの JavaScript 関数を使用できるようにします。コントロールに対して JavaScript を有効にするには、WebSettings クラスを使用します。

WebView コントロールをページにナビゲートさせるには、いくつかの方法があります。このアプリケーションでは、プロジェクトのアセットとしてパッケージ化された index.html の完全修飾パスを指定して loadurl() メソッドを使用します。WebView コントロールの作成方法についての詳細は、android.webkit パッケージのオンライン・マニュアルを調べてください (「参考文献」を参照)。index.html ファイルは、アプリケーションに付属のリソースから直接 Webview コントロールにロードされます。図 2 でリソース配下に置かれた assets フォルダーに注目してください。ハイブリッド・アプリケーションで使用する HTML ファイルを保存するには、このフォルダーが最適な場所です (図 2 をテキストで表現したものを見るには、ここをクリックしてください)。

図 2. Eclipse 内でのプロジェクト
Eclipse 内でのプロジェクト

WebView を処理する上で最も重要で、最も興味深い側面はほぼ間違いなく、WebView の JavaScript 環境を Android の Activity コードに接続するという部分です。次は、このステップを行います。


JavaScript インターフェースの接続

次のステップは、Activity 内の Java コードが、WebView が管理する HTML ファイル内の JavaScript コードとやりとりできるようにすることです。そのためには、addJavascriptInterface() メソッドを呼び出します (リスト 4 を参照)。

この関数の引数は、Java クラスのインスタンスと名前空間 ID の 2 つです。このアプリケーションの場合、calc の名前空間を定義し、コードを CalculatorHandler というクラスに実装します (リスト 5 を参照)。

リスト 5. CalculatorHandler の実装
// Javascript handler
    final class CalculatorHandler
    {
        private int iterations = 0;
        // write to LogCat (Info)
        public void Info(String str) {
            iterations++;
            Log.i("Calc",str);
        }
        // write to LogCat (Error)
        public void Error(String str) {
            iterations++;
            Log.e("Calc",str);
        } 
        // sample to retrieve a custom - written function with the details provided 
        // by the Android native application code
        public String GetSomeFunction()
        {
            iterations++;
            return "var q = 6;function dynamicFunc(v) { return v + q; }";
        }
        // Kill the app        
        public void EndApp() {
            iterations++;
            finish();
        }
        public void setAnswer(String a)
        {
            iterations++;
            Log.i(tag,"Answer [" + a + "]");
        }
        public int getIterations()
        {
            return iterations;
        }
        public void SendHistory(String s)
        {
            Log.i("Calc","SendHistory" + s);
            try {
                JSONArray ja = new JSONArray(s);
                for (int i=0;i<ja.length();i++) {
                    Log.i("Calc","History entry #" + (i+1) + " is [" + ja.getString(i) 
+ "]");
                }
            } catch (Exception ee) {
                Log.e("Calc",ee.getMessage());
            }
        }
    }

JavaScript 環境内では、window.calc.methodname 構文を使って CalculatorHandler の各メソッドにアクセスします。一例として、CalculatorHandler は、ストリングの引数を取り、それをアプリケーション・ログに書き込む Info() という名前のメソッドを実装しています。このメソッドに JavaScript 環境からアクセスするには、例えば window.calc.Info("write this string to the application log!"); のような構文を使用します。

Java コードを JavaScript コードから呼び出す基本的な方法がわかったところで、リスト 6 の index.html ファイルを調べて、それぞれのメソッドがどのように呼び出されるかを確認してください。

リスト 6. WebView コントロールでレンダリング (および実行) される index.html
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=0.25,
    user-scalable=yes" />
<title>Android to JavaScript with JSON</title>
</head>
<script language="JavaScript">
var cmdHistory = new Array();
function startup() {
    try {
        window.calc.Info("Starting up....");
        cmdHistory[cmdHistory.length] = "startup";
    } catch (ee) {

    }
}
function PerformSimpleCalculation(formula) {
    try {
        cmdHistory[cmdHistory.length] = "PerformSimpleCalculation";
        var answer = eval(String(formula));
        document.getElementById('data').value = answer;
        window.calc.setAnswer(answer);
    }    catch (ee)     {
        window.calc.Error(ee);
    }
}
function PerformComplexCalculation(andmethod) {
    try    {
        /*
         * argument to this function is a single object with 2 "members or properties"
         * operation: this is a string naming what we want the function to do.
         * array of arguments: this is an array of integers
         * 
         */
        //alert(andmethod.operation);
        //alert(andmethod.arguments.length);
        if (andmethod.operation == "addarray") {
            cmdHistory[cmdHistory.length] = "PerformCompleCalculation-addarray";
            var i;
            var result = 0;
            for (i=0;i<andmethod.arguments.length;i++) {
                result += andmethod.arguments[i];
            }
            document.getElementById('data').value = result;
            window.calc.setAnswer(result);
        }
        if (andmethod.operation == "multarray") {
            cmdHistory[cmdHistory.length] = "PerformCompleCalculation-multarray";
            var i;
            var result = 1;
            for (i=0;i<andmethod.arguments.length;i++) {
                result *= andmethod.arguments[i];
            }
            document.getElementById('data').value = result;
            window.calc.setAnswer(result);            
        }
    }    catch (ee)    {
        window.calc.Error(ee);
    }
}
function dynamicfunction()
{
    try {
        cmdHistory[cmdHistory.length] = "PerformCompleCalculation-dynamic";
        eval(String(window.calc.GetSomeFunction()));
        var result = dynamicFunc(parseInt(document.getElementById('data').value));
        document.getElementById('data').value = result;
    }catch (ee) {
        alert(ee);
    }
}
</script>
<body >
<center>
<h3>Running in Web View :)</h3>
this is some sample text here <br />
<input type="text" id="data" value="starting value"><br />
<button onclick="window.calc.Info(document.getElementById('data').value);">Log
 Info</button>&nbsp;&nbsp;
<button onclick="window.calc.Error(document.getElementById('data').value);">Log
 Error</button><br />
<button onclick="dynamicfunction();">Dynamic</button>
<button onclick="alert(String(window.calc.getIterations()));">How 
    Many Calls</button>
<button onclick="window.calc.SendHistory(JSON.stringify(cmdHistory));">
    History</button>
<button onclick="if (window.confirm('End App?')) window.calc.EndApp();">Kill This
 App</button><br />
</center>
</body>
</html>

リスト 6 の終わりのほうに記載されているボタン・ハンドラーを見てください。基本的に、これらのハンドラーは window.calc 名前空間にある呼び出し側メソッドであり、AndroidJSON.java の CalculatorHandler クラスに実装されます。

リスト 5リスト 6 の組み合わせによって、JavaScript 環境で開始されたコードのやりとりが Java ソース・ファイルで実装される様子が理解できるはずです。その一方、WebView 内で実行するアクションを Activity コードから開始する方法はまだ見えてきていません。

そこで今度は、Java コードの詳細を探ります。


JavaScript コードの挿入

最初に取り掛かる作業は、数式を JavaScript コードに渡して評価させることです。JavaScript が持つ素晴らしい (そして危険な!) 機能の 1 つに、eval() という関数があります。eval() 関数を使用すれば、コードのストリングを実行時に評価することができます。この例では、「EditText」コントロールからストリングを取得し、JavaScript 環境に渡してストリングを評価します。具体的には、リスト 6 に記載する PerformSimpleCalculation() 関数を呼び出します。

リスト 7 に AndroidJSON.java から抜粋したコードを記載します。このコードが、ボタンの選択を処理します。

リスト 7. Java からの PerformSimpleCalculation() JavaScript 関数の呼び出し
  btnSimple.setOnClickListener(new OnClickListener()
  {
       public void onClick(View v) {
         Log.i(tag,"onClick Simple");
         // Perform action on click
         try
         {
            String formulaText =  formula.getText().toString();
            Log.i(tag,"Formula is [" + formulaText + "]" );
            browser.loadUrl("javascript:PerformSimpleCalculation(" + formulaText + ");");
         }
         catch (Exception e)
         {
               Log.e(tag,"Error ..." + e.getMessage());
         }
       }
  });

このメソッドには多数の行がありますが、ここで注目しなければならない行は、browser.loadurl() の行だけです。この行は、javascript:<実行するコード> のフォーマットでストリングを渡します。

上記の JavaScript コードが WebView の現行ページに注入されて実行されます。このようにすることで、Java コードは WebView に定義された JavaScript コードを実行できるというわけです。

「Simple」ボタンの場合にはストリングが渡されますが、これよりも複雑な構造を扱わなければならない場合にはどうすればよいのでしょうか。そこで活躍するのが、JSON です。リスト 8 に、リスト 6 に記載した PerformComplexCalculation() 関数を呼び出す方法を示します。

リスト 8. JSON オブジェクトを渡して複雑な関数を呼び出す方法
btnComplex.setOnClickListener(new OnClickListener()
{
     public void onClick(View v) {
         Log.i(tag,"onClick Complex");
         // Perform action on click
         try
         {
             String jsonText = "";
         
             if (flipflop == 0)
             {     
                 jsonText = "{ \"operation\" : \"addarray\",\"arguments\" :
 [1,2,3,4,5,6,7,8,9,10]}";
                 flipflop = 1;
             } else {
                 jsonText = "{ \"operation\" : \"multarray\",\"arguments\" :
 [1,2,3,4,5,6,7,8,9,10]}";
                 flipflop = 0;
             }
             Log.i(tag,"jsonText is [" + jsonText + "]" );
             browser.loadUrl("javascript:PerformComplexCalculation(" + jsonText + ");");
         }
         catch (Exception e)
         {
             Log.e(tag,"Error ..." + e.getMessage());
         }
         
     }
});

リスト 6 の JavaScript 関数、PerformComplexCalculation を見てください。この関数には引数としてストリングが渡されているのではなく、独自に作成された以下のオブジェクトが渡されています。

  • operation - 処理対象の関数またはプロシージャーの名前
  • arguments - 整数の配列

このオブジェクトには 2 つのプロパティーしか含まれていませんが、より高い要求に応えるためにもっと複雑なオブジェクトにすることもできます。上記の例で PerformComplexCalculation() JavaScript 関数がサポートする操作は、addarray と multarray の 2 つです。これらの操作が呼び出されて処理を完了すると、その結果が window.calc.setAnswer 関数の呼び出しによって Java コードに返されます。これが、Java コードと JavaScript コードの間での双方向のデータ・フローです。

この例では JSON オブジェクトを渡しましたが、経験から言うと、Java コードから返された Java ストリングを処理するときには、Java ストリングを JavaScript ストリングに変換すると役に立ちます。この変換を行うには、String 関数に eval(String(formula)); の形で値を渡します。

JavaScript の eval() 関数は JavaScript ストリングを使用します。JavaScript ストリングに変換しないと、eval 関数は基本的に何も行いません。

多少複雑な例として、WebView で「Dynamic」ボタンが選択された場合のコード・シーケンスを調べるようお勧めします。

これまでに記載したサンプル・コードのまとめとして、最後に JavaScript 環境から Java 環境にストリングの配列を渡す場合について説明します。


JSON オブジェクトの交換

サンプル・アプリケーション (index.html) の JavaScript コードは、ローカル関数呼び出しを cmdHistory というページ・レベルの配列に記録します。関数が呼び出されるごとに、この配列には新しいエントリーが追加されます。例えば dynamicfunction() 関数が呼び出されると、cmdHistory[cmdHistory.length] = "PerformCompleCalculation-dynamic"; のようにして新しいストリングが配列に保存されます。

この手法には何も特別なことはありません。これは単に、ページ・レベルで使用状況のデータを収集するという一例です。このデータを Android アプリケーションのデータベースに保存すれば役に立つでしょうが、Java コードに対しては、このデータはどのようにして返されるのでしょうか。

ストリング・オブジェクトの配列を送信するには、JSON.stringify 関数を呼び出して配列を引数として渡します。stringify 関数ではオプションで、複合オブジェクトの特定のプロパティーのフォーマット設定をカスタマイズすることもできます。このカスタマイズ方法について詳しく調べるには、json.org に記載されている説明を参照してください (「参考文献」を参照)。

図 3 に、アプリケーションを標準的な方法で実行するのに続いて JSON 配列を構文解析した結果、ログに記録された内容を示します。

図 3. JavaScript から送信された JSON 配列の構文解析結果
JavaScript から送信された JSON 配列の構文解析結果のスクリーン・ショット

この例ではストリング・データのみを保存しているので、データをより長いストリングに追加して CalculatorHandler で単純な関数を呼び出すだけで、このハンドラーがストリングを構文解析できることはほぼ間違いありません。一方、アプリケーションで特定の変数の値などの他のデータを追跡しなければならない場合、あるいは特定の関数呼び出しの所要時間を記録してコードのプロファイルを作成するといった場合を考えてみてください。このような複雑なシナリオでは、オブジェクトを記録および交換する機能が関心の的となるはずです。


まとめ

この記事では、Android アプリケーションの Java コードと WebView の JavaScript コードとの間でデータを転送する方法をサンプル・コードで紹介するとともに、WebKit を利用したハイブリッド・アプリケーションに関する概要を説明しました。ハイブリッド・アプリケーションは JavaScript、JSON、コールバック関数、Android-SDK Java コード、そして何よりも重要な要素として開発者の想像力を組み合わせ、柔軟で有能なモバイル・アプリケーションを実現します。


ダウンロード

内容ファイル名サイズ
Article source codeandjson.zip58KB

参考文献

学ぶために

製品や技術を入手するために

  • Android SDK: Android SDK をダウンロードしてください。このサイトでは、API リファレンスや Android に関する最新ニュースも調べられます。この記事の演習には、バージョン 1.5 以降を使用することができます。
  • Eclipse: 最新の Eclipse IDE を入手してください。
  • Android Open Source Project: Android はオープンソースなので、ここからソース・コードを入手できます。
  • JSONLint: このオンライン JSON バリデーターを試してみてください。
  • IBM 製品の評価版: DB2®、Lotus®、Rational®、Tivoli®、および WebSphere® のアプリケーション開発ツールとミドルウェア製品を体験するには、評価版をダウンロードするか、IBM SOA Sandbox のオンライン試用版を試してみてください。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML, Web development
ArticleID=548031
ArticleTitle=Android で XML と JSON を使用する: 第 2 回 JSON を使用してハイブリッド Android アプリケーションを実現する
publish-date=08242010