2001/12/14
ここだけ昔のまま。(--;;
(私にとっては)膨大な情報のため現在修正中です。
NTT DoCoMo 純正の開発環境「J2ME Wireless SDK for the DoJa」の KToolBar を使った開発法です。
ダウンロード
NTT DoCoMoのJavaサイトからSDKをダウンロードします。
http://www.nttdocomo.co.jp/i/java.html
実際に使うにはJDK1.3も必要となります。
http://java.sun.com/j2se/1.3/ja/download-windows.html
ダウンロード後は「JDK1.3」>「SDK」の順にインストールしてください。
使い方
流石に公式ツールらしく「新規作成」したときに「C:\J2MEWSDK4DOJA\apps\プロジェクト名」というフォルダが作成され、
通常のエディタで作成したソース(*.java)をプロジェクト以下の「src」フォルダに、リソースとして扱いたい物は「resフォルダ」に入れて
「アプリケーション属性設定」にJAMの設定を入力すれば、「ビルド」のボタンを押すだけでJAR化&JAM作成までやってくれます。
さらにエミュレータによるテストが簡単にできます。
このエミュレータではSystem.out.println(文字列);とするとKToolBarの
テキストエリアに内容が出力されます。これはデバッグにとても便利です。
また、ネットワークを使ったアプリを実行する場合は「編集>設定」の「読み込み先URL」と「NetworkAccess」を有効にしなければならないので注意です。
JAMの設定内容は非公式版の方をご覧下さい。
iEmulatorを使用する場合 i-JADEを使用する場合 からっぽ実装を使用する場合
iEmualtorを使用する場合
福野さんのiEmulatorで作成したクラスファイルを使って今からすぐできる iアプリ作成法を紹介します。
iEmulatorのダウンロードは 福野氏の iEmulatorのページから。
http://uni.himitsukichi.com/iap/index.html2001/2/5:iEmulator最新バージョンのリリース11ではネットワーク、スクラッチパッドへのアクセスが可能になりました!
以下の内容は release11を対象にしていますのでご注意ください。- ライブラリの作成
実機で動作させるためのライブラリを作成します。
iEmulator release11を解凍した物の中の iEmulatorフォルダ内の com, javax, org フォルダをライブラリにするフォルダ(C:\DoJa\classes)へコピーします。
- MIDP1.0正式版から
C:\midp-fcs\classes にある javaフォルダと comフォルダを先ほどのクラスパス(C:\DoJa\classes)へコピーするだけです。
- J2ME Wireless Toolkit 1.0正式版から
C:\j2mewtk\lib\midpapi.zip を解凍して得た javaフォルダと comフォルダを先ほどのクラスパス(C:\DoJa\classes)へコピーする。
これでクラスパスに設定するライブラリが完成しました。
以下の作業はコンパイルにて。
i-JADEを使用する場合
ゼンテックの i-JADEを利用した開発法です。
http://64.177.67.223/i-JADE/index.html2001/1/31: ゼンテックの方からお許しを頂いたので公開させて頂きます。m(__)m
- ライブラリの作成
i-JADEを使用した開発には i-JADEに付いてくる i-jade-xxx.jarの解凍が必要です。
( i-jade-xxx.jar とは i-jade-p.jarや i-jade-f.jarのことです。)jar.exe xvf i-jade-xxx.jar解凍された com , javax をクラスパスに設定するC:\DoJa\classesなどにコピーします。
もうひとつ必要なパッケージ(java)があるので、それをMIDP1.0正式版、或いは J2ME Wireless Toolkit 1.0正式版から手に入れます。
- MIDP1.0正式版から
C:\midp-fcs\classes にある javaフォルダと comフォルダを先ほどのクラスパス(C:\DoJa\classes)へコピーするだけです。
- J2ME Wireless Toolkit 1.0正式版から
C:\j2mewtk\lib\midpapi.zip を解凍して得た javaフォルダと comフォルダを先ほどのクラスパス(C:\DoJa\classes)へコピーする。
これでライブラリが完成しました。
からっぽ実装を使用する場合
Atsushiさんが公開している「からっぽ実装」を使用した開発法です。
http://www.antun.net/これはその名の通り、中身は空っぽのコンパイル専用ライブラリです。(^^;;
いやぁ、Javaって楽しいですね。(^^;;;;- ライブラリの作成
nullimpl.zipを解凍した物(C:\DoJa\classes)のほかに javaパッケージと com.sunパッケージが必要なため、例によってMIDP1.0正式版、或いは J2ME Wireless Toolkit 1.0正式版から手に入れます。
- MIDP1.0正式版から
C:\midp-fcs\classes にある javaフォルダと
comフォルダをクラスパス(C:\DoJa\classes)へコピーするだけです。- J2ME Wireless Toolkit 1.0正式版から
C:\j2mewtk\lib\midpapi.zip を解凍して得た javaフォルダと
comフォルダをクラスパス(C:\DoJa\classes)へコピーする。2001/3/17: 「からっぽ実装」ではcomフォルダのコピーは必要ありませんでした。
これでライブラリができました。
コンパイル 作成したライブラリをブートクラスパスに指定してコンパイルします。
javac.exe -g:none -bootclasspath .;C:\DoJa\classes test.java-g:none とすることで余分な情報を省くのでクラスファイルが小さくなります。
検証 MIDP1.0或いはJ2MEWTK付属の preverify.exeを使い検証します。
C:\j2mewtk\bin\preverify.exe -classpath .;C:\DoJa\classes testJAR化 JAR化するんですが仕様書を見る限り、 iアプリではマニフェストが入ってないのが普通のようなのでJARのオプションでマニフェストを省きます。
以下のコマンドをpreverifyされたクラスファイルで実行します。
jar.exe cvMf test.jar *.classオプションの cvMf の M はマジでラージMです。(^^;;
JAMの作成 JAM(ADF)は仕様書を見て根気良く書いていきます。(^^;;
ちなみに必須となっているのは「AppName」「PackageURL」「AppSize」「AppClass」「LastModified」です。
サンプルAppName = test PackageURL = test.jar AppSize = 842 AppClass = test AppVer = 0.0 LastModified = Fri, 26 Jan 2001 14:10:12なお実機は iアプリのバージョンアップを LastModifiedをチェックすることにより確認しているようです。
AppVerを変更したからと言ってバージョンアップが使用できるわけでは無いのでご注意を。HTMLの編集 アプリのダウンロードにはHTMLからの指定が必要なので書きます。
サンプル<OBJECT declare id="b" data="http://cgi.sinsen.org/test/test.jam" type="application/x-jam"> test </OBJECT> <A ijam="#b" href="http://www.sinsen.org/">testJAM</A>アップロード 適当なURLにJARファイルとJAM、そしてHTMLファイルをアップします。
ただし、JAMファイルはアスキーモードで、JARはバイナリモードでアップするのをお忘れなく。(^^;;実行 あとは503iシリーズでHTMLを参照し、JAMをクリック>ダウンロード、そして実行です。(^^
お疲れ様でした。(^^;;
2001/4/2: D503iの結果も一部載せました。
ボタン操作方法 SO503iでは十字ボタンにあたる物が「左右ボタン+ジョグ」になっています。
ジョグでのボタン上下イベントはかなり特殊であるということなので注意が必要です。
画面サイズ SO503iではiアプリで使用できる画面サイズ(Canvas#getHeight())が「120 x 120」です。
D503iの画面サイズは「132 x 126」です。P503i、F503i、N503iでは「120 x 130」です。
最小認識時間(?) N503iでベンチマークなどの時間計測をSystem.currentTimeMillis()で実行したところ、最小 100ms単位での計測しかできませんでした。
これはフレームプログラムなどで 100ms以下の結果が欲しい場合に障害になります。なお、P503i、D503iでは 10ms以下まで、F503iでは 10ms単位での計測ができます。SO503iでは 25ms単位のようです。
対応画像フォーマット iアプリでは標準でGIF(アニメーション・透過)が使用できるんですが、P503iではなぜかJPEGも表示できました。(--;; ナゼ?
やり方は普通にGIFをロードするようにJPEGをロードしてやるだけです。
MediaImage mi = MediaManager.getImage("resource:///sample.jpg"); mi.use(); Image image = mi.getImage();同様の方法でPNGもやってみましたが、さすがに表示されませんでした。
2001/2/9: JPEGを表示することで不具合が発生する可能性があるそうです。JPEGを使用することはやめてください!
2001/3/1: 全国のドコモショップにてP503iの不具合を解消するためP503iの交換をしております。
環境変数 AtsushiさんのEnvというアプリを使用して出力された環境変数です。
P503i F503i N503i SO503i D503i microedition.platform Panasonic P503i f50x pdc SO503i D503i microedition.encoding SJIS SJIS 未確認 未確認 SJIS microedition.configuration CLDC-1.0 CLDC-1.0 未確認 未確認 CLDC-1.0 microedition.profiles DoCoMoProfile-1.0 DoCoMoProfile-1.0 未確認 未確認 DoCoMoProfile-1.0 なお、java.version, java.vendor, java.vendor.url, java.home, java.vm.specification.version, java.vm.specification.vendor, java.vm.specification.name, java.vm.version, java.vm.vendor, java.vm.name, java.specification.version, java.specification.vendor, java.specification.name, java.class.version, java.class.path, java.ext.dirs, os.name, os.arch, os.version, file.separator, path.separator, line.separator, user.name, user.home, user.dir は nullでした。
HTMLタグについて まずAタグですが、Pの場合 ijam="#anchor"を href="#anchor"と指定しても iアプリをダウンロードすることができてしまいます。
他に、Objectタグで囲われたテキスト(例えば<Object ..>text</Object>のtext)がPでは表示されませんが、Fでは表示されます。
Fの場合はHTMLのHEADへ入れても表示されてしまうので注意が必要です。
ちなみにPCのIEでは表示されますが、HEADに入れれば表示されません。画面更新について FでJavaによるアニメーション(GIFアニメは未確認)を実行する場合、処理が重いと途中のコマが飛ぶ可能性があります。
Pではアニメーションが飛ぶことはありませんでした。Fでの処理飛びをある程度防止するにはrepaint()をpaint(getGraphics())に変えると良いそうです。<Atsushiさんからの情報
プッシュ音について iアプリ実行時にテンキー(っていうのかな?)を押すと、Pではプッシュ音が鳴ってしまいますが、Fでは鳴りません。
バックライトについて Fでは iアプリ実行時にバックライトがオフになってます。Pでは通常の携帯時と同じように入力があればオンになります。結果、Fでは表示が暗くなってしまいます。
しかし、これはFではバックライトをJavaから操作することができるが、Pではバックライトを操作しても無効になる、或いは消したい時に点灯してしまう可能性があります。画像について ゲームをやるなら画像がどのように表示されるかが大きな問題とされますが、Fではエミュレータで実行したようにGIFそのまま表示されるようです。
しかし、Pでは一部の画像にディザパターンが見えます。(液晶が悪いだけかも?)<液晶が悪いだけみたいです。(--;;GUIについて ボタンを配置する場合、Pだと左につめて配置されますが、Fだと中央に配置されます。
その他 両者に言えることなのですが、Graphics#drawString()などにより文字を描画する際、画面外に文字の一部が出てしまうことがありました。
具体的には文字を画面外の下から上へスクロールさせようとしたところ、文字の下半分などがソフトキーなどに割り当てられている領域に描画され、そのまま表示され続けることがありました。市場最強のへっぽこJava携帯
市場に出ているJava携帯の開発者から見た最悪スペックの姿・・・。(^^;;
画面サイズ SO503i:120 x 120 D503iの「132 x 126」も横長だし・・・ 液晶 P503i,F503i:256色固定パレット P503iはRGB>パレットへの変換も特殊で嫌! ボタン SO503i:ジョグダイアル 操作系が特殊過ぎ! CPU P503i:?MHz 普及率が高いだけに厄介。 描画能力 P503i イメージ描画はF503iが最弱。 ヒープメモリ N503i :96K ナゼに低いかな・・ Timer性能 F503i:100ms単位 F503iは10FPS出ないからいいけどね。 iメロディー D503i フォーマットの関係でD503iだけ動かないことがある。
しかしながら最悪スペックでも動作するアプリは他の機種でも動く可能性が高いわけで・・・。
でも完璧に全部の項目をクリアするのは無理だよね。(^^;;バグ
残念ながらDoJa対応携帯には機種によってバグがあります。それらバグの中にはユーザーを危険にさらしてしまうものも含まれます。
現在発見されているバグ、バグらしき物を紹介します。- P503iのJPEG縮小表示バグ
i-modeサイト或いは通常のWebページに画面サイズ以上のJPEGがある場合、それを縮小して携帯画面に表示するはずが、縮小ルーチンにバグがあったため 携帯電話が落ちてしまいます。
さらに復帰させるとメモリ上に記憶していた「電話帳・着メロ・メール・iアプリ」などが消されているという深刻なバグです。
P503iではiアプリでもJPEGが表示できるのですが、この場合に同様のことが起きるかどうかは分かっていません。が、危険なのでやらない方がいいです。対応策:P503iでJPEGを表示させない
- P503iの4月バグ
これはiアプリ限定のバグです。JAMファイルの最終更新情報「LastModified」に4月「Apr」と設定した場合P503iではエラーが出ます。そして「Apr」ではなく「Apl」と設定した場合、動いてしまいます。
これによりP503iユーザーだけ利用できないアプリが出てきてしまいます。対応策:4月以外の月を指定する。JAMファイルを編集して「3月:Mar」や「5月:May」にしてやれば全機種で動作します。
- SO503iのスクラッチパッドセキュリティホール
SO503iでスクラッチパッドのサイズ設定「SPsize」を0からそれ以上へバージョンアップした場合に、他のアプリの保存領域を確保してしまうバグ。
現在調査中です。対応策:SO503iではバージョンアップしない。
携帯の機能をJavaから扱うためのクラス。標準ではバックライトを制御できる。
バックライト
PhoneSystem.setAttribute(0,1); // オン PhoneSystem.setAttribute(0,0); // オフ
P503i
PhoneSystem.setAttribute(120,1); // バイブレータオン PhoneSystem.setAttribute(123,1); // バックライトオン PhoneSystem.setAttribute(124,0); //入力音オフサウンドオフ?
SO503i
PhoneSystem.setAttribute(64,1); // バイブレータオン PhoneSystem.setAttribute(64,0); // バイブレータオフxucker氏からF503iでのバイブレータ制御方法を教えて頂きました。m(__)m
F503i
PhoneSystem.setAttribute(64,65); // バイブレータオン PhoneSystem.setAttribute(64,64); // バイブレータオフ
と言っても同時発色数とかだけですが。(^^;;
自前描画の減色が上手いこと行かないので実機のパレットがどうなっているか調べてみました。
方法は・・・RGBで塗りつぶされた画面を目視で確認・・・・。(--;;;;;
F503i、P503iともにRGB各色8段階の濃度を持っているようです。
と、言うことは 「512色中(8*8*8=512)256色表示」 と簡単に考えて・・・・いいのでしょうか?(^^;;
流石に全ての状態を目視で確認するのは辛いのでご勘弁を。m(__)m
さかき氏のAPIドキュメントによると「R:G:B=8:8:4=11111111=256色」のようです。
ってか、Graphics#getColorOfRGB(r,g,b)の返り値を見てれば分かったかも・・・・。(--;;;;;
なお、RGBの数値がどの値になったときに色が変わるのかは以下のようになるようです。
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
| P503i | 0 - 18 | 19 - 54 | 55 - 91 | 92 - 127 | 128 - 164 | 165 - 200 | 201 - 237 | 238 - 255 |
| F503i | 0 - 31 | 32 - 63 | 64 - 95 | 96 - 127 | 128 - 159 | 160 - 191 | 192 - 223 | 224 - 255 |
GET、POSTの使用サンプル
String text = "";
HttpConnection con = null;
String url = IApplication.getCurrentApp().getSourceURL();
// GET METHOD SAMPLE
try{
// GET
String request = url + "log.cgi?"+URLEncoder.encode("this is Get text!");
con = (HttpConnection)Connector.open(request,Connector.READ,true);
con.setRequestMethod(HttpConnection.GET);
con.connect();
InputStream in = con.openInputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buf = new byte[128];
int t;
while((t=in.read(buf))!=-1){
out.write(buf,0,t);
}
in.close();
text += new String(out.toByteArray(),"SJIS");
out.close();
con.close();
}catch(ConnectionException ce){
text += ce.toString()+ce.getStatus();
}catch(Exception e){
text += e.toString();
}
// POST METHOD SAMPLE
try{
// POST
con = (HttpConnection)Connector.open(url+"log.cgi",Connector.READ_WRITE,true);
con.setRequestMethod(HttpConnection.POST);
con.setRequestProperty("Content-type","text/plain");
OutputStream out = c.openOutputStream();
out.write("this is POST test!".getBytes());
out.close();
con.connect();
InputStream in = con.openInputStream();
ByteArrayOutputStream out2 = new ByteArrayOutputStream();
byte[] buf = new byte[128];
int t;
while((t=in.read(buf))!=-1){
out2.write(buf,0,t);
}
in.close();
text += new String(out2.toByteArray(),"SJIS");
out2.close();
con.close();
}catch(ConnectionException ce){
text += ce.toString()+ce.getStatus();
}catch(Exception e){
text += e.toString();
}
CGI側:Perlはこんな感じです。
#!/usr/local/bin/perl
require "jcode.pl";
$datafile = "log.txt";
$agent = $ENV{'HTTP_USER_AGENT'};
if(index($agent,"DoCoMo")!=-1){
$method = $ENV{'REQUEST_METHOD'};
$method =~tr/a-z/A-Z/;
if($method eq 'POST'){
read(STDIN,$data,$ENV{'CONTENT_LENGTH'});
}else{
$data = $ENV{'QUERY_STRING'};
}
$data=~tr/+/ /;
$data=~s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
&jcode'convert(*data,"sjis");
$data=~s/\n//g;
open(FP,">>$datafile");
&lock($datafile);
print FP $agent."\t".(&getTime)."\t".$data."\n";
&unlock($datafile);
close(FP);
print "Content-type: text/plain\n\n";
print "Connection True!";
}else{
print "Content-type: text/html\n\n";
print "Error";
}
exit;
sub getTime {
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
if ($year < 90) { $year = "20$year"; }else{$year+=1900;}
return sprintf("%04d/%02d/%02d/ %02d:%02d:%02d",$year,$mon + 1,$mday,$hour,$min,$sec);
}
sub lock {
local($dev ,$ino ,$mode ,$nlink,$uid ,$gid);
local($rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks);
local($lockfile);
$lockfile=$_[0].".lock";
while (-e $lockfile) {
($dev ,$ino ,$mode ,$nlink,$uid ,$gid,
$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks)=stat($lockfile);
if (time()-$ctime>$_[1]) { last; }
sleep(1);
}
open(LOCK,">".$lockfile);
close(LOCK);
}
sub unlock {
unlink $_[0].".lock";
}
画像で余分にファイルサイズを増加させない為にネットからスクラッチへ画像を保存し、それを再ロードするプログラムです。
毎回ダウンロードするわけではなく、一度正常にダウンロードが済めば、その後はスクラッチを直接参照します。
ただしこのプログラムではイメージのサイズと名前が分かっている物とします。
実際に使用する前に、このプログラムを追加する程画像サイズが大きいことを確認してください!(^^;;
扱う画像サイズが小さかったり、合計5Kを超える場合は意味の無いプログラムです。
さらには必ずしも安全なプログラムではないのでご注意。
// 0.gif から 4.gif をロードしてスクラッチへ保存
int[] fileSize = { 250 , 631 , 422 , 851 , 1020 };
Image[] image = null;
boolean loadImages() {
try{
image = new Image[ fileSize.length ];
int p = 0;
for(int i = 0 ;i < fileSize.length ; i++){
MediaImage mi = MediaManager.getImage("scratchpad:///0;pos=" + p );
mi.use();
image[ i ] = mi.getImage();
p += fileSize[ i ];
}
return true;
}catch(Exception e) {
}
return false;
}
void downImages() {
try{
HttpConnection con = null;
InputStream in = null;
OutputStream out = Connector.openOutputStream("scratchpad:///0;pos=0");
String url = IApplication.getCurrentApp().getSourceURL();
byte[] buf = new byte[ 128 ];
for( int i=0 ; i < fileSize.length ; i++ ) {
con = (HttpConnection)Connector.open( url + i + ".gif", Connector.READ , true );
con.setRequestMethod( HttpConnection.GET );
con.connect();
in = con.openInputStream();
int t;
while( ( t = in.read(buf) ) != -1 ){
out.write( buf , 0 , t );
}
in.close();
con.close();
}
out.close();
}catch(Exception e) {
}
}
void prepareImage() {
// 実際に使うのはこんな感じ
if( !loadImages() ) {
downImages();
loadImages();
}
}
ネット上のテキストファイルを入手し、その内容をStringで得るプログラムです。
String text = "";
HttpConnection con = null;
String url = IApplication.getCurrentApp().getSourceURL();
try{
con = (HttpConnection)Connector.open(url+"text.txt",Connector.READ,true);
con.setRequestMethod(HttpConnection.GET);
con.connect();
InputStream input = con.openInputStream();
byte[] buf = new byte[(int)con.getLength()];
input.read(buf);
input.close();
con.close();
text = new String(buf,"SJIS");
}catch(Exception e){
text = e.toString();
}
AppVer アプリのバージョンを設定します。これで携帯から「iアプリ>バージョンアップ」などとして更新できるので
カッコイイ便利です。
バージョンアップにはLastModifiedの更新が必要です。KvmVer KVMのバージョンを指定します。KVM規格のバージョンがあがれば後々必要となってくるでしょう。
AppParam スペースで区切られた複数のパラメータ文字列をアプリに渡すことができます。IApplication#getArgs()で収得できる文字列です。
TargetDevice 対応機種を設定できます。F503i専用とか。
LaunchAt エージェントとしての利用時の起動時間を設定きます。
UseNetwork ネットワークを利用する場合「http」を設定します。
SPsize スクラッチパッドを利用する場合にそのサイズを指定します。
使用ツール PhoneSystemやパレットを調べるために使ったアプリはここにあります。
基本的に自分だけの為に作ったものなので、どえりゃ〜ええかげんです、注意。(^^;;現在P503iにて動作確認をしたプログラムです。 import com.nttdocomo.ui.*; public class test extends IApplication { public void start(){ Canvas c = new Canvas(){ public void paint(Graphics g){ g.drawString("Hello World!",Display.getWidth()/2,Display.getHeight()/2); } }; Display.setCurrent(c); } }