One Note Jam

Java ME開発・ProGuardをWindows環境で使用する際の注意点 (2006-12-31)

忘れないうちに備忘録として書いておきます。

要旨

  • ProGuardをWindows環境で使用する場合、"-dontusemixedcaseclassnames"オプションを使用するのが無難。
    • そうしないと、クラスファイル数が26を超えた場合に出力jarファイルが不正になる。
  • ProGuardを「J2ME Wireless Toolkit」から使用する場合、ProGuardに詳細なオプションを渡すためには「スクリプトファイル」が必要。
    • ただし、プロジェクトごとにスクリプトファイルを作成する必要があるため、面倒かつ忘れやすい。
  • ProGuardへ固定のオプションを常に指定したい場合、ProGuard自体のデフォルトオプションを変更してしまう方法もある。
    • その場合は、proguard.jar内のオプション設定ファイル"proguard/wtk/default.pro"を変更して、proguard.jarを作成しなおす必要がある。

前置き

容量制限の厳しいJava ME開発では、obfuscator(難読化ツール)を使用したjarアーカイブの容量削減が常套的に行われています。obfuscatorとは、元々は逆コンパイル対策のために、識別子を短くして逆コンパイル後のソースコードを読みにくくするためのツールですが、その結果としてクラスファイルのサイズが小さくなるという効果があります。

個人的には、いまどき容量削減についてはあまり考えないで開発をしていますが、obfuscatorによる容量削減は手間もかからないので行うようにしています。その際には、ProGuardというobfuscatorを使用しています。

ProGuard
http://proguard.sourceforge.net/

ところで私の場合、MIDletを開発する際の開発環境として、普段はEclipseを使用しています(EclipseMEというMIDP開発用プラグインを導入済み)。しかし、リリース用のバイナリを作成する際には、なるべくトラブルを避けるため、標準開発環境である「J2ME Wireless Toolkit」を使用するようにしています。いずれの環境にしても、obfuscator(ProGuard)を使用してのパッケージ作成を標準でサポートしているので、ProGuardの詳細を意識せずとも、簡単に使うことができます。

トラブル発生

ところが、以前「Rev.2」の開発中に、ProGuardがらみのトラブルに見舞われました。開発も終わりが見え始めた頃、リリース用のバイナリを作成するために「J2ME Wireless Toolkit」でリビルドを行いました。ところが、KToolbarのメニューから「Package→Obfuscated Package」を選択すると、以下のようなエラーメッセージが出力されて、パッケージ作成に失敗してしまいました。

Error preverifying class A
com.sun.kvem.ktools.ExecutionException: Preverifier returned 1

    Class loading error: Wrong name

ちなみに、Eclipseで「Create Obfuscated Package」を選択した場合だと、難読化されたjarファイルが問題なく作成できます。

オプション指定であっさり解決か?

ProGuardのウェブサイトを調べると、エラーメッセージで「InvalidClassException」「class loading error」「verification error」などが出た場合の対処方法が載っていました。

Troubleshooting - Problems while preverifying for J2ME
http://proguard.sourceforge.net/manual/troubleshooting.html#preverifying

If you get any such message from the preverifier, you are probably working on a platform with a case-insensitive file system, such as Windows. The preverify tool always unpacks the jars, so class files with similar lower-case and upper-case names overwrite each other. You can use ProGuard's -dontusemixedcaseclassnames option to work around this problem.

以下、適当な訳:

もしpreverifierからこのようなメッセージが出た場合、おそらく大文字/小文字を区別しないファイルシステムのプラットフォーム(例えばWindows)の上で実行しようとしているのだろう。preverifyツールは常にjarファイルを展開するので、同じ名前で大文字/小文字のクラスファイルは、互いに上書きされてしまう。これは、ProGuardの"-dontusemixedcaseclassnames"オプションを使用することで、この問題を回避できる。

要するに、クラスファイルの数が多すぎた(26個を超えた)ことにより、リネーム後のクラスファイル名として"a.class"〜"z.class"の次に"A.class"が使われてしまったため、いったんファイル上に展開した際に上書きされてしまって不正な状態になったということのようです。この"-dontusemixedcaseclassnames"オプションを指定することで、同じ名前で大文字/小文字だけ異なるクラスファイルを作成しないようになるようです。

というわけで、この"-dontusemixedcaseclassnames"オプションを指定してやれば問題解決、と思ったのですが……。

どうやってオプション指定を行うのか?

KToolbar上で「Package→Obfuscated Package」を実行するとProGuardが起動することについては前述しましたが、ProGuardに渡すオプションをどうやって設定すればいいのでしょうか? いろいろ調べたところ、以下の文書が参考になりました。

FAQ - Obfuscation, Classes and FileSystems
http://developers.sun.com/techtopics/mobility/midp/questions/wtk-proguard/

この文書に書いてある方法によると、以下の手順でProGuardに渡すオプションを指定できるとのことです。

  • まずは、ProGuard用の「スクリプトファイル」を生成する。一度KToolbar上で「Package→Obfuscated Package」を実行すると、KToolbarが"MIDlet名.pro"という名前のスクリプトファイルをMIDletのベースディレクトリに生成するので、これをスクリプトファイルの元ネタにすればよい。
  • そのスクリプトファイルに、ProGuardのオプションである"-dontusemixedcaseclassnames"を追記する。
  • MIDletのベースディレクトリに、そのスクリプトファイルを別名で保存する。
  • "wtklib\Windows\ktools.properties"ファイル内に、"obfuscate.script.name: スクリプトファイル名"というプロパティを追加する。

このとき、"obfuscate.script.name"に指定するスクリプトファイルは、ファイル名のみを記載する必要があるようです(ディレクトリパスを記載しないようにする)。

これで無事にobfuscatorを使用することができるようになったわけですが、この方法の場合、新しいプロジェクトを作るたびにスクリプトファイルを新しく作ってやる必要があります。これはちょっと面倒ですし、つい忘れてしまいそうです。

ProGuardのデフォルト設定自体を変えてしまう

何か他によい方法はないかとProGuardのマニュアルを探していたら、以下の文書を見つけました。

ProGuard Manual - J2ME Wireless Toolkit Integration
http://proguard.sourceforge.net/manual/wtk.html

つまるところ、こういうことのようです。

  • 「J2ME Wireless Toolkit」には、ProGuardを使うためのプラグインが最初から組み込まれている。
  • それとは別に、ProGuard自身もプラグインとして使うことができる。その場合、"wtklib\Windows\ktools.properties"ファイルを下記のように変更すればOK。
obfuscator.runner.class.name: proguard.wtk.ProGuardObfuscator
obfuscator.runner.classpath: bin\\proguard.jar
  • ProGuard自身をプラグインとして使用する場合、proguard.jar内部の設定ファイル"proguard/wtk/default.pro"を変更することで、ProGuardの設定をカスタマイズできる。

この方法ならば、ProGuardのオプションを恒久的に設定することができそうです。

proguard.jarの改造手順

jarファイルの圧縮・展開には、JDKのツールの一つ"jar.exe"を使用します。

まずはproguard.jarの中身を展開します。

jar xf proguard.jar

展開されたファイルから、"proguard\wtk\default.pro"というファイルを探して、"-dontusemixedcaseclassnames"の一行を追加します。

その後、新しく"proguard_new.jar"という名前で、再度アーカイブします。

jar cfm proguard_new.jar META-INF/MANIFEST.MF proguard/

これで改造完了です。後は、この"proguard_new.jar"を、元の"proguard.jar"という名前にリネームした上で、"\WTK22\bin\"以下に上書きコピーします(オリジナルのproguard.jarは、どこかにバックアップを残しておくのが無難です)。

posted at 2006-12-31 | Permalink

MIDlet版(& iアプリ版)「Rev.2」公開 (2006-10-28)

Rev.2 タイトル画面

MIDlet版(& iアプリ版)の「Rev.2」を公開しました。変則的な盤面でのリバーシゲームです。2年前に作成した「変則リバーシ Rev.」のバージョンアップ版です。

MIDlet版 & iアプリ版「Rev.2」
http://end.skr.jp/rev2.html

開発のきっかけ

少し前に、S60 3rd Edition上での開発についていろいろ調べていたわけですが(2006-06-30)、 3rd Edition(というよりSymbian OS v9)開発の敷居の高さや、2ndと3rdの互換性の無さ、また、804NKのインストール制限(2006-08-31)の話などもあり、今ひとつやる気がなくなっていました。

そこでふと、お手軽なMIDPでの開発というのもいいかもな、と気が向いて、何か作ってみたくなりました。MIDlet(MIDP仕様で作成したアプリケーション)であれば、2nd Editionだろうが3rd Editionだろうが動きますし、それどころか世界中のMIDP対応端末でも動きます(実際には細かい動作の違いなどの問題はあるでしょうけど)。私が現在使っている「WX310SA」がMIDP2.0対応であるというのも理由のひとつです。

移植のつもりが、作り直しに

手始めに、以前作成したiアプリ「変則リバーシ Rev.」をMIDletに移植してみることにしたわけですが、けっこう手間がかかってしまいました。原作を開発していた際は、一応それなりにポータブルなソースコードを書くように心がけてはいたのですが、意外にDoJaに依存したつくりになっていて、広範囲に渡って手直しが必要な状態でした。そこでこれを機に、ゲームのコアとなる部分をPure Javaで書いて、(MIDP・DoJaなどの)環境に依存した部分をきっちり分離するようにリファクタリングしてみました。

これでMIDP環境でもゲームが一通り動作するようになったので、さっそく自分が使っている端末にインストールして、主に移動中の空き時間を利用して動作テスト(と称して遊んでいただけですが)を行いました。そうやって実際に自分で遊んでみると、不便なので改良したい点がいろいろと出てきます。まず真っ先に、ゲーム途中で中断した後、次回起動時に中断したところから再開できる機能を追加しました。それと、返せる石の数を盤面のマス上に表示するようにしてみたり。その他、細かい部分についてもいろいろ追加・変更を行いました。

そういうわけで、結局ほぼ完全に作り直しに近い状態になってしまったため、タイトルも「Rev.2」と変更しました。まあ、内部的には作り直しではあるものの、外から見ると大差ないにもかかわらず「2」というのはどうかとも思いますが、「Rev. Revision 2」の略で「Rev.2」ということでひとつ。

また、iアプリ版の「Rev.2」も用意してあります。リファクタリングしたおかげで、環境に依存する部分を最小限にすることができたので、マルチプラットフォーム化も簡単です。残念なことに、機能追加によってjarファイルのサイズが30KBytesを超えてしまったため、900iシリーズのみの対応となります。

スクリーンショット

Rev.2 盤面選択画面 16種類の盤面を選択できます。

Rev.2 ゲーム画面 最高レベルの「LV6-CPU」は、高速な端末での実行をおすすめします。

Rev.2 ゲーム画面 ゲームを中断した場合でも、再起動時に続きから再開できます。

posted at 2006-10-28 | Permalink

S60開発・設定リストのスライダ設定アイテムをカスタマイズ(2) (2006-10-26)

前回の記事(2006-10-17)の続きです。

グラフィック表示を文字表示に

設定リストにおける「スライダ設定アイテム」は、デフォルトのままだと設定リスト上でもスライダのグラフィックが表示されます。

スライダによるグラフィック表示

このようなグラフィック表示は、直感的にわかりやすい表示方法ではありますが、正確な値を知りたい場合には不便です。こういった場合、以下のように設定値を文字(数字)で表示させるようにすると、正確な値が一目でわかるようになるので便利です。

数字による文字表示

このように、設定リスト上の表示をカスタマイズする方法について、以下に説明します。

ヘッダファイル

設定リスト上の表示をカスタマイズする場合は、S60標準のスライダ設定アイテムクラス(CAknSliderSettingItem)を継承して、デフォルトの動作をオーバーライドして変更する必要があります。以下に、派生クラス(ここではCMySliderSettingItemという名前にしました)の定義例を示します。

class CMySliderSettingItem : public CAknSliderSettingItem
    {
public:
    CMySliderSettingItem(TInt aIdentifier, TInt& aExternalSliderValue);
    virtual ~CMySliderSettingItem();

public:
    // from CAknSliderSettingItem.
    const TDesC& SettingTextL(void);

private:
    // from CAknSliderSettingItem.
    CFbsBitmap* CreateBitmapL(void);

private:
    TBuf<32> iLabelText;
//  (以下略)
    };

ソースファイル

オーバーライドする必要があるメンバ関数は、SettingTextL()とCreateBitmapL()の2つです。

SettingTextL()
const TDesC& CMySliderSettingItem::SettingTextL(void)
    {
    _LIT(KFormat, "%d秒");  // サンプルなので、ソース内に直書き
    iLabelText.Format(KFormat, InternalSliderValue());

    return iLabelText;
    }

設定リスト上に表示したい文字列を戻り値として返すように実装すればOKです。上の例の場合、InternalSliderValue()にて現在のスライダの値を取得して、その値に単位「秒」を付加した文字列を返す実装になっています。結果として、設定リスト上には「5秒」といった文字列が表示されることになります。

CreateBitmapL()
CFbsBitmap* CMySliderSettingItem::CreateBitmapL(void)
    {
    return NULL;
    }

常にNULLを返すように実装すれば、設定リスト上のグラフィックは消えます。

CreateBitmapL()関数は、設定リスト上に表示するビットマップを返すメンバ関数です。S60標準のスライダ設定アイテムや音量設定アイテム(CAknVolumeSettingItem)では、このメンバ関数でスライダやボリュームのグラフィックを表示するように実装されているようです。なので、常にビットマップとしてNULLを返すように実装し直すことで、設定リスト上のグラフィックが消えるわけです。

ちなみに、CreateBitmapL()をオーバーライドしないでSettingTextL()のみオーバーライドした場合、標準のCreateBitmapL()内の処理でスライダのグラフィックが表示されて、その上に、オーバーライドしたSettingTextL()内の処理で文字列が表示されることになります。

posted at 2006-10-26 | Permalink

S60開発・設定リストのスライダ設定アイテムをカスタマイズ(1) (2006-10-17)

数値に単位をつけたい

設定リストにおける「スライダ設定アイテム」は、一定範囲内の数値を入力させる際などに有用なコントロールです。しかし、デフォルトのままでは何かと使いづらい点があるので、カスタマイズしてみます。

まずはこちら。

スライダ(単位なし)スライダ(単位あり)

デフォルトのままだと、現在のスライダが示す数値がそのまま表示されますが、この数値に単位をつけて表示してみました。

リソースファイル

この程度の変更であれば、ソースコードには手を入れずに、リソースファイルの修正のみで可能です。

RESOURCE SLIDER r_getpixels_slider_delaytime
    {
    layout = EAknSettingsItemSliderLayout;
    minvalue = 0;
    maxvalue = 60;
    step = 1;
    valuetype = EAknSliderValueBareFigure;
    minlabel = "0秒";
    maxlabel = "60秒";
    valuelabel = "%U秒";
    }

重要なのは、"valuelabel"フィールドです。見てのとおり、ここでの"%U"という文字列の部分に、現在のスライダが示す数値が入った状態で表示が行われるようになります。

(なお、上記例はあくまでサンプルなので、各種フィールドに文字列リテラルを直接埋め込んでいますが、本来ならばローカライズ等を考慮して、文字列リテラルは別ファイルにて定義するべきです)

posted at 2006-10-17 | Permalink

「GetPixels」(一応)完成版 (2006-10-10)

今更ながら……

以前の記事(2006-03-13)にも書きましたが、以前から開発を進めていた――というより開発が凍結していたS60用画面キャプチャアプリケーションの「GetPixels」ですが、今更ながら(一応)完成しましたので置いておきます。今更ながらS60 2nd Editionのみの対応なので、804NK(Nokia N71)などの3rd Edition端末では使用できません。

GetPixels for S60 2nd Edition
http://end.skr.jp/getpixels.html

実のところ、現在では画面キャプチャアプリケーションとして「Screenshot for Symbian OS」という優れたアプリケーションがあるので、あんまり存在意義がなかったりします。

Screenshot for Symbian OS
http://www.antonypranata.com/screenshot/

「Screenshot for Symbian OS」はS60 3rd Editionにも対応しており、しかも「Symbian Signed」のアプリケーションなので、インストール制限の厳しい804NKにもインストール可能です。3rd Editionへの対応というのもけっこう手間のかかる作業ですが、Symbian Signedへの対応となると対応の手間が段違いなわけで、作者の方の労力は並大抵のものではないと思われます。画面キャプチャアプリケーションの場合、キー入力を横取りするためのケイパビリティが必要な関係上、どうしてもSymbian Signedへの対応が必要となってくるんですよね……。

それはさておき、拙作「GetPixels」には怪しげな機能がいろいろと用意されているので、特殊なシチュエーションにおいては何らかの使い道があるかもしれません。例によってソースコードも置いておくので、興味のある方は参考にしてください(例によってコメントはほとんどありませんが)。

スクリーンショット

GetPixels スクリーンショット1 GetPixels スクリーンショット2 怪しげな機能の筆頭に挙げられるのが「外部イベントをトリガとした撮影」機能です。充電機が接続されたタイミングや、メール受信などをトリガとしてキャプチャを行います。

GetPixels スクリーンショット3 撮影完了の通知をスーパーインポーズ表示で行います。スーパーインポーズ表示自体をキャプチャすることはできないので、エミュレータ上にてキャプチャしています。

GetPixels スクリーンショット4 最後に撮影した画像ファイルを送信する機能です。S60プラットフォームでは、非常に簡単に「送信」機能を実装することができるので、試しに実装してみました。

posted at 2006-10-10 | Permalink

Vodafone 804NK・アプリケーションのインストール制限 (2006-08-31)

先日「Vodafone 804NK」が発売開始されました。しかし残念なことに、ネイティブアプリケーションのインストールには制限が加えられているとのことです。具体的には、「Symbian Signedの署名があるアプリケーションしかインストールできない」という制限です。これは「自己署名証明書」のアプリケーションがインストールできないことを意味します(3rd Editionにおける「署名」については、以前の記事(2006-06-30)を参照)。この件についてはすでにあちこちで言及されていて、海外のSymbian開発者のblogなどでも話題になっていました。

個人的には、今回の804NK(や、今後発売される3rd Edition端末のVodafoneバージョン)では、この種のインストール制限は行わない(ベースモデルであるN71と同等の仕様になる)だろうと予想していました。なので、この話は意外でした。

しかし考えてみれば、Nokia 6630のVodafoneバージョンである702NKにおいても、「Symbianの認証を受けたアプリケーションしかインストールできない」という制限がありました。そう考えると、今回の804NKにおいて同様のインストール制限が加えられることは、別に不思議な話ではありませんが……。

とはいえ自分としては、3rd Edition(というよりSymbian OS v9)においては、プラットフォームセキュリティによって「非Symbian Signed(≒自己署名証明書)」のアプリケーションの機能制限がなされているため、新たにインストール制限を加える必要があるほどには危険ではない、との認識でいました(「安全である」とまでは言えませんが)。少なくともSymbian社としては、Symbian OS v9のセールスポイントの一つとして「セキュリティの強化」を挙げているわけですし、もう少しなんとかならなかったものでしょうか……。

posted at 2006-08-31 | Permalink

Nintendo DS liteの液晶ドット抜けを修復したい (2006-08-06)

先日、Nintendo DS liteを購入しました。物自体はいい感じなのですが、残念ながら、上画面のけっこう目立つ部分にドット抜け(正確には常時点灯)が見つかりました。Nintendo DSの液晶画面は、画面の大きさの割には解像度が低いので、1ドットが物理的に大きめです。なので余計に目立ちます。

任天堂に送れば無償で修理(というか良品交換?)してくれるとの話ですが、正直めんどうくさい。そう思っていた矢先、「PSPの液晶のデッドピクセルを活性化させる動画」なるものを見かけました(PSPも液晶を使用した携帯ゲーム機で、本体標準で動画再生機能を持っています)。

要するに、RGB(赤・緑・青)を高速に切り替えて表示するという動画のようです。この動画を表示することによって、液晶の不良画素に刺激を与えるということでしょうか。正直なところ、ものすごく眉唾物です。オーディオ方面の「CDに傷をつけると音が良くなる」といった言説と同じくらいの胡散臭さを感じます。

とはいえ、この程度のことでドット抜けが治るのならば、もうけものです。PSPと違って、DSは標準で動画再生機能などを持っていないので、GBA用にRGB高速切り替え表示を行うプログラムをでっち上げて、DS lite上で動かすことにしました。

  • flicker.zip (実機で動作させるにはGBA用のFlash ROMなどが必要になります)

さて、実際にDS lite上にて実行してみましたが……とりあえず言えることは、実行中の画面は見ない方がいいですね。DS liteの液晶は残像が少ないので、赤・緑・青の高速切り替えがはっきり見えます。ちらつきで目を悪くしそうです。

肝心の効果ですが、一晩放置しておいたものの、相変わらずドット抜けはそのままでした。やはりこんなことでドット抜けが治るなら苦労はしませんか……。

posted at 2006-08-06 | Permalink

S60開発・S60 3rd Edition SDK for C++導入 (2006-07-15)

SDKのダウンロード

まずはForum Nokiaから「S60 Platform SDKs for Symbian OS, for C++」をダウンロードします。3rd Edition用のSDKは3種類ほどありますが(2006-07-15現在)、その中から日本語版と思われる「SDK for 3rd Edition, Japanese」をダウンロードしてインストールしました(今から思うと、この選択がトラブルの元でした)。

エミュレータ用ビルドができない?

最初はサンプルプログラムのビルドから始めてみます。ところが、いきなりつまずいてしまい、エミュレータ用のビルドができません。従来(2nd Edition)と同様にコマンドラインから"abld build wins udeb"と実行しても、エラーになってしまいます。不審に思って、Symbian OS v9.1のリファレンスの「abld command syntax overview」を見ると、なんとターゲットとして指定できるプラットフォームから"WINS"がなくなっています。

エミュレータ用ビルドを行いたい場合、サポートしているプラットフォームは"WINSCW"だけとなります。"WINSCW"はコンパイラとしてMetrowerks CodeWarriorを使いますが、私はCodeWarriorは持っていません。ちなみに、"WINS"の場合だとコンパイラとしてMicrosoft Visual C++を使います。私はMicrosoft Visual C++ 2003を購入しているので、今まではこちらを使っていたのですが……。

ちなみに、実機用(プラットフォームとして"GCCE"を指定)のビルドは問題なく実行できました。しかし、手元に3rd Edition端末がない状態で実機用のビルドだけできてもどうにもなりません。

Carbideを試すものの……

エミュレータ用のビルドができないと開発にならないので、なんとかしないといけません。そこで、Nokia謹製の統合開発環境である「Carbide」を試してみることにしました。

「Carbide」には、Eclipseベースの統合環境である「Carbide.c++」と、Visual Studio用のプラグインである「Carbide.vs」があります。とりあえず、Visual C++でのビルドをしたいので、「Carbide.vs」をインストールしました。

ところが、「Carbide.vs」で新規プロジェクトの作成を行ったところ、「どのSDKを使って開発するか?」の設定の際に「S60 3rd Edition for Japanese」が表示されません。正確には、表示はされるものの、「Not Available」と表示されていて、選択することができません。今まで使っていた「S60 2nd Edition FP2 for Japanese」であれば問題なく新規プロジェクトを作れるのですが……。

それならばと、今度は「Carbide.c++ Express」を試してみることにします。ところがこちらもだめ。症状としては「Carbide.vs」と似たようなもので、やはり「S60_3rd_JP」での新規プロジェクト作成ができません。それどころか、従来の「S60_2nd_FP2_J」も選択不可。

ここで改めて、Nokiaの「S60 3rd Edition SDK for C++」の配布サイトを見たところ、よく読むとCarbideがサポートするSDK一覧の中に「S60 3rd Edition for Japanese」は含まれていませんでした。あー、そういうことなのか。無駄に時間を費やしてしまいました。

再度SDKのインストール

とりあえず、再度SDKのインストールを行います。今度はCarbide.c++が対応しているSDKを選択します。今回は最新版である「S60 3rd Edition, Maintenance Release」を選択しました。

インストールした後、言語設定を変更します。スタートメニューから"S60 Developer Tools"→"3rd Edition SDK"→"1.1 MR"→"Languages"→"Change to Japanese"を選択すると、なにやら内部のファイルをいろいろ再構築して、日本語用の設定に切り替わります。エミュレータを起動すると、メニューなどの表示がすべて日本語になっています。

「Carbide.c++ Express」を起動してみます。おっと、今度はちゃんと「S60_3rd_MR」での新規プロジェクトを作成できます。ウィザードに従ってプロジェクトを作成して、ビルドしてみます。あっさりビルド完了。エミュレータを起動して、正常に動作することを確認しました。ちなみに、ビルドしたプログラムは、メニューから「インストール」を選ぶと一覧から起動できます。

これで3rd Editionのネイティブアプリの開発環境ができたわけですが、本腰をすえて取り掛かるならば、まずは開発用PCを買い換えないとなあ。2nd Editionの頃もそうでしたが、エミュレータがとにかく遅い。Symbian開発環境におけるエミュレータは、実機用のバイナリをCPUレベルでエミュレートしているわけではなく、Windows用にビルドしたバイナリをWindowsネイティブのプログラムとして動かしているわけですが、それにも関わらずなんでこんなに遅いのでしょうか……。

エミュレータのスクリーンショットあれこれ

エミュレータの画面(1) QVGAの画面サイズ。「Vodafone 804NK(Nokia N71)」の画面サイズはこの大きさです。

エミュレータの画面(2) こちらは352×416の画面。3rd Editionのプログラムは、さまざまな画面サイズに対応できるように作りたいところです。

エミュレータの画面(3) 動的に横画面へと変化。3rd Editionのプログラムは、実行中に解像度が変化することも考慮しないといけません。

エミュレータの画面(4) 待ち受け画面。2nd Editionの頃のエミュレータでは待ち受け画面の表示がサポートされていませんでした。

posted at 2006-07-15 | Permalink

S60開発・開発者から見たS60 3rd Edition (2006-06-30)

S60 3rd Edition端末、日本でも続々登場(予定)

先日「Vodafone 804NK」が発表されました。ベースとなる機種は「Nokia N71」とのことです。さらに、「Nokia E60」と「Nokia E61」をベースとした端末のリリースも予定されています。また、ノキアからも「Nokia E60」と「Nokia E61」のスタンダードバージョンを発売予定とのことです。ここにきて、日本でもNokia端末がいろいろ登場してきそうです。

個人的に気になるところは、これらすべての端末のプラットフォームが「S60 3rd Edition」であるという点です。最近のS60端末は、ほとんどが3rd Editionになっているようですね。ちょっと見聞きしたところでは、ネイティブアプリケーションの導入に何かと難があるとのこと。S60 3rd Editionではセキュリティ面が強化されたため、そのあおりを受けて、ネイティブアプリケーションの開発が困難になっているようです。

開発者から見たS60 3rd Edition

ところで、S60 3rd Editionにおけるセキュリティ面の強化は、S60 3rd EditionのベースとなるSymbian OSのバージョンがv9.1にバージョンアップしたことが要因となっています。Symbian OS v9の勉強も兼ねて、S60 3rd Editionについて(ユーザー側の視点からではなく)開発者側の視点から調べてみました。

すべてのアプリケーションに署名が必要

S60 3rd Editionプラットフォームでは、すべてのアプリケーションに署名が必要となります。趣味の開発者や独立系開発者にとっては、ここが最も敷居が高く思える部分です。しかしながら、「自己署名証明書」というものがあり、これを使えば面倒な手続きなしに、アプリケーションに署名を行えるようです。とはいえ、問題点がないわけではありません(これについては後述)。

機能が制限される

従来のS60プラットフォームでは、ネイティブアプリケーションはほとんどすべてのAPIを使うことができ、ほとんどすべてのファイルにアクセスすることができます。しかし、S60 3rd Editionでは「プラットフォームセキュリティ(Platform Security: PlatSec)」と呼ばれるシステム保護モデルを導入しているため、アプリケーションの機能がいろいろと制限されます。

例えば、他ウィンドウへのキー入力をキャプチャする機能を持つAPIがありますが、S60 3rd Editionプラットフォームでは、権限のないアプリケーションがこのAPIを使用することはできなくなっています(APIをコールした時点で強制終了)。これは、キーロガーのようなプログラムを作られることを防ぐための制限です。

このような制限のかかったAPIを使用するためには、アプリケーション側でAPIの使用許可を得ている必要があります。これらは「ケイパビリティ(Capability)」と呼ばれていて、APIの種類ごとにさまざまなカテゴリに分かれています。例えば、先ほど挙げたキー入力キャプチャのAPIですと、そのAPIを含めたキー入出力関連のAPIは「ケイパビリティ"SwEvent"が必要」と定義されています。アプリケーションはケイパビリティ"SwEvent"があれば、これらキー入出力関連のAPIを使うことができるわけです。

これらのケイパビリティを得る手段ですが、ここで先ほどの「署名」の話が関係してきます。先ほどの「自己署名証明書」による署名を行ったアプリケーションでは、限られたケイパビリティしか使用できません。ちゃんとした署名、例えば「Symbian Signed」による署名であれば、さらに多くのケイパビリティを使用できるようになります。また、端末メーカーが電話機の基本機能として搭載するアプリケーションでは、すべてのケイパビリティを使用できるようです。

ファイルアクセスが制限される

S60 3rd Editionでは、ファイルアクセスについてもいろいろと制限があります。この仕組みは「データケージング(Data Caging)」と呼ばれていて、重要なシステムファイルや他のアプリケーションのプライベート領域にはアクセスできないようになっています。また、アプリケーションのインストールディレクトリにも手を出すことはできません。そのため、702NKで行われていたような「正規のインストール手順を踏まずに、アプリケーションファイルを“手で”コピーしてインストール」といった抜け道も使えません。

なお、ファイルアクセスの制限についても、先ほどの「ケイパビリティ」によって、制限を解除することはできます。しかしながら、「システム全体で重要なファイル」の操作を可能にするためのケイパビリティは、普通のアプリケーションでは取得することができません(たとえSymbian Signedによる署名があり、Symbian Signedのテストに合格したとしても)。

バイナリ互換性が完全に失われる

ユーザー側としては、S60 3rd Editionで最も大きいのはこの点でしょう。従来のアプリケーションはまったく使えなくなってしまうため、開発者側から3rd Edition対応版がリリースされるのを待つしかありません。

開発者側からしてみれば、ソース互換性さえ保たれていれば、3rd Edition環境でリビルドすれば済むはずなので、たいして問題ないように思われるのですが……そう簡単にはいかないようです。

「廃止予定(deprecated)」とされていたAPIが本当に廃止されてしまっている

Symbian OSはバージョンアップのたびにさまざまな機能が追加され、それにともない多くのAPIが追加されています。それはいいのですが、「APIの置き換え」というのもあちこちの機能で行われています。書籍『Symbian OS/C++プログラマのためのNokia Series 60アプリケーション開発ガイド』を読むと、特にマルチメディア関連の機能では、1st Editionと2nd Editionの間でAPIが大きく異なっていることがわかると思います。とはいえ、旧来のAPIは「廃止予定」とされましたが、多くのAPIは引き続きサポートされていて、下位互換性は保たれていました。

ところが、3rd Editionではバイナリ互換性がなくなったことを契機として、これらの廃止予定のAPIが本当に廃止されてしまいました。

開発環境や開発プロセスが大きく変わった

S60 3rd Editionアプリケーションの開発においては、バイナリ互換性の喪失にともなってコンパイラも変更になりますし、プラットフォームセキュリティの導入により、署名やらケイパビリティやらいろいろと面倒なことも増えました。

この点については、今後私の方でも身をもって体験することになりそうです。まずは、3rd Edition用SDKのダウンロードからはじめますか……。

参考文献

posted at 2006-06-30 | Permalink

S60開発・設定リストで保存先メモリ選択用の標準UIを使う (2006-04-30)

はじめに

S60アプリケーションでは、設定リストでファイルの保存先などを「電話機メモリ」「メモリーカード」の二択で選択するようなUIをよく見かけます。

GetPixels 「電話機メモリ」を選択した状態の画面写真 GetPixels 「メモリーカード」を選択した状態の画面写真

S60 2nd Editionプラットフォームでは、このような保存先メモリ選択用のUIを、システム側で標準で提供しています。せっかく用意されているものなので、ありがたく使わせてもらいましょう。開発の労力も減らせますし、システム全体でのUIの統一感にもつながります。

使用法

保存先メモリ選択用のUIは、「設定リスト」内に格納できる「設定アイテム」の一種類として用意されています。具体的にはCAknMemorySelectionSettingItemクラスとして定義されています。とりあえずここでは「メモリ選択設定アイテム」と呼ぶことにします。

「設定リスト(CAknSettingItemList)」の使用法については、書籍『Symbian OS/C++プログラマのためのNokia Series 60アプリケーション開発ガイド』あたりを参考にしてください。英語でよければ、"S60 Platform: Avkon UI Resources"というドキュメントもあります(アーカイブ内の"S60_Platform_Avkon_UI_Resources_Setting_Lists_v1_1_en.pdf"が、設定リストについての説明です)。

本題の「メモリ選択設定アイテム」の使用法ですが、実は上記ドキュメントにも説明が載っていなかったりします。とはいえ、使い方は非常に簡単なので、設定リストを実装した経験があればすぐに理解できるでしょう。以下に、拙作「GetPixels」のソースコードから、メモリ選択設定アイテムまわりの実装を抜粋します。

ソースファイル

CAknSettingItem*
CGetPixelsSettingItemList::CreateSettingItemL(TInt aIdentifier)
    {
    CAknSettingItem* settingItem = NULL;

    switch (aIdentifier)
        {
//      (中略)

    case ESettingsSaveLocation:
        settingItem = new(ELeave)
            CAknMemorySelectionSettingItem(aIdentifier, iSettings.iSaveLocation);
        break;

//      (中略)
        }

    return settingItem;
    }

一般的な設定アイテムの生成方法と同じです。なお、"iSettings.iSaveLocation"は設定された内容が格納される変数で、CAknMemorySelectionDialog::TMemory型の列挙体です。以下の2つの値をとります。

  • EPhoneMemory (電話機メモリ)
  • EMemoryCard (メモリーカード)

リソースファイル

RESOURCE AVKON_SETTING_ITEM_LIST r_getpixels_settingitemlist_settings
    {
//  (中略)

    items =
        {
//      (中略)

        AVKON_SETTING_ITEM
            {
            identifier = ESettingsSaveLocation;
            name = TEXT_SAVE_LOCATION;
            },

//      (中略)
        }
    }

メモリ選択設定アイテムには、"setting_page_resource"とか"associated_resource"といったリソースは必要ありません。なので、必要な作業は、設定リストのリソースに対してメモリ選択設定アイテム用の項目を追加するだけです。

注意点

「メモリーカード」が選択された際に画面に表示されるテキストは、メモリーカードのボリュームラベルとなります(未設定の場合は"Memory card"と表示される)。このボリュームラベルに非ASCII文字が含まれていた場合、表示がおかしくなってしまいます。ボリュームラベルの文字コードによるのかもしれませんが、よくわかっていません。

また、冒頭にも書きましたが、メモリ選択設定アイテムがサポートされているのはS60 2nd Edition以降となります。以前のS60端末に対応したアプリケーションを作成する場合には使用できませんのでご注意ください。

posted at 2006-04-30 | Permalink

S60開発・PathInfoクラスで各種フォルダのパスを取得する (2006-03-19)

S60端末では、各種ファイルを格納するための標準のパスが定義されています。例えば、702NKにおいて画像ファイルを格納するパスとしては、本体メモリの場合は"C:\Nokia\Images\"が、メモリーカードの場合は"E:\Images\"が標準のパスとなります。内蔵アプリケーションの「ギャラリー」では、これらのパス以下に存在する画像ファイルが画像リストに表示されます。

これらの定義されている標準のパスを取得するためのAPIとして、PathInfoクラスが提供されています。使い方は非常に簡単で、static関数として用意されているAPIを呼ぶと、パス文字列がconst TDesC&型の戻り値で取得できます。

具体的に取得できる値は以下のようになります(702NKの場合)。それぞれのAPIが何のパスを表しているのかについては、API名を見ればだいたいわかると思います。

PathInfo API戻り値
RomRootPath()Z:\Nokia\
PhoneMemoryRootPath()C:\Nokia\
MemoryCardRootPath()E:\
GamesPath()Games\
InstallsPath()Installs\
OthersPath()Others\
VideosPath()Videos\
ImagesPath()Images\
PicturesPath()Images\Pictures\
GmsPicturesPath()Images\Pictures\
MmsBackgroundImagesPath()Images\Backgrounds\
PresenceLogosPath()Images\Presence\
SoundsPath()Sounds\
DigitalSoundsPath()Sounds\Digital\
SimpleSoundsPath()Sounds\Simple\
ImagesThumbnailPath()_PAlbTN\
MemoryCardContactsPath()E:\Others\Contacts\

ただし、PathInfoクラスがサポートされているのはS60 2nd Edition以降となります。以前のS60端末に対応したアプリケーションを作成する場合には使用できませんのでご注意ください。

posted at 2006-03-19 | Permalink

「GetPixels」開発途中版 (2006-03-13)

お蔵出し

以前、S60プラットフォーム向けのスクリーンキャプチャツール「GetPixels」を開発していたのですが、ここしばらくの多忙のため、塩漬けにしたまま3ヶ月以上が過ぎてしまいました。あらかた動く状態まで作りこんだものの、最後の仕上げの段階で放置していました。

このままお蔵入りにするのももったいないので、開発途中ですが公開しておきます。ソースコードも置いておきますので、参考にしたい方はどうぞ(コメントはほとんどありませんが……)。

特徴など

主な特徴は以下のとおりです。

  • 4種類の画像フォーマットに対応(PNG・BMP・MBM・JPEG)
    • 画像フォーマットごとに各種設定可能
  • 画像ファイル保存場所のカスタマイズ可能(ドライブ・ディレクトリ名・ファイル名)
  • キャプチャトリガとするキーのカスタマイズ可能
  • 外部イベント(充電開始)をトリガにしてキャプチャ可能
  • ディレイ時間設定可能
  • グローバルノートやバイブレーションによるキャプチャ完了通知可能

目新しい機能としては「充電開始をトリガにしたキャプチャ」でしょうか。キー入力をトリガにしてキャプチャしようとすると、高負荷なゲームなどの動作中だとなかなかキャプチャができないことが多々あります(他プロセスにCPU時間がまわらないため?)。ところが、そんな高負荷な状態でも、充電を開始する際には高いプライオリティで『充電中です』という表示が行われます。充電開始をトリガにしてキャプチャすることで、高負荷アプリケーションの隙を突いてキャプチャを行おうという魂胆です。

ただ、実際には微妙なタイミングに左右されるようで、『充電中です』と表示された画面がキャプチャされてしまうこともしばしば。なかなか思うようにはいかないものです。

未完成な部分もいろいろあります。

設定リストのスクロールバー(?)が表示されない
なぜ表示されないのか理由がよくわかりません。CCoeControl::SetMopParent()あたりの使い方が間違っている?
コメント情報を含むJPEGファイルの生成時にメモリリークしている
JPEGファイルを生成する際に、任意のコメント情報を埋めこめられるように設定できますが、その際にメモリーリークが発生している模様。原因もだいたい分かってはいますが、クラスの設計ミスが原因なので、直すのが面倒くさくて放置中。
画像ファイル名の指定方法が難しい
キャプチャ時の日時を元にして画像ファイル名を決めるようにしているのですが、カスタマイズの自由度を上げようとして四苦八苦した結果、「TTime::FormatL()の引数となる文字列をユーザー側で直接指定する」というひどいI/Fにしてしまいました。
アイコンがない
面倒なので作っていません。
動作が不安定
これが一番大きな問題で、高負荷時にキャプチャする際にどうも動作が怪しい。特にゲームなどでは、ものによってはキャプチャ時に端末の再起動がかかったりすることも。この件については原因不明です……。

スクリーンショット

以下のスクリーンショットは、当然ですが「GetPixels」にてキャプチャした画像です。

GetPixels スクリーンショット1 GetPixels スクリーンショット2 メイン画面には、最後にキャプチャした画像が表示されます。

GetPixels スクリーンショット3 GetPixels スクリーンショット4 各種設定画面です。

GetPixels スクリーンショット5 GetPixels スクリーンショット6 こちらは画像パラメータの設定画面です。

GetPixels スクリーンショット7 実際にキャプチャされた画像はこんな感じ。

GetPixels スクリーンショット8 カメラのファインダ画面もこのとおり。

posted at 2006-03-13 | Permalink

© 2004-2008 ENDO