AIR / ActionScript
Entries
mxmlc/amxmlc のコンパイルの背景
- Date
- 2007-07-30 (Mon)
- Category
- AIR / ActionScript
Flex SDK は
- 無料 で使えて、
- 馴染みのテキストエディタを使ってActionScipt の編集ができて
- .swf か .air がコンパイル出来る
というよいものです。2週間ほど触ってみて理解した事などをまとめてみます。
大事なのは以下の三点。
- mxmlc は .as を .swf へ変換する、(java で書かかれた)コンパイラ
- その中で、画面への描画をしたいなら、DisplayObject を extends したクラスを作る必要がある。
- これは予想だけれども、Display Object と全く同じ signature をもつ別のクラスを作れば、Display Object を extends する必要はないと思う。そのかわり Display Object Container やらいろいろ自分で実装せねばならないけれども。でもこのクラス図が提供する世界観がきらいとか、それではどうにもならない、という人が新しい世界を作れる、というのはすばらしい。
- amxmlc は、mxmlc に Air 用のプリプロセスを含めたコンパイラ。Air 用のプリプロセス、とは
- いくつかの Air 専用メタデータ(アノテーション)を ActionScript 3 の文法内で再現できるようにすること(マクロ展開みたいなもの。でも java のアノテーションも同じように、コンパイル前のプリプロセスでやってるんだよね?)
- mxml を .as ファイルへ変換する事
- 以上の事より、amxmlc が展開する .mxml という xml ファイルは無名パッケージで同名の public class に変換される、ということ。
例えば、Hoge.mxml というファイルで、以下のような内容だったとする
<?xml version="1.0" encoding="utf-8"?> <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" backgroundColor="0xFFCC00" > <mx:Script source="bootstrap.as"/> </mx:WindowedApplication>
これは、
package
{
import mx.core.WindowedApplication
public class Hoge extends WindowedApplication
{
public var layout:String = "absolute";
public var backgroundColor:uint = "0xFFCC00";
/* bootstrap.as の内容がここに挿入される */
public function Hoge ():void
{
}
}
}
という内容の Hoge.as ファイルが作成される事。
当初の目的
僕がしたかったのは、mxml を作る人(DreamWeaver なり Flex Builder なり、何らかの Visual Editing Software を使う人。)と、.as のコードを書く人を分けたかった。で、そのために一番簡単なのは、.mxml の root content (上の例で云えば mx:WindowedApplication )に何らかの event トリガを仕込む事。creationComplete を使うのが一般的かしらん。
でも、それだと、コード側が全権掌握できない。というか、creationComplete の前に何かしたい時どうする、とか、creationComplete で発動させたい関数の名前が変わる時いちいち mxml 作る人に話さなきゃいけないとか、そもそも静的にはアクセスできない関数をトリガしたい、とかいろいろ問題がある。で、どうするのか考えて、僕なりに出した結論が以下のような bootstrap.as で、上の Hoge.mxml から呼び出されている内容です。
// this code works as a bootstrap import mx.core.Application; import mx.events.FlexEvent; import mx.controls.Alert;
public var myvar:int = 0;
public function initilizer (ev:Event):void { //trace("init: Start"); Alert.show(this); trace(this.myvar); //trace("init: End"); }
Shell.shell.addEventListener(InvokeEvent.INVOKE, function(ev:InvokeEvent):void { // because Application.application is not set yet this moment. Application.application.addEventListener(FlexEvent.CREATION_COMPLETE, Application.application.initilizer); });
一番大きなポイントは、イヴェントの発動が2段構えなところでしょうか。何故こんな面倒な事をしているかというと、上で一度説明していますが、amxmlc がコンパイルする時、この bootstrap.as は変換された Hoge.as の一部に挿入されるだけ、だからなんですね。もし
- Application.application.addEventListener の行を一番外側に持ってこようとすると動かない→実行時にまだその Object は出来てないから。
- Application.application.addEventListener でリスンさせている関数が Application.application.initilizer という見慣れない完全修飾型になっているのは、呼び出し元によって、default の名前空間(端的に言えば this )が変わるから。これは Javascript をやってる人にはなじみが深いと思うのだけれど、instance method 内で this を使うと、普段はちゃんと動くのだけれど、Event からトリガされると this が切り替わってしまって動かないとか。それと同じ。
- Shell.shell の InvokeEvent.INVOKE には、closure をあてているのは、意味のない関数に名前のあてるが癪だから。
これがわかるまで、グローバルに配置しておきたい変数宣言を何処におくかとか、名前空間とか、めちゃくちゃ悩みました。もう遅いので後で、自分が使うプロトタイプなどをアップしておきます。
ActionScript 3 版 print_r
- Date
- 2007-07-25 (Wed)
- Category
- AIR / ActionScript
オールドスクール開発で、print debug はかかせません。そして php で育った僕には、print_r みたいな、データ構造ダンプ関数がかかせません。というわけで作りました。
使い方
import Utils;
trace( Utils.print_r( [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] ) );
などとすると、
[trace] --------------------------------------------------------------------- [trace] :Array => [trace] [0]:int => 0 [trace] [1]:int => 1 [trace] [2]:int => 2 [trace] [3]:int => 3 [trace] [4]:int => 4 [trace] [5]:int => 5 [trace] [6]:int => 6 [trace] [7]:int => 7 [trace] [8]:int => 8 [trace] [9]:int => 9 [trace] ---------------------------------------------------------------------
と、帰ってきます。他に toCamelCase / capitalize ができます。
既存の問題
- コンストラクタ、イヴェントそれにスコープチェインなどは、まずどうやって表示するのがわかりやすいのか、わからない。取得の方法はわかっていて、ソースを見ればだいたいわかると思います。
コード
package
{
import flash.utils.describeType;
public class Utils
{
public static function print_r (o:*, name:String = "", recur:int = 0):String
{
var result:String = "";
var type:String = typeof(o);
var desc:XML = describeType(o);
// meta data of object
if (recur == 0)
{
result += "---------------------------------------------------------------------\n";
}
else
{
for (var i:int = 0; i < recur; ++i)
{
result += " ";
}
}
if (name)
{
result += '[' + name + ']';
}
result += ':' + desc.@name + ' => ';
// content of object
switch (type)
{
case "boolean":
case "number":
case "string":
result += String(o);
break;
case "xml":
result += o.toXMLString();
break;0
case "object":
if (desc.@name == "Object" || desc.@name == "Array")
{
for (var key:String in o)
{
result += "\n";
result += print_r(o[key], key, (recur + 1));
}
}
else
{
var prop:XML;
//trace("UTIL: " + typeof(o));
//trace("UTIL: " + desc.toXMLString());
// -- properties
for each (prop in desc.variable)
{
result += "\n";
result += print_r(o[prop.@name], prop.@name, (recur + 1));
}
// -- methods
for each (prop in desc.method)
{
//trace("UTIL: " + prop.toXMLString());
result += "\n";
result += print_r(o[prop.@name], prop.@name, (recur + 1));
}
// -- constructor
//<constructor>
// <parameter index="1" type="flash.net::URLRequest" optional="true"/>
//</constructor>
// -- inheritance and implements
//<implementsInterface type="flash.events::IEventDispatcher"/>
//<extendsClass type="flash.events::EventDispatcher"/>
//<extendsClass type="Object"/>
// -- events and others..
//<metadata name="Event">
// <arg key="name" value="httpStatus"/>
// <arg key="type" value="flash.events.HTTPStatusEvent"/>
//</metadata>
}
break;
case "function":
//trace("UTIL: " + typeof(o));
//trace("UTIL: " + desc.toXMLString());
result += String(o);
break;
}
if (recur == 0)
{
result += "\n---------------------------------------------------------------------";
}
return result;
}
public static function toCamelCase (str:String):String
{
var r:String = "";
var a:Array = str.split(' ');
for (var s:String in a)
{
r += Utils.capitalize(a[s]);
}
return r;
}
public static function capitalize (str:String):String
{
var r:String = "";
r += (str.slice(0, 1)).toUpperCase();
r += str.slice(1);
return r;
}
}
}
fdb あるいは Flash Player debug
- Date
- 2007-07-21 (Sat)
- Category
- AIR / ActionScript
最近 ActionScript をすこし真面目にやるようになりました。もうほとんど Java で、まぁ覚えやすいような、みんなそこまで Java 好きなのか… Design Pattern をやったので、それも近いうちにまとめたいです。
さて、今回は小ネタで。Flash では伝統的に trace という標準出力関数があり、皆よく print debug などに使いまくってるはずですが、最新の Flash Player.app でどうやるかを解説します。
僕の記憶では、昔のバージョンの Debug 版 Flash Player.app (昔は Projector とか呼ばれてたような…)では、フローティングパネルが開いて、そこに出ていたりしたような気がします(嘘かも)。もちろん、Flash CS3 の IDE 内ではそのように動作するし、coding から、build、debug まで一貫した環境で出来て便利そうではあります。
僕のやり方は、Flex SDK を使った OLD SKOOL!! 開発なので(emacs まではまだたどり着いてない)、無料で手に入るものでやりましょう。ActionScript 3 なので最新バージョンの Flash Player が必要です。以下のページよりダウンロード。
Adobe Flash Player - Downloads
種類がありすぎて confusing ですが、Projector content debugger と書いてあるものを platform 毎に選んでください。ちなみに Flex3 SDK に同梱の Flash Player.app は debug ビルドではありません。(っつぅか何処見ても Debug と Release ビルドの違いがわからないのはどうかと思う。)
さてようやく本題です。
そのまま debug ビルドな Flash Player.app を立ち上げて、trace 文を含む swf ファイルを開こうとすると、debug host は何処だとか聞いてきます。どうやら debug 用に別の server daemon が必要なんですね? Projects Open Source Flash をみるといくつか興味深いプロジェクトがいくつかあります。試しましたけど、なんというか、ソースコードに手を加えなきゃ行けなかったり、それは納得いきません。
で、どうするか。実は Flex3 SDK には fdb という超本格的な debugger が付属しています。これと Flash Player を連携させると、trace を拾えます。というか連携させないと拾えません。しかも致命的に使いにくい点もいくつかあります。以下使い方を。
- fdb の中から、Flash Player を起動させる必要があります。
- fdb が Flash Player.app を起動するためにのファイルパスを渡してやる必要がありますが、fdb は空白を含むパスを理解しません。
- ので、まず最初に Debug built Flash Player.app を適当な名前に rename して、空白文字列を含まないパスに copy します。僕は /usr/local/flash/debug.app とかしました。
- fdb とタイプすると、interactive shell のようなものが立ち上がります。次に run /usr/local/flash/debug.app などとすると、Flash Player が立ち上がるので、その dock アイコンに swf ファイルをドロップするもよし、メニューからファイルを開くもよし。
- 通常の terminal shell から、fdb run /usr/local/flash/debug.app などとすると、Debug built Flash Player が立ち上がる所まで行くので、僕はそれを Shell の Alias に登録しました。
- そしてその開いた Flash Player で swf ファイルを開くと、fdb が最初に実行を休止します。fdb シェルにて continue あるいは c とタイプすると、実行が再開されます。
- fdb シェル上にて help または h とタイプすると、コマンド一覧が表示されます。
- 一度 swf ファイルを Flash Player から閉じると、fdb と Debug built Flash Player のコネクションは途絶えます。というわけで最初からやり直し!なのです。
- また開いたままでしばらくほっとくと、やはりコネクションタイムアウト、とかいって勝手に切られます。
こんな所でしょうか。
最近 TextMate に TextEditor を鞍替えしようかと思っています。Skeleton (App-config.xmlとかの)作成ができて、one key stroke でbuild → debug player の起動まで云ったりしたら便利そう?あぁ、それにしても1行で終わらせるつもりのエントリに1時間もかけてしまった。。
Apollo on Mac OS X: adt コマンドを使った配布パッケージの作成
- Date
- 2007-04-11 (Wed)
- Category
- AIR / ActionScript
Apollo を Mac OS X で開発するための記録です。今回は Adobe の sample ページにあるような、.air ファイルの配布パッケージの製作をやってみます。
コマンド実行時 (adl とか adt ) にエラーが出る、という場合は 前回の記事 を参考にしてみてください。
Apollo on Mac OS X: Install(完成版)
- Date
- 2007-04-11 (Wed)
- Category
- AIR / ActionScript
昨日に引き続き、Apollo を Mac OS X で開発するための記録です。今回はインストールを完了して、(あまりに長くなったので)次エントリで Adobe の sample ページにあるような、.air ファイルの配布パッケージの製作をやってみます。
最初に、この本はダウンロードしましょう。
Apollo:Books:Apollo for Adobe Flex Developers Pocket Guide
僕もやってる事はここに書いてある事です。加えて開発環境 (Flex Builder) を買わないで、無料で何処までできるか、というのがこの記事の目的です。