Aug 28

Flexを利用したActionScript開発では、デバッグがボトルネックになることがしばしばあります。
プリントデバッグを利用するのも一苦労です。

私が開発中によく利用している方法をご紹介します。

ActionScriptで手軽に関数を利用するには無名パッケージでグローバルに関数を定義し、それをソースパスにふくめるのが便利です。
私は、以下で紹介されているlog関数などの便利関数を開発中のみソースパスに含めています。
http://subtech.g.hatena.ne.jp/secondlife/20070219/1171872801

この方法のメリットは以下の通り

  • 無名パッケージだからいちいちパッケージをimportしなくていい。
  • クラスじゃなくて関数だからインスタンスをつくる必要もない(ActionScriptでは、ファイル名と関数名を同じにすることでグローバル関数を定義できます)。

では、これらのソースコードを開発中のみ読み込むようにするにはどうすればいいでしょう?
方法は簡単で、デバッグ用のXMLを用意します。Flexではビルド時の設定をxmlファイルで指定できるのでそれを利用します。

以下をdebug-config.xmlという名前で保存。開発中は、こちらの設定ファイルを読み込むようにします。
source-pathを設定しているのは、便利関数をオートロードするため。
debug を true に設定することでエラーメッセージにソースコードの行数も載るようになります。

<flex-config>
  <compiler>
    <debug>true</debug>
    <source-path append="true">
      <path-element>./</path-element>
    </source-path>
  </compiler>
</flex-config>

mxmlcのオプションに以下を指定し、上のファイルをコンパイル時に読み込みます。

-load-config+=/path/to/debug-config.xml

私はrascutというビルド用ツールを使っているのですが、rascutを使用する場合、rascutは以下のようにします。こちらのオプションを rascut起動用のスクリプトに書き込んでおき、デバッグ用xmlを読み込まないスクリプトと読み込むスクリプトを、「開発中ビルド用」「製品版ビルド用」で使いわけています。

-start-rascut-dev.bat

rascut -c"-load-config+=/path/to/debug-config.xml" some.mxml

以下、デバッグ中にロードする便利関数を紹介します。まずは先にあげたlog関数です。
log関数の他にも以下のような関数を利用しています。
(先ほどの、debug-config.xmlと同じディレクトリにおけば、これらの関数もオートロードされるようになります。ファイル名と関数名を同じにする必要があるので気をつけてください)。

-dump.as
dump関数。オブジェクトを文字列にダンプする関数。ObjectUtilクラスを利用しているだけですが、いちいちパッケージをimportする必要がないのでデバッグ中に重宝します。

package {
    import mx.utils.ObjectUtil;

    public function dump(a:*):String {
        return ObjectUtil.toString(a);
    }
}

-alert.as
alert関数。アラートウィンドウをどこからでも使えるようにする関数。

package {
    import mx.controls.Alert;
    public function alert(...r):void {
        var a:* = r[0];
        if(a is String)
            Alert.show(a);
        else
            Alert.show(dump(a));
    }
}
Jan 12

明けましておめでとうございます!!
ども、amo-kです。

2009年最初の投稿は、JavaScript / ActionScript についての内容です。
個人的にはRIA大好物ですので、この辺りは興味深いジャンルです。
では、本題に入ります。

JavaScript と ActionScript で相互に会話ができることを知った。

…ということは、
ブラウザ操作をトリガーにFlashを操作、
Flash操作をトリガーにブラウザを操作
できるということだ。
これは面白い!!
※厳密には、FlashもブラウザのFlashプレイヤで動作している訳だがそこはおいておこう。

という訳で早速動作確認がてら、簡単なjs, as(Flex用mxml)を書き相互会話サンプルアプリを作ってみた。

サンプルアプリ概要

1.JavaScript(白色部分)からActionScriptの関数を実行
サンプルアプリ上部のボタン「js2as」クリックで
ActionScript側の関数を実行、実行時刻をFlash上に表示。
2.ActionScript(黒色部分)からJavaScriptの関数を実行
サンプルアプリ下部のボタン「as2js」クリックで
JavaScript側の関数を実行、実行時刻をブラウザ上に表示。
※勿論いずれも何度押してもかまわない。

処理概要

上記サンプルアプリは、flash.externalパッケージのExternalInterfaceクラスを利用している。
JavaScriptからActionScriptの関数を実行するには、ExternalInterface.addCallback()メソッドを利用する。このメソッドでは、JavaScriptから呼び出すActionScript関数を定義する。

また、ActionScriptからJavaScriptの関数を実行するにはExternalInterface.call()メソッドを利用する。このメソッドでは、ActionScriptからJavaScriptの関数名を指定する。

サンプルソース

ブラウザ側のサンプルソースコードは、サンプルアプリ白色部分を右クリックしてソースを確認できますので
サンプルソースはFlash側のみ記載します。

import flash.external.ExternalInterface;
import mx.controls.*

// as2jsボタンクリック時実行
private function callFunction():void {
    if (ExternalInterface.available) {
        try {
            ExternalInterface.call("as2js");
        }
        catch(e: Error) {
            Alert.show("error : " + e);
        }
    }
}

// JavaScriptイベントのコールバック関数定義
private function setCallbackFunction():void {
    if (ExternalInterface.available) {
        try {
            //JavaScript から実行
            ExternalInterface.addCallback("js2as", function(): void {
                var date: Date = new Date();
                var dateTime: String = date.getFullYear().toString();
                dateTime += "-" + (date.getMonth() + 1).toString();
                dateTime += "-" + date.getDate().toString();
                dateTime += " " + date.getHours().toString();
                dateTime += ":" + date.getMinutes().toString();
                dateTime += ":" + date.getSeconds().toString();
                myLabel.text = "JavaScript => ActionScript: " + dateTime;
            });
        }
        catch(e : Error) {
            Alert.show("error : " + e);
        }
    }
}

参考情報

Dec 01

たかだです。

先日 Adobe Labs が C/C++ のコードを Flash Player 向けにコンパイルする Alchemy というプロジェクトをプレビューリリースしました。

Alchemy は llvm を利用し、C/C++ のコードを ActionScript3(ActionScript ByteCode ではありません)に変換し、それを SWF または SWC 形式にコンパイルします。
llvm の最適化処理によって、しばしばネイティブの ActionScript より高速に動作するそうです。

新しもの好きのわたしが早速こちらを動かしてみたいと思います。
以下 Alchemy:Documentation:Getting Started を参考に、Windows+Cygwin 環境で Alchemy を動かします。

必要なものは、以下の通りです。

  • Cygwin
  • (Cygwin上で動く)Perl
  • (Cygwin上で動く)zip
  • (Cygwin上で動く)gcc/g++
  • Java
  • Flex 3.2 SDK

Flex のインストール

最初に Flex 3.2 SDK をインストールします。Flex SDK は以下から 3.2 をダウンロードしてください。
(Cygwin および Java などのインストールについては以下では解説しません)。

解凍し、適当なパスに置いてください。
Cygwin 上で Flex SDK に Path を通す必要があります。
ここでは Flex SDK のインストール先を C:/develop/flex_sdk_3/ とします。
以下を .bashrc などに書きくわえてください。


PATH=/cygdrive/c/develop/flex_sdk_3/bin/:$PATH
export PATH

正しくパスが通っていれば、以下のようになるはずです。


$ mxmlc -version
Version 3.2.0 build 3958

Alchemy のインストール

Adobe Labs より「Alchemy Toolkit for Cygwin on Windows」をダウンロードし、適切な場所に解凍しておきます。
(以下では C:/develop/alchemy-cygwin/ に解凍したものとします)。

最初に config というスクリプトを実行します。


$ cd /cygdrive/c/develop/alchemy-cygwin/
$ ./config
Generating alchemy-setup...
Turning execution bit on for Alchemy binaries...

Add "source /cygdrive/c/develop/alchemy-cygwin/alchemy-setup" to your login script.
  "alc-home" takes you to the Alchemy install folder.
  "alc-on" puts Alchemy gcc toolchain replacements at the front of your path.
  "alc-off" restores original path.
  "alc-util" shows you various Alchemy-related environment vars
You need Flash 10 or AIR 1.5 and the Flex 3.2 SDK installed for testing.

以上により alchemy-setup が生成され、alchemy ツールのいくつかが使えるようになりました。
alchemy-setup というシェルスクリプトを実行することで必要な環境変数を設定し、alc-on などのコマンドを呼び出せるようになります。
ただし、こちらを実行する前に Air Debug Launcher(ADL)のパスを alchemy-setup に追加しておく必要があります。ADL は Flexディレクトリの bin/ 以下にある adl.exe というファイルです。
alchemy-setup を編集し、ADL のパスを追加してください。
(以下は alchemy-setup に書き加えます)。


export ADL=/cygdrive/c/develop/flex_sdk_3/bin/adl.exe

ログイン時に、alchemy-setupが実行されるようにするため、.bashrcを変更します。Adobe Labsのgetting startedには、achacksディレクトリをPATHに追加するように書いてありますが、追加しない方がよいようです。
(alchemy-setupの場所は、設定に応じて変更してください)。
(以下は.bashrcに書き加えます)。


source /cygdrive/c/develop/alchemy-cygwin/alchemy-setup

alchemy-cygwin/bin/llvm-stub にシンボリックリンクをはる必要もあるようです


cd bin/
ln -s llvm-stub llvm-stub.exe

以上が終わったら、Cygwinにログインし直し環境変数の設定が更新されるようにします。
(単に source .bashrc を実行するだけでもかまいません)。

C コードのコンパイル

以上までで alc-on / alc-off というコマンドを利用できるようになりました。
alc-on を実行すると gcc コマンドの参照先が alchemyプロジェクトのものに変更され、alc-off で元に戻ります。


$ alc-on
$ which gcc
/cygdrive/c/develop/alchemy-cygwin/achacks/gcc

さっそくサンプルプログラムをコンパイルしましょう。alchemy のディレクトリの中にすでにサンプルプログラムが用意されています。
ここでは、stringecho.c というコードをコンパイルします。
コードを一部だけのぞいてみましょう。以下のようなC言語の関数が定義されています。引数が null かどうかチェックし、AS3_String 型にして返すだけの関数のようです。


static AS3_Val echo(void* self, AS3_Val args)
{
	//initialize string to null
	char* val = NULL;

	//parse the arguments. Expect 1.
	//pass in val to hold the first argument, which
	//should be a string
	AS3_ArrayValue( args, "StrType", &val );

	//if no argument is specified
	if(val == NULL)
	{
		char* nullString = "null";
		//return the string "null"
		return AS3_String(nullString);
	}

	//otherwise, return the string that was passed in
	return AS3_String(val);
}

alc-on の状態で、gcc コマンドを利用し、コンパイルします。


$ cd /cygdrive/c/develop/alchemy-cygwin/samples/stringecho/
$ gcc stringecho.c -Wall -swc -o stringecho.swc
WARNING: While resolving call to function 'main' arguments were dropped!

4328.achacks.swf, 363894 bytes written
frame rate: 60
frame count: 1
69 : 4
72 : 363824
76 : 33
1 : 0
0 : 0
frame rate: 24
frame count: 1
69 : 4
77 : 506
64 : 31
63 : 16
65 : 4
9 : 3
41 : 26
82 : 471
1 : 0
0 : 0
converting to DOS line endings
catalog.xml: done.
  adding: catalog.xml (deflated 75%)
  adding: library.swf (deflated 61%)
$ ls -l
total 149
drwx------+ 2 takada-at ????????         0 Dec  1 10:02 as3
-r-x------+ 1 takada-at ????????       435 Nov 13 10:20 readme.txt
-r-x------+ 1 takada-at ????????      1221 Nov 13 10:20 stringecho.c
-rwxr-xr-x  1 takada-at mkgroup-l-d 144137 Dec  1 11:07 stringecho.swc

SWC ファイルが生成されました!
生成された SWC ファイルはライブラリとして ActionScript コードの中で利用できます。
stringecho.swc は、引数として渡された文字列を、そのまま返すだけの関数を提供しています。
ここでは、以下のような mxml コードを利用して、このライブラリの動作を試してみましょう。以下を、Hello.mxml として保存し、同じディレクトリに stringecho.swc も置きます。


<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="main()">
    <mx:Label text="aaa" id="labelone" fontSize="24" />
    <mx:Script><![CDATA[
        public function main():void{
            import cmodule.stringecho.CLibInit;
            var lib:CLibInit = new CLibInit();
            var stringEcho:Object = lib.init();
            labelone.text = stringEcho.echo("Hello!");
        }
    ]]></mx:Script>
</mx:Application>

SWFファイルとしてコンパイルします。target-player の指定を忘れないように注意してください。


$ mxmlc.exe -library-path+=./stringecho.swc Hello.mxml -target-player=10.0.0
設定ファイル "C:\develop\flex_sdk_3\frameworks\flex-config.xml" をロードしています
C:\develop\alchemy-cygwin\samples\stringecho\Hello.swf (461380 bytes)

生成されたSWFファイルをブラウザにドラッグすると…?

期待通り、Helloの文字が表示されました。