アットマーク・アイティ @IT@IT情報マネジメント@IT自分戦略研究所QA@ITイベントカレンダー  
 @IT > Master of IP Network > Mobile Connection > HTTP通信とスクラッチパッドへのアクセス
 

DoJaによるiアプリの開発入門(4)
HTTP通信とスクラッチパッドへのアクセス

服部隆志
http://www.sinsen.org/
http://www.ngy1.1st.ne.jp/~takashi/sinsen_index.html
2001/6/19

 

今回のおもな内容
Generic Connectionでネットワーク接続
スクラッチパッドはデータ保存領域
サンプルを作成する
プロジェクト作成
ソースの記述
事前準備とエミュレータ・実機での動作確認
次回はCGIとの連携

 Java対応携帯電話の特徴の1つとして、「ネットワークとの親和性」があります。これは携帯電話自身がネットワークアダプタとしての機能を持っていることと、Java言語の仕様がネットワークの利用を容易に行えるようになっているためです。特にJ2ME CLDC(Connected Limited Device Configuration)環境では、パッケージjavax.microedition.ioにGeneric Connection Framework(以下Generic Connection)という、ネットワークを簡単に扱うための仕様が用意されています。DoJaはJ2ME CLDCをベースに構築されているため、この仕様を使い簡単にそれぞれのネットワークにアクセスすることができます。

 今回は、このGeneric Connectionを利用して、HTTP通信とスクラッチパッドへのアクセスを行うサンプルプログラムを作成します。

  Generic Connectionでネットワーク接続

 Generic Connectionではjavax.microedition.io.Connectorクラスにネットワークを表すURLを与えることで、そのネットワークへの接続(実際はjavax.microedition.io.Connectionインターフェイス)ができます。接続ができたら、InputStreamあるいはOutputStreamを入手し、任意にデータの送受信が可能です。Generic Connectionの仕様では、さまざまなネットワークに対応して通信できるようになっていますが、実際に使用できるネットワークは端末側の実装により制限されます。DoJaでは「HTTP/HTTPS、スクラッチパッド、リソース」が利用可能です。前回はこのリソースにあたるGeneric Connectionを利用して、JARファイル内のメディアリソースを利用しました。なお、JARファイル内のリソースへデータを書き込むことなどは当然できません。

 Connectorクラスに与えるURLは、

プロトコル : 対象へのパス ; オプション

であらわされ、HTTP通信の場合は“http://”で始まる通常のURLを与えることで接続できます。表1に、DoJaでのGeneric Connectionで使用可能なURLの例を記します。

対象 プロトコル パス オプション
HTTP http://hogehoge/image.gif http hogehoge/image.gif なし
スクラッチパッド scratchpad:///0;pos=0 scratchpad 0 pos=0
リソース resource:///image.gif resource image.gif なし
表1 DoJaでのGeneric ConnectionURLの例

 前回は、このURLを「MediaManager#getImage("resourse:///image.gif")」などのように引数として設定しましたが、これはMediaManagerクラス内でGeneric Connectionが使われていることを意味しています。

 ここで「同じGeneric Connectionなら、MediaManagerにHTTPやスクラッチパッドを指定しても動作するのだろうか?」という疑問が出てきます。もちろん、これは可能です。このような汎用性があることがGeneric Connectionの利点といえます。

  スクラッチパッドはデータ保存領域

 スクラッチパッドとは、iアプリから使用できるバイト配列で構成されたデータの保存領域のことで、Generic Connectionで得たInputStream、OutputStreamを使って読み込み/書き込みが可能です。スクラッチパッドで使用できる領域サイズは、JAMファイルのSPsizeで指定されたバイト数によって設定され、実機ではJAMファイルを参照して、各iアプリごとにスクラッチパッド用の領域を確保します。SPsizeに設定できる最大値、すなわちスクラッチパッドの最大領域サイズは、NTTドコモの仕様では5Kbytes(=5120bytes)までとなっていますが、本稿執筆時点(2001年6月16日)で発売されている全機種(P503i、P503iS、F503i、N503i、SO503i、D503i)で10Kbytes(=10240bytes)となっています。しかし、これは携帯機器メーカーの独自設定であり、今後5Kbytesを上限とする機種が出てくる可能性はありますし、大きく設定することでユーザー側の負担も大きくなってしまいます。開発者としては可能な限り少なくなるよう努力するべきでしょう。

 また、Generic ConnectionのURL表示では“scratchpad:///0”までが固定され、それ以降の“;pos=0”という部分でバイト配列のオフセットが指定できるようになっています。例えば、“scratchpad:///0;pos=64”と指定した場合にInputStreamを得ると、そのInputStreamで入手される最初の値は保存領域の64bytesからの値となります。

注:SO503iには、iアプリのバージョンアップ時にSPsizeを以前より多く設定した場合、増加した分だけほかのiアプリに設定されている領域から確保してしまう欠陥がありました。これによりほかのiアプリで使用している重要な情報が盗まれたり、使用不能に陥る可能性が指摘されています。そのため、2001年6月12日より回収・交換が始まった(NTTドコモのリリース)。

 

  サンプル作成

 では、実際にHTTP通信とスクラッチパッドを利用したサンプルプログラムを作ってみます。内容は、Panel型アプリを使い、HTTP通信によってGIFイメージをダウンロードし、それをスクラッチパッドへ書き込み、最後にMediaManagerにスクラッチパッドのURLを指定してPanel上にイメージを表示するというものです。「MediaManagerにGIFファイルのURLを指定してやればすぐなのにどうして?」と思われるかもしれませんが、今回はGeneric Connectionに慣れるためのサンプルなので、このような複雑なサンプルにしてみました。これを応用すれば10KbytesというJARファイルサイズ制限の対策にもなります。

 また、1つのIApplicationで2つのPanelを使い、その切り替えもやってみたいと思います。

■プロジェクト作成

 まず、これまでと同じようにDoJaを起動して新規プロジェクト「GCTest」を作成し、アプリケーション属性設定でAppNameとAppClassを設定します。ただし、今回はネットワークとスクラッチパッドを使用するためにUseNetworkSPsizeの設定が必要となります。UseNetworkにhttpを、SPsizeにはスクラッチパッドに保存するデータ容量をバイト単位で設定します(図1)。今回の場合は、Panelに表示したいGIFファイルの最大のファイルサイズより大きい値を設定する必要があります。

図1 アプリケーション属性設定でSPsizeとUseNetworkを設定する

■ソースの記述

 メモ帳などのテキストエディタを使ってリスト1のソースを記述後、GCTest.javaとして保存し、先ほど作成したプロジェクトのsrcフォルダ(C:\J2MEWSDK4DOJA\apps\GCTest\srcなど)に移してください。

import com.nttdocomo.ui.*;
import com.nttdocomo.io.*;
import javax.microedition.io.*;
import java.io.*;

public class GCTest extends IApplication implements SoftKeyListener,ComponentListener {

  Panel panel1 = null, panel2 = null;
  Button button = null;
  TextBox url_text = null;
  TextBox result_text = null;

  ImageLabel imageLabel = null;

  String error = "";

  public void start(){
    PhoneSystem.setAttribute(PhoneSystem.DEV_BACKLIGHT,
PhoneSystem.ATTR_BACKLIGHT_ON);

    panel1 = new Panel();
    panel1.setTitle("GCTest");
    panel1.setSoftKeyListener(this);
    panel1.setSoftLabel(Frame.SOFT_KEY_1,"終了");
    panel1.setSoftLabel(Frame.SOFT_KEY_2,"切替");

    panel1.setComponentListener(this);

    url_text = new TextBox("image.gif",18,1,TextBox.DISPLAY_ANY);
    panel1.add(url_text);

    button = new Button("実行");
    panel1.add(button);

    result_text = new TextBox("no error",18,10,TextBox.DISPLAY_ANY);
    panel1.add(result_text);

    panel2 = new Panel();
    panel2.setTitle("イメージパネル");
    panel2.setSoftKeyListener(this);
    panel2.setSoftLabel(Frame.SOFT_KEY_1,"終了");
    panel2.setSoftLabel(Frame.SOFT_KEY_2,"切替");

    imageLabel = new ImageLabel();
    panel2.add(imageLabel);

    Display.setCurrent(panel1);
  }

  public void componentAction(Component source,int type,int param){
    if(type==ComponentListener.BUTTON_PRESSED){

      Image image =null;
      error = "";

      imageLabel.setImage(null);

      // HTTPでデータをダウンロード
      byte[] data = getBytesFromHttp(url_text.getText());

      if(data!=null){

        int offset = 0;
        // データをスクラッチパッドへ書き込み
        writeToScratchpad(data,offset);

        // スクラッチパッドからイメージを作成
        image = getImageFromScratchpad(offset);
      }

      if(image!=null){
        imageLabel.setImage(image);
      }

      if(!error.equals("")){
        result_text.setText(error);
      }else{
        Display.setCurrent(panel2);
      }
    }
  }

  byte[] getBytesFromHttp(String url){
    if(!url.startsWith("http://")){
      url = getSourceURL() + url;
    }

    HttpConnection http = null;
    InputStream in = null;
    byte[] data = null;

    try{
      http = (HttpConnection)Connector.open(url,Connector.READ);
      http.setRequestMethod(HttpConnection.GET);
      http.connect();

      int contentLength = (int)http.getLength();
      in = http.openInputStream();

      data = new byte[contentLength];
      in.read(data);

    }catch(ConnectionException ce){
      error += ce.toString()+"\n";
      error += "status = "+ce.getStatus()+"\n";
    }catch(Exception e){
      error += e.toString()+"\n";
    }finally{
      try{
        if(in!=null){
          in.close();
          in = null;
        }
        if(http!=null){
          http.close();
          http = null;
        }
      }catch(Exception e){
        http = null;
        in = null;
      }
    }

    return data;
  }

  void writeToScratchpad(byte[] data,int offset){
    OutputStream out = null;

    try{

      out = Connector.openOutputStream("scratchpad:///0;pos="+offset);
      out.write(data);

    }catch(ConnectionException ce){
      error += ce.toString()+"\n";
      error += "status = "+ce.getStatus()+"\n";
    }catch(Exception e){
      error += e.toString()+"\n";
    }finally{
      try{
        if(out!=null){
          out.close();
          out = null;
        }
      }catch(Exception e){
        out = null;
      }
    }
  }

  Image getImageFromScratchpad(int offset){
    Image image = null;
    try{
      MediaImage mi = MediaManager.getImage("scratchpad:///0;pos="+offset);
      mi.use();
      image = mi.getImage();
    }catch(Exception e){
      error += e.toString()+"\n";
    }

    return image;
  }

  public void softKeyPressed(int key){
    if(key==Frame.SOFT_KEY_1){
      terminate();
    }
    if(key==Frame.SOFT_KEY_2){
      if((Display.getCurrent()).equals(panel1)){
        Display.setCurrent(panel2);
      }else{
        Display.setCurrent(panel1);
      }
    }
  }
  public void softKeyReleased(int key){
  }
}
リスト1 HTTP通信とスクラッチパッドを利用したサンプルプログラム(GCTest.java

■事前準備とエミュレータ・実機での動作確認

 ソースの記述後、ビルドが正常に終了したら、エミュレータで動作確認をします。今回はネットワーク上のGIFファイルをダウンロードするという動作が行えるかどうかをエミュレータで確認するので、事前にGIFファイルをネットワーク上の適当なサーバに用意しておく必要があります。また、エミュレータ側にもネットワークの設定が必要となります。「編集>設定」から「エミュレータの設定」というダイアログが表示されます。そこの「読み込み先URL」に先ほど準備しておいたGIFファイルがあるURLを、「NetworkAccess」を「enable」に設定してください。この設定によりエミュレータでのネットワーク動作確認が可能となります。

図2 エミュレータの設定ダイアログでGIFファイルの読み込み先を設定する画像をクリックすると拡大表示します

 なお、ネットワーク、スクラッチパッド関係はDoJaの中でも特にエラーが出やすい部分です。今回は例外が発生した場合、画像の表示はせず、例外の内容をTextBoxに出力するようにしました。特にcom.nttdocomo.io.ConnectionExceptionが発生した場合は、ConnectionException#getStatus()で例外の種類が分かる数値を得ることができます。正常に動作しなかった場合は、得た数値を「iモード対応Javaコンテンツ開発ガイド(APIリファレンス編)1.0版」のConnectionExceptionフィールド一覧で調べて、原因を突き止めてください。

 また、エミュレータのHTTP通信ではUserAgentが一切送られないため、サーバの設定によってはHTTPエラー(ConnectionException#getStatus()でいうと10)が発生することがあります。残念ながら、こういったサーバでは、DoJa付属のエミュレータを使ったネットワーク機能は使えません(ただし、こういったサーバでも実機での動作には支障ありません)。ほかのサーバが使用できる場合は、そちらを使用してください。

 エミュレータでの正常動作が確認できたら、実機での動作確認をしましょう。どうでしょうか、正常に動作しましたか?

図3 エミュレータでの実行画面画像をクリックすると拡大表示します

 

  次回はCGIとの連携

 今回はネットワークからGIFファイルをダウンロードしてみましたが、次回はネットワークはネットワークでも、CGIとの連携を紹介したいと思います。

「連載 DoJaによるiアプリの開発入門」


 


 
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

   
@ITトップMobile Connectionフォーラム トップ会議室利用規約プライバシーポリシーサイトマップ