japan.internet.comThe Internet & IT Network
RSS
  • ニュース
  • コラム
  • リサーチ
  • ヘッドライン
  • 特集
  • ブログ
  • プレスリリース
  • 専門チャンネル
  • イベント
  • ランキング
  • ニュースメール
2008年9月5日
文字サイズ文字サイズ小文字サイズ中文字サイズ大
デベロッパー2007年2月20日 09:30

プリプロセッサを使ってJ2MEアプリケーションの移植を自動化する

海外海外internet.com発の記事
  • このエントリーを含むはてなブックマーク
  • この記事をクリップ!
  • Buzzurlにブックマーク
  • Yahoo!ブックマークに登録
  • newsing it!

はじめに

 Javaは理論上は移植可能なので、Javaモバイルアプリケーションを開発するときにも、すべてのJava対応デバイス上で正しく実行されるはずだと思いがちです。ところが、理論上の事柄が大抵そうであるように、これも実際にはうまくいきません。J2MEモバイルアプリケーションはまだ日の浅い技術ですが、多くの開発者は、こうした共通利用の問題がMIDP2.0やJTWIのような新しいイニシアチブによって簡単に解決されることはないだろうと述べています。

 J2MEはグローバルに移植できるとしても、J2MEアプリケーションはそうではないというのが現実です。つまり、バイトコードはすべてのJavaハンドセットで正しく実行されますが、アプリケーションの動作はハンドセットごとに個別に調整しなければならないのです。モバイルデバイスは1200種もありますが、いずれも能力が異なり、MIDPを含めて種々のJavaプラットフォームをサポートしており、またオプションのAPIとオプションのAPIパーツをサポートしています。さらに、これらの実装にはそれぞれ独自のバグもあります(デバイスの特性/特徴の細分化の例については、下記の補足説明を参照)。

 そのため、典型的な開発サイクルでは、移植とテストにかかる時間が全体の40〜80パーセントに上ることになります(実際にどれくらいの比率になるかは、開発者の経験レベルとサポートするデバイスの数によります)。

 移植したモバイルアプリケーションを実際の携帯電話でテストするのは必ずしも簡単なことではありません。よくできたエミュレータを使用すれば、実際のデバイスのバグがすべて再現されるはずですが、常にエミュレータがあるとは限りませんし、たとえあっても決して当てにできるわけではありません。

 バグにはもう1つ難しい問題があります。バグに対処するには、バグをソースコード上で解決するか、不具合のある機能を無効化しなければなりませんが、このような対策がファームウェアのバージョンによってすべて異なるものになる可能性があります。特に厄介なのは、仮想マシンにバグがある場合です。これは、メーカーが仮想マシンをハードウェアレベルでハンドセットに統合する際に問題になります。

 モバイルオペレータは配布されたミッドレットの品質をコントロールする必要があります。なぜなら、低品質のミッドレットはオペレータサービスに影響を与えるからです。オペレータは比較的うまくできている古いミッドレットを新しいデバイスモデルのために交換し、広範に使用できるようにする必要もあります。そのため、開発者はアプリケーションを新しいデバイスにすばやく移植できなければならないのです。

デバイスの特徴の細分化
デバイスの能力
デバイスの能力
Javaプラットフォーム
Javaプラットフォーム
MIDPプラットフォーム
MIDPプラットフォーム
MIDP用のオプションのAP
MIDP用のオプションのAP

移植の自動化は必要か

 一番のポイントは、そのアプリケーションでサポートできるデバイスの数です。これが、自動化という投資の効果を左右する最大の要因になります。移植を自動化することには次のような利点があります。

  • J2MEプロトタイプが使用可能になり、市場化までの時間が短縮される。
  • 単調で退屈な作業が自動化される。
  • さまざまなデバイス仕様に煩わされずにアプリケーションロジックに専念できる。
  • デバイスごとに最適化されたアプリケーションを生成できる。

 まず、各デバイスモデルの特異性を考慮する必要があります。利用できる場合にはいつでもオプションの機能を使用すべきです。デバイスに応じてアプリケーションでサポートすべき機能の例を表1に示します。

表1 デバイスモデルの特異性の例
デバイスが次の条件に当てはまる場合はアプリケーションで次のことを実現する
サウンドをサポートしているサウンドを再生する
アルファブレンディングをサポートしている不透明度に変化をつけてメニューを表示する
.jarファイルサイズの制限がきつい必須でないイメージを削除する
全画面をサポートしている全画面を使用する
十分なヒープメモリがあり、大きな.jarファイルサイズをサポートしているビットマップフォントなどのオプションの機能を使用する
カメラコントロールをサポートしているカメラで撮ったスナップショットを使ってゲームをカスタマイズできる
BluetoothをサポートしているSMSまたはHTTP接続を使用して他のユーザーと通信する(チャットなど)
SMSをサポートしているSMSを使用して現在のアプリケーションをアクティブ化する
PDAPをサポートしているPDAPを使用して内部ギャラリーのイメージにアクセスする
電話をかけられる電話をかける
バックグラウンドでのアプリケーションの実行をサポートしているバックグラウンドでアプリケーションを実行する

内製の移植ソリューション

 アプリケーションの移植を自動化することに決めたら、実際に何をすればよいのでしょうか。もちろん外注することもできますが、自社内でやるつもりなら、基本的に4つの方法の中から選ぶことになります。

  1. デバイスシリーズごとにバージョンを1つずつ作成する
  2. このアプローチは、単に一連のモデル(例えばNokia Serie40 Edition 1)ごとにアプリケーションを開発するというものです。この場合の問題点は、サポートするAPIが多いほど、あるいはアプリケーションでそのデバイスに力点を置くほど、シリーズを細分化することになります。というのも、高度なAPIに対するサポートによってシリーズ内のわずかな差異が際立つからです。例えば、同じような2つのデバイスでも、画面上のイメージの数によってパフォーマンスが大きく違ってきます。
  1. ハンドセットの動的検出
  2. このオプションでは、実行中にアプリケーションをテストします。例えば、モデルがNokiaハンドセットだとすると、アプリケーションは実行中にこのデバイスモデルを検出し、モデルに応じた適切な動作を選択します。
    これで、特定のハンドセットでのみ使用可能なメソッド(全画面モードなど)を呼び出すことができます。それぞれの実装ごとにクラスを作成する必要があります(NokiaCanvasSiemensCanvasStandardCanvas)。次に例を示します。
    try {
       Class.forName("com.nokia.mid.ui.FullCanvas");
       Class myClass = Class.forName("NokiaCanvas");
       myCanvas = (ICanvas)(myClass.newInstance());
    } catch (Exception exception1) {
       try {
          Class.forName("com.siemens.mp.color_game.GameCanvas");
          Class myClass = Class.forName("SiemensCanvas");
          myCanvas = (ICanvas)(myClass.newInstance());
       } catch (Exception exception2) {
          myCanvas = (ICanvas) new StandardCanvas();
       }
    }
    
    基本的にインターフェイス(Icanvas)と3つの実装(Nokiaデバイス、Siemensデバイス、標準MIDPデバイスについて1つずつ)を作成します。
    それからプロプラエタリAPIが利用可能かどうか確認するためにClass.forNameを使用します。例外がスローされなければ、NokiaCanvasを使用します。そうでなければ、現在のデバイスがこのAPIをサポートしていないことになります。その場合は、もう1つのAPI(例えばSiemens)をテストします。もう1つの例外がスローされた場合は、標準キャンバスを使用しなければなりません。
    このソリューションではデバイスの各モデルの動作のロジックを各アプリケーションに組み込むことを想定しているので、すぐに無理がきます。
  1. AOPや拡張Javaのような代替物を使用する
  2. Allen Lauは最近のDevXの記事で、AOPによる細分化問題の解決方法を論じています。彼のアイデアは、アプリケーションロジックを一箇所にまとめ、コードを部分的に追加/削除することでアプリケーションのコードを修正するというものです。
    このアプローチでは、いくつかの問題が解決されますが、アプリケーションの構造をそれぞれのプラットフォームに合わせて修正しなければならないので、結局のところ、もう1つの補足的なソリューションを使用するはめになるかもしれません。なぜなら、アプリケーションを各デバイスモデルに合わせて最適化するのは非常に難しい場合があるからです。オプションのAPIをサポートするときは特にそうです。
    さらに、この方法では各デバイスモデルに合わせてコンテンツ(イメージやサウンドなど)を修正するという問題が解決されません。Java拡張機能を使用すればソースコードを自動的に変換できますが、これは興味深いアプローチであっても、実際には作業量が増えてしまいます。
  1. プリプロセッサを使用する
  2. プリプロセッサを使用すると、条件によってソースコードが自動的にアクティブまたは非アクティブになります。
    例えば、Nokiaデバイスで全画面モードを設定するには、Canvasではなく、FullCanvasを拡張する必要があります。MIDP2デバイスでは、setFullScreenModeを呼び出す必要があります。MIDP1デバイスでは、これは可能でないので、非全画面モードのままです。
    //#ifdef NOKIA
       extends com.nokia.mid.ui.FullCanvas
    //#else
       extends Canvas
    //#endif
       {
     :
     :
    //#ifndef MIDP2
          setFullScreenMode(true);
    //#endif
    
    プリプロセッサによってこのソースコードが処理されるので、ディレクティブを設定します。従って、Nokiaデバイス用のアプリケーションを生成するには次のようにします。
    //#define NOKIA
    
    プリプロセッサは次のものを生成します。
    extends com.nokia.mid.ui.FullCanvas
    {
    
    MIDP2デバイスの場合(//#define MIDP2)は、次のものを生成します。
    extends Canvas
    {
        setFullScreenMode(true);
    
    このソリューションでは、ソースコードの1つの本体を各デバイスにモデルに合わせて修正できます。ディレクティブを含むリファレンスソースコードを開発するだけで済むのです。処理済みファイルに加えられたその他の変更は、次のプリプロセスですべて失われます。
    このソリューションはプリプロセスという古い発想に頼っていますが、いろいろなデバイスモデルへの移植を試みるときに遭遇する問題をすべて解決できる、柔軟性の高い唯一の方法です。

プリプロセッサを使った移植に必要なこと

 ソースコードのバージョンを1つだけにするというのが基本原則です。これがプリプロセスされて、それぞれのデバイスモデルに適合したコードが生成されます。

 留意すべき点を以下に列挙します。

  • それぞれのデバイスモデルの動作を熟知している必要があります。
  • それぞれのデバイスモデルでサポートされているJava機能を知る必要があります。
  • プリプロセスでどんな操作(デプロイメントなど)が扱われるか知る必要があります。
  • プリプロセスではリソース(イメージやサウンドなど)は変換されません。
  • 完全に自動化されたソリューションにする必要があります。パラメータ化したソリューションでは不十分です。
  • 自動化されたコンパイルとパッケージングのプロセスの開発に力を注ぐ必要があります。

 イメージやサウンドなどのリソースを各デバイスモデルの能力に適合させるためには、変換ツールを使う必要があります。イメージの最適化も必要です(例えば、.pngイメージのヘッダーからオプションの情報を取り除いたり、小さなイメージを大きなイメージにまとめたり、各イメージの色の数を減らしたり、リソースをプリロードしたりします)。

 同じ特性や機能や動作を持つ一連のJavaデバイスを作成する必要があるかもしれません。そうすれば、各デバイスモデルに対してではなく、このシリーズに対して1つのアプリケーションを生成できます。このシリーズの機能は、アプリケーションの中で使用したい機能に本質的に依存することになります。使用するオプションの機能が多いほど、細分化の度合いが増大します。

 予期しないリソースを考慮に入れようとすると、アプリケーションの更新が必要になります。例えば、デバイスが大きな.jarファイルをサポートしていて、大きなヒープメモリを持っていれば、アプリケーションのバックグラウンドイメージを格納できます。そうでなければ、イメージは.jarファイルには入れられないので、単純に描画する必要があります。その場合、.jarサイズは小さくなり、ヒープメモリはあまり消費されません。

 モバイルプログラミングでは画面サイズが重要な問題となるので、あらゆる技法を(イメージの動的変換やパッケージング前の変換など)駆使して、イメージサイズを小さくするように努力してください。

 さらに、システムとのやりとりを管理することも大切です。例えば、着信の際にサウンドを中止し、ミッドレットを一時停止するといった具合です。

具体例

 MyGameというゲームを、MIDP1、MIDP2、MIDP1 NokiaUI、MIDP1 Motorolaのデバイスに移植するものとします

 移植手順の概要は次のとおりです。

  1. AntおよびAntennaをダウンロードし、インストールします。
  2. サウンドのためのクラスを作成します。このクラスに各デバイスのサウンドを再生するためのコードを入れます。
  3. 各デバイスモデル(MIDP1、MIDP2、MIDP1 NokiaUI、MIDP1 Motorola)の一連のAntenna XMLファイルを作成します。これらのファイルは次のことを行います。
  4. ソースファイルをプリプロセスし、現在のデバイスに関係する行だけを残します。
  5. ソースファイルをコンパイルし、クラスを事前に検証して、プロジェクトをビルドします。
  6. 移植したミッドレットをテストのためにエミュレータで実行します。

SoundManagerクラスの作成

 SoundManagerクラスには、基本的なサウンドを再生し、バックライトを設定するための命令が含まれます。このクラスは次の汎用デバイスをサポートします。

  • MIDP1
  • このデバイスはサウンドとバックライトをサポートしていないので、メソッドは空になります。
  • MIDP2
  • このデバイスはサウンドとバックライトをサポートしているので、//#ifdef MIDP2//#endifの間のコード行が選択されます。
  • MIDP1 NokiaUIこのデバイスはサウンドとバックライトをサポートしているので、//#ifdef NOKIAUI//#endifの間のコード行が選択されます。
  • MIDP1 Motorolaこのデバイスはバックライトだけをサポートしているので、サウンドを再生するためのメソッドは空になります。

 リスト1にコードを示します。

リスト1 SoundManagerクラス
//#ifdef MIDP2
import javax.microedition.media.*;
import javax.microedition.media.control.*;
import javax.microedition.media.control.ToneControl;
//#endif
//#ifdef NOKIAUI
import com.nokia.mid.sound.*;
import com.nokia.mid.ui.*;
//#endif
//#ifdef MOTOROLA
import com.motorola.multimedia.*;
//#endif
import javax.microedition.lcdui.*;
import java.io.*;

public class SoundManager {

  Display display;

  public SoundManager(Display display) {
    this.display = display;
  }

  public void doLight() {
//#ifdef MIDP2
    display.flashBacklight (duration);
//#endif
//#ifdef NOKIAUI
    try {
      DeviceControl.setLights (0,100);
    } catch (Exception exception) {
    }
//#endif
//#ifdef MOTOROLA
    try {
      Lighting.backlightOn();
    } catch (Exception exception) {
    }
//#endif
  }

  public void doSound() {
//#ifdef MIDP2
    try {
      InputStream is = getClass().getResourceAsStream("music.mid");
      Player audioPlayer = Manager.createPlayer(is, "audio/midi");
      audioPlayer.start();
    } catch (IOException ioe) {
    }
//#endif
//#ifdef NOKIAUI
    Sound sound = new Sound (1000, 100);
    sound.play(1);
//#endif
  }
}

「BUILD.XML」ファイルの作成

 「BUILD.XML」ファイルの中で適切なディレクトリを選択します。これは手作業になるので、デバイスごとにXMLファイルを作成し、それらを保持しておくことが望ましいでしょう。

 MIDP2プロファイルの場合は、「SoundManager.java」ファイルのプリプロセスによって次の出力が生成されます。

import javax.microedition.media.*;
import javax.microedition.media.control.*;
import javax.microedition.media.control.ToneControl;
import javax.microedition.lcdui.*;
import java.io.*;

public class SoundManager {

  Display display;

  public SoundManager(Display display) {
    this.display = display;
  }

  public void doLight() {
    display.flashBacklight (duration);
  }

  public void doSound() {
    try {
      InputStream is = getClass().getResourceAsStream("music.mid");
      Player audioPlayer = Manager.createPlayer(is, "audio/midi");
      audioPlayer.start();
    } catch (IOException ioe) {
    }
  }
}

 MIDP1プロファイルの場合は、次の出力が生成されます。

import javax.microedition.lcdui.*;
import java.io.*;

public class SoundManager {

  Display display;

  public SoundManager(Display display) {
    this.display = display;
  }

  public void doLight() {
  }

  public void doSound() {
  }
}

 デバイスのプロファイルは次の行で選択します。

<wtkpreprocess srcdir="src" destdir="outputsrc" 
  symbols="MIDP2" verbose="false"/>

 Antennaは属性シンボルの内容を取り(この例ではMIDP2)、次のように各ファイルの先頭に//#define MIDP2を挿入します。

//#define MIDP2
//#ifdef MIDP2
import javax.microedition.media.*;
import javax.microedition.media.control.*;
import javax.microedition.media.control.ToneControl;
//#endif
//#ifdef NOKIAUI
import com.nokia.mid.sound.*;
import com.nokia.mid.ui.*;
//#endif
//#ifdef MOTOROLA
import com.motorola.multimedia.*;
//#endif
import javax.microedition.lcdui.*;
import java.io.*;

プリプロセスされたソースコードのビルド

 次にプリプロセスされたソースコードをビルドします。つまり、作成した2つのファイルをコンパイルするわけです。

 .jadファイルの名前とその内容をタグの中で指定します。

<wtkjad jadfile="outputin${midlet.name}.jad"
  jarfile="outputin${midlet.name}.jar"
  name="${midlet.name}"
  vendor="You"
  version="1.0"
  target="">
    <midlet name="${midlet.name}" icon="/icon.png" 
      class="game.${midlet.name}"/>
        <attribute name="MIDlet-Icon" value="/icon.png"/>
    </wtkjad>

 アイコンに対して常に同じ名前を使用するようお勧めします(例:icon.png)。

 ミッドレットをパッケージ化するには、.jarファイルを作成します。.jadファイルに統合するリソースを選択してください。このプロセスの簡単なガイドラインを以下に示します。

  • グラフィックスを画面のタイプごとに分けます(大きな画面、中程度の画面、小さな画面など)。
  • アイコンをサイズごとにサブディレクトリに分けます(res_icon32x32、res_icon16x16など)。
  • サウンドのリソースを分けます(res_midifiles、res_ottfilesなど)。

 次の表2では、右側の欄がコードで、左側の欄がその説明になっています。

表2 プリプロセスされたコードのビルド
表2 プリプロセスされたコードのビルド

「RUN.XML」ファイルの作成

 エミュレータを実行するためには、XMLファイルを作成する必要があります。エミュレータはWTKのディレクトリ「wtklibdevices」にインストールします。WTKに表示されるデバイス名を使用し(デバイスのディレクトリ名)、それを属性デバイスの次の行で指定してください。

<wtkrun jadfile="outputin${midlet.name}.jad" 
  device="DefaultColorPhone"/>

 次の表3では、右側の欄が「RUN.XML」ファイルのコードで、左側の欄がその説明になっています。

表3 「RUN.XML」ファイルのコード
表3 「RUN.XML」ファイルのコード

 この例では、いくつかのデバイスについて基本的なサウンドとバックライトをサポートしています。しかし、実際には、その他の機能(キーボード定数、全画面サポート、画面リフレッシュループ、フレームレートの調整、イメージとサウンドの形式など)もサポートする必要があるでしょう。

完全なプロダクションチェーンへの取り組み

 デプロイメントとテストが非常に重要であることを忘れないでください。デバイスモデルごとに細かな手作業を繰り返さなければならないので、モバイル開発は単調で退屈な作業になりがちです。.jadファイルや.jarの名前をいちいち変更したり、各.jadファイルの内容を修正するといった作業を想像してみてください。あるいは、テストのためのテストWAPサーバへのアップロードが手作業で、300とか400のデバイスについてFTPクライアントを使用しなければならないとしたらどうなると思いますか。

 オプションのAPI(Bluetooth、3D、ファイル接続、SMS、MMSなど)とオプションのAPIパーツ(カメラサポート、オーディオ記録、.jpegなど)をすべて考慮に入れることが望ましいでしょう。デバイスの中により強力な機能を提供できるものがある場合には、すべてのデバイスについて同じアプリケーションを生成し続けるのは避けてください。

 移植は基礎的な問題ですが、最適化され充実したモバイルアプリケーションを生成するうえで大きな障害とはなりません。結局のところ、完全に共通利用できるモバイルアプリケーションは、モバイルデバイスの構造のせいで不可能です。ますます複雑になるソフトウェアを埋め込むというのが世の趨勢であり、従って常に実装で問題が生じることになるのです。

著者紹介

Bruno Delb(Bruno Delb)
フランス語で書かれたJ2MEに関する最初の書籍の著者で、Net InnovationsおよびUnified Mobilesの創始者でもある。Unified MobilesはUMAK(Unified Mobile Application frameworK)に基づいた統一モバイルアプリケーション開発という概念を生み出した。UMAKはマルチプラットフォームアプリケーション(J2ME、DoJa、Webアプレット)の開発を促進する完備したフレームワークである。UMAKはデバイスに関する非常に詳細な知識ベースとJavaテストスイートと生産性ツールスイートと構成エンジンを基にしており、各デバイスモデルの各機能を考慮に入れている。
関連テーマ
最新トップニュース
データメーション
【データメーション】
OSについて気に入らないこと(9月5日)
ベンチャー専門家の目利きブログ「なぜこの企業は伸びるのか?」
【ベンチャー専門家の目利きブログ「なぜこの企業は伸びるのか?」】
「導入期〜成長期へ!一歩一歩と前進を目指す『Annoii(アノイ)』」/maka hou,Inc.(9月5日)
最新テクノロジーの意外な処方箋
【最新テクノロジーの意外な処方箋】
グリッドコンピューティング技術でETに遭遇(9月5日)
Graphic Design Forum
【Graphic Design Forum】
古い Emigre を探して (9月3日)
エンジニアの独り言
【エンジニアの独り言】
データをローカルに保存するWebアプリケーション(8月22日)
デスマーチからの脱却
【デスマーチからの脱却】
30min. iPhoneアプリリリース(8月18日)
最新ハイテク講座
最新ハイテク講座
なぜ勝った? 世界No.1シェアをつかんだ“Windows”(9月5日)
developer.com
developer.com
デザインパターンの使い方: Composite(9月5日)
最新アフィリエイト事例にみる成功の法則
最新アフィリエイト事例にみる成功の法則
コンバージョンレートを高めよう!(9月5日)
百式のネットビジネス研究
百式のネットビジネス研究
ガジェット購入時に将来の買取保証プランを提供する「TechForward」(9月5日)
週刊-サイト別アクセス状況データ
週刊-サイト別アクセス状況データ
ビデオリサーチインタラクティブ調査(月間インターネットオーディエンスデータ)(9月4日)
「IT の耳」
「IT の耳」
【書評】『検索にガンガンヒットさせる SEO の教科書』――SEO テクニックで効果的に PR する(9月4日)
検索エンジンマーケティング
検索エンジンマーケティング
果たしてモバイル SEO は必要なのか?(9月4日)
Eメールマーケティング事情
Eメールマーケティング事情
読者が迷惑メールと認識する時…(9月3日)
日本と韓国のインターネットビジネス最新動向調査
日本と韓国のインターネットビジネス最新動向調査
日本と韓国の動画サイト比較1―現状(9月3日)
SNSをビジネスに活用しよう
SNSをビジネスに活用しよう
「しまじろう」に学ぶ企業内コミュニティの活性化のポイント(9月2日)
海外のインターネットコムアメリカ韓国ドイツトルコ
Copyright 2008 Jupitermedia Corporation All Rights Reserved.http://www.internet.com/