JS AS / Shibuya.js in Kyoto

本日の OSC Kansaia 2008 で開かれた Shibuya.js in Kyoto で、JavaScriptActionScript の連携について話しました。関西のカンファレンスでの発表は初めてでしたが、楽しかったです。スピーカの皆さん、参加された皆さん、どうもありがとうございましたー。
以下発表資料です。

JS <-> AS

自己紹介

JS と AS

  • JS だけでよくない?
  • AS だけでよくない?
    • 相互に補完しあえる関係
    • 両方使えると、様々なメリットが

JavaScript -> ActionScript

  • crossdomain.xml, domain 超え
  • ファイルの複数選択による同時アップロード
  • バイナリ操作

JavaScript -> ActionScript

  • マルチメディア関連
  • AS ライブラリの利用
    • 画像情報取得(exif, 色情報... etc)
    • 音楽再生(FlMML ... etc)

ActionScript -> JavaScript

  • URL の変更
    • location.query, location.hash
  • JS の API での情報取得
    • navigator.userAgent

ActionScript -> JavaScript

JS <-> AS の API

  • ExternalInterface
    • ExternalInterface#addCallback
    • ExternalInterface#call

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

ExternalInterface.
  call('MyApp.exampleCallback', uniq_id, data);

ExternalInterface#call 問題点

    • 'Foo.bar.baz' な関数のみ
      • 'Foo.bar().baz' などの呼び出しは不可
      • JS の変数への代入、参照も不可
      • ExternalInterface. call('document.body.innerHTML'); // エラー

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

Uffy

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 使うと便利!