JS AS / Shibuya.js in Kyoto
本日の OSC Kansaia 2008 で開かれた Shibuya.js in Kyoto で、JavaScript と ActionScript の連携について話しました。関西のカンファレンスでの発表は初めてでしたが、楽しかったです。スピーカの皆さん、参加された皆さん、どうもありがとうございましたー。
以下発表資料です。
JS <-> AS
- JavaScript と ActionScript の連携
自己紹介
- はてなエンジニア
- 舘野 祐一 (id:secondlife)
- Ruby, ActionScript3, JavaScript
JS と AS
- JS だけでよくない?
- AS だけでよくない?
- 相互に補完しあえる関係
- 両方使えると、様々なメリットが
JavaScript -> ActionScript
- crossdomain.xml, domain 超え
- ファイルの複数選択による同時アップロード
- swfupload ( http://swfupload.org/ )
- バイナリ操作
ActionScript -> JavaScript
- URL の変更
- location.query, location.hash
- JS の API での情報取得
- navigator.userAgent
ActionScript -> JavaScript
- html の要素取得
- ブログパーツ等で、ブログの本文等の情報利用
- html 上に動的オーバーレイ, スクロール制御
JS <-> AS の API
- ExternalInterface
- ExternalInterface#addCallback
- JavaScript から呼び出せる API を登録
- ExternalInterface#call
- JavaScript を呼び出す
- ExternalInterface#addCallback
ExternalInterface# addCallback
JS 側から
$('flash_id').example(arg);
で簡単に呼び出せる!けど問題が…
- 関数呼び出し時、swf がロードし終わってないとエラー
- Flash 側での非同期処理
- JS にどうやって通知するか
swf 未ロード問題
- swf ロード完了時に、ExternalInterface#call で JS 側に通知
MyApp.onLoad = function() { MyApp.example(arg); };
// AS 内部でロードが終わったら通知 ExternalInterface. call('MyApp.onLoad');
Flash 側での非同期処理
- ネットワーク上のファイルをロードし終わったら、等の処理
- Flash 側の非同期処理完了時、ユニークなIDで関数を呼ぶ
// AS 処理完了時 ExternalInterface. call('MyApp.exampleCallback', uniq_id, data);
- 通常は JS 側で Object を作って処理をラップ
- 使いやすい API に
ExternalInterface#call
- JavaScript の関数呼び出し
ExternalInterface. call('MyApp.exampleCallback', uniq_id, data);
ExternalInterface#call 問題点
-
- 'Foo.bar.baz' な関数のみ
- 'Foo.bar().baz' などの呼び出しは不可
- JS の変数への代入、参照も不可
- ExternalInterface. call('document.body.innerHTML'); // エラー
- 'Foo.bar.baz' な関数のみ
ExternalInterface#call
クロージャな文字列で渡すと何でも可能
# JS の変数の参照 var body:String = ExternalInterface.call('(function() { return document.body.innerHTML; })');
# JS の変数へ代入 ExternalInterface.call('(function(arg) { document.body.innerHTML = arg; })', 'hello');
ExternalInterface#call BK その他
ExternalInterface#call
複雑な呼び出しになると大変
- そこで…
JSProxy
ExternalInterface#call の面倒な処理をよしなにしてくれる
var body:String = JSProxy.proxy.document.body.$innerHTML; JSProxy.proxy.document.body.$innerHTML = 'hello';
JSProxy - Example
var location:JSProxy = JSProxy.proxy.location; // location の情報を取得できる var browserUrl:String = location.$href; var hostname:String = location.$hostname; location.$href = 'http://www.hatena.ne.jp/';
JSProxy - HTML フォームの送信
var form:JSProxy = JSProxy.proxy.document. getElementById('testform'); var inputs:JSProxy = form.getElementsByTagName('input'); inputs[0].value = 'oreore'; inputs[1].value = 'oreore@example.com'; form.forceAsync = true; form.$submit();
JSProxy
- 続きは Web で!
- JSProxy を使うと AS -> JS は楽に
- JS -> AS を楽にしたい
Uffy
- http://github.com/hotchpotch/uffy/tree/master
- AS から簡単に JS のクラス作成・メソッド定義
- 今まではラッパをいちいち書いていた
- Uffy を使うと、独自ラッパ定義しなくておk
Uffy.as
import uffy.javascript; public class URI { javascript function getURL(...) javascript function postURL(...)
import uffy.Uffy; Uffy.register('URI', URI);
Uffy.js
var uffy = new Uffy('GetURL.swf'); uffy.load('URI', function(URI) { var uri = new URI; uri.getURL(fooUrl, callbackFunc); }); // 別のを register してやるとそいつも uffy.load('Exif', function(Exif) { var uri = new Exif(url); exif.load(callbackFunc); });
no Uffy.js
JS 側は Uffy.js 使わなくても OK
var uri = new $('my_swf_id').URI; uri.getURL(fooUrl, callbackFunc); var exif = new $('my_swf_id').Exif(url); exif.load(callbackFunc);
Uffy help
- 自動で help 変数が登録される
alert($('my_swf_id').UffyTest.help);
- help 変数は、定義された関数の引数や戻り値を表示
callFunc(**, Function):** refrect():** foo():String
Uffy
- 1swf の id に複数の JS のクラスが持てる
- javascript namespace による関数登録
- AS 側は、AS のクラスを書くように JS のクラスを定義
- help の表示
- Uffy.js を使った swf ロード待ち
- その他…
まとめ
- JS <-> AS は相互に補完しあえる関係
- AS でできないブラウザ操作を JS 経由で
- JSProxy 使うと便利!
- JS でできないこと、難しいことを AS に
- Uffy 使うと便利!