2007年02月14日
ExternalInterface.addCallback で定義された関数は apply できない
ActionScript の関数を JavaScript から呼び出すときに、ExternalInterface.addCallback で関数を使うと便利なのですが、ここで公開された関数は apply, call, toString といったメソッドが定義されていません。
実験した ActionScript はこんなの。要は draw 関数を ExternalInterface を使って公開してます。
package { import flash.display.*; import flash.external.ExternalInterface; public class ExtTest extends Sprite { public function ExtTest() { draw(0); ExternalInterface.addCallback("draw", draw); } private function draw(color:int):void { graphics.beginFill(color); graphics.drawCircle(0,0,50); graphics.endFill(); } } }
HTML は swfobject.js を使って楽チンに。
<script src="swfobject.js"></script> <script> window.onload = function(){ var so = new SWFObject("ExtTest.swf", "ExtTest", "300", "300", "9", "white"); so.write("box"); } </script> <div id="box"></div>
準備ができたところで、FireBug のコンソールでいろいろ実験してました。
# 関数は定義されている >>> $("ExtTest").draw function() # 呼び出しもできる >>> $("ExtTest").draw(0) # でも、toString(), call(), apply() は失敗 >>> $("ExtTest").draw.toString() $("ExtTest").draw.toString is not a function >>> $("ExtTest").draw.call() $("ExtTest").draw.call is not a function >>> $("ExtTest").draw.apply() $("ExtTest").draw.apply is not a function
apply, call, toString が定義されていないことが分かりますね。
toString と call はいいとして、apply がないのはちょっと不便です。
そこで、私は次のような実装ラッパー関数を作ってます。
function applySwf(swf, method, args){ if(swf && typeof swf[method] == "function"){ switch(args ? args.length : 0){ case 0: return swf[method](); case 1: return swf[method](args[0]); case 2: return swf[method](args[0], args[1]); case 3: return swf[method](args[0], args[1], args[2]); case 4: return swf[method](args[1], args[1], args[2], args[3]); default: throw "argument too many"; } } }
ちょっとかっこ悪すぎな実装ですが、いちおう呼び出せます。
applySwf($("ExtTest"), "draw", [0xff0000])
SWF をロードした直後に、$("ExtTest").call = function(){...} としてやってもできそうなのですが、SWF 側で ExternalInterface.addCallback するタイミングは実装依存なので難しそうです。
追記
上のへぼ実装版 applySwf 関数をかっこよくする方法が 最速インターフェース研究会 :: Functionコンストラクタを使ってJavaScriptネイティブじゃない関数をラッピングする方法 にて紹介されています。ma.la さん、ありがとうございます。 (2007/02/16 23:00)