JavaScript通过Flash的CallFunction和Flash通信

目录

参数传递回目录

当JavaScript调用一个Flash方法的时候,FlashPlayer会将参数转换成XML格式,而转换函数实际上在Flash嵌入到页面并且被正确加载的时候就被抛出到了全局上:

  • __flash__argumentsToXML 用于将参数转换成XML表达的方法
  • __flash__arrayToXML 用于将数组转换成XML
  • __flash__escapeXML 用于将XML内的字符转义
  • __flash__objectToXML 用于将Object转换成XML
  • __flash__request 用于组成请求体
  • __flash__toXML 用于将数据转换成XML

实际上JavaScript 和 Flash 程序之间只能传递字符串数据,任何类型的数据都通过上面的转换函数转换成了xml字符串来表示。假设上面的方法不存在,或者上面的方法被不正确的复写,那么很可能就出现外部JavaScript无法调用到Flash对外注册的接口。

实例如下:

1
2
3
4
5
6
7
8
<script type= "text/javascript" >
var  myArg = [];
myArg[10000] = 1;
myArg[10001] = {
   a : 1,
   b :  "string"
};
</script>

会被转换成(优化后的):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
< invoke  name = "test"  returntype = "javascript" >
   < arguments >
     < array >
< property  id = "10000" >
         < number >1</ number >
       </ property >
< property  id = "10001" >
         < object >
< property  id = "a" >
             < number >1</ number >
           </ property >
< property  id = "b" >
             < string >string</ string >
           </ property >
         </ object >
       </ property >
     </ array >
   </ arguments >
</ invoke >

JavaScript调用Flash方法回目录

CallFunction 是Flash Player插件对外公开的调用接口,无论是使用C++还是JavaScript都是从这个接口来调用Flash的方法。__flash__request 将传入的参数组成最终的请求体(上面XML),然后发送给Flash Player, Flash Player拿到请求体解析后调用相印的方法,并且把请求参数传入,然后将执行结果返回。

实例如下:

1
2
3
<script type= "text/javascript" >
alert(testSwf.test);
</script>


等同如下:

1
2
3
4
5
6
7
8
<script type= "text/javascript" >
var  arg = [ 'test' ];
for  ( var  i=0; i<arguments.length; ++i)
{
arg.push(arguments[i]);
}
testSwf.CallFunction(__flash__request.apply( null , arg));
</script><BR><BR>

Flash调用JavaScript方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var  myJavaScript:XML = <script>
<![CDATA[
   function ()
   {
     function  sum(a, b)
     {
       alert(a + b);
     }
   
     sum( 1 2 );
   }
]]>
</script>
   
ExternalInterface.call(myJavaScript);   //output 3<BR><BR>

甚至还可以注入JavaScript代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var  myJavaScript:XML = <script>
<![CDATA[
   function ()
   {
     window.sum =  function (a, b)
     {
       alert(a + b);
     }
   
     sum( 1 2 );
   }
]]>
</script>
   
ExternalInterface.call(myJavaScript);<BR><BR>

之后就可以执行如下调用:

1
2
3
<script type= "text/javascript" >
alert(window.sum);
</script>


这样甚至能把你的JavaScript代码嵌入到Flash当中,这样做法的优劣暂时不进行讨论。然而Flash不仅仅能在浏览器中调用JavaScript方法或者注入JavaScript代码,在IE甚至能够调用和注入VBScript的方法和代码。

方法的性能优化回目录


之前提到,Flash Player会在SWF成功加载后将6个函数抛到全局上,然而不幸的是,这六个全局函数都不同程度的存在性能问题,其中问题比较严重的函数是:

函数之一:__flash__arrayToXML 负责将数组转换成XML

1
2
3
4
5
6
7
8
9
function  __flash__arrayToXML(obj) {
   var  s =  "<array>" ;
   for  ( var  i=0; i<obj.length; i++) {
     s +=  "
<property id=\""  + i +  "\">"  +
       __flash__toXML(obj[i]) +  "</property>" ;
   }
   return  s+ "</array>" ;
}


假设将如下的JavaScript数组转换成XML

1
2
var  myArray = [];
myArray[10000] = 1;


上面的函数会循环10000次,把所有的数组元素不管存在与否都解析成XML, 这就导致了以下问题:

  • 把性能浪费在无用的解析上
  • 使得XML请求体无比庞大
  • Flash Player拿到XML数据后还要无奈地建立XML DOM并且将刚才的无用数据解析还原
  • 对字符串使用了 += 操作,这个操作在IE浏览器的效率非常低

函数之二:__flash__escapeXML 负责将特殊字符转为实体

1
2
3
4
5
6
function  __flash__escapeXML(s) {
   return  s.replace(/&/g,  "&amp;" ).replace(/</g,
     "&lt;" ).replace(/>/g,
     "&gt;" ).replace(/\ "/g,
     " &quot; ").replace(/'/g, " &apos;");
}


对字符串做了多达4次的replace, 这也消耗了不少性能。

所以对于需要传递大数据量的情况,建议将这两个全局函数复写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
__flash__arrayToXML =  function (obj)
{
   var  s = [ '<array>' ];
   var  len = obj.length
   for  ( var  i=0; i<len; ++i) {
     if  ( typeof  obj[i] !==  'undefined' )
     {
       s.push(
         [
         '
<property id="' , i,  '">' ,
         __flash__toXML(obj[i]),
         '</property>'
         ].join( '' )
       );
     }
   }
   
   s.push( '</array>' );
   return  s.join( "" );
};
   
__flash__ecapeXML =  function (s)
{
   var  keywords = {
     '"'  '&quot;' ,
     '<'  '&lg;' ,
     '>'  '&gt;' ,
     '\''  '&apos;'
   };
   
   return  s.replace( new  RegExp( '([\'\"\<\>])' 'g' ),
     function (a, b)
     {
       var  c = keywords[b];
       return  c ? c : a;
     }
   );
};

 

===========================================================================================

    m_flash.CallFunction() 方法需要一个 XML 格式的字符串作为实参.

 

    而这个字符串的格式如下:

 

    <invoke name="functionName" returntype="xml">
        <arguments>
             ... (individual argument values)
        </arguments> 
    </invoke>

 

      节点为 invoke 节点。它具有两个属性:name,指示要调用的函数的名称;以及returntype,总是为 xml。如果函数调用包括参数,则invoke 节点具有一个 arguments 子节点,该节点的子节点是使用单个值格式(下面将予以说明)进行了格式设置的参数值。

 

下表列出了 ActionScript 类以及用于对该数据类型的值进行编码的 XML 格式:

ActionScript 类/值

C# 类/值

格式

注释

null

null

<null/>

 

Boolean true

bool true

<true/>

 

Boolean false

bool false

<false/>

 

String

string

<string>字符串值</string>

 

Number、int、uint

single、double、int、uint

<number>27.5</number> 
<number>-12</number>
 

Array(元素可以是混合类型)

允许混合类型元素的集合,如 ArrayList 或 object[]

<array> 
    <property id="0"> 
        <number>27.5</number> 
    </property> 
    <property id="1"> 
        <string>Hello there!</string> 
    </property> 
    ... 
</array>

property 节点定义各个元素,而 id 属性为从零开始的数值索引。

Object

含有字符串键和对象值的字典,如具有字符串键的 HashTable

<object> 
    <property id="name"> 
        <string>John Doe</string> 
    </property> 
    <property id="age"> 
        <string>33</string> 
    </property> 
    ... 
</object>

property 节点定义各个属性,而 id 属性为属性名称(字符串)。

其它内置或自定义的类

 
<null/> or  
<object></object>

ActionScript 将其它对象编码为 null 或空对象。不管是哪种情况,所有属性值都会丢失。

注: 该表举例说明了 ActionScript 类,并且还列出了等效 C# 类;但是,外部 API 可用来与支持 ActiveX 控件的任何编程语言或运行时进行通信,而不仅限于 C# 应用程序。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值