Archive for the ‘flash’ Category

flash与javascript交互注意事项

Tuesday, September 29th, 2009

网上大多都是帮助文档,其实as和js的交互有很多注意事项,来总结一下:
一.flash到javascript

1. getURL方法

getURL("javascript:s2j_call('参数')","_self");

这个是很古老的了,不过发布成player7或之前的版本都可以支持到它,所以几年来一直用它.
不过只能传递字符串参数,只能做些简单的调用.最致命的是,执行这条语句会导致页面正在加载的异步js进程被阻断,所以如果一个页面渲染了一般flash就发出这个事件,那就等着空白页面吧.
所以现在不要再用这条方法了!

2.ExternalInterface接口

ExternalInterface.call("s2j_call",参数);

发布成8或更高的版本的flash支持该接口,优点是参数可以为json,object,数组,布尔,字符串等,所以和js交互就很方便了.
而且不会阻碍页面异步js进程.目前都使用该方法.

注意:
当flash和页面跨域时候,页面需要允许flash操控其函数,所以在插入flash时,需要加入

<param name="allowScriptAccess" value="always" />

二.javascript到flash

这个才是重点,简单的来说,就是在flash里绑定js事件
flash里:

ExternalInterface.addCallback("j2s_callback",this, j2s_callback);
function j2s_callback(_p)
{
    
trace(_p);
}

js里,首先要获得对flash元素的引用,考虑到不同浏览器,需要对object和embed标签都赋予不同的id,然后判断浏览器类型,通过getElementById来获取ref.然后通过ref.j2s_callback来调用flash内方法.

注意:
1.当flash和页面跨域时候,flash里需要加入允许js添加callback的安全许可:

System.security.allowDomain("");
System.security.allowInsecureDomain("");

2.由于各个浏览器的缓存机制和页面加载机制都不同,所以不要指望flash在addCallback执行的时候确实相应的js程序已经定义了,如果没有的话,addCallback是不会成功的.
所以,可以设个轮循来检测页面是否初始完成.随便用1.0的语法写一下:

this.onEnterFrame = function()
{
    
if (ExternalInterface.call("s2j_check") == "ok")
    
{
        
ExternalInterface.addCallback("j2s_callback",this, j2s_callback);
        
this.onEnterFrame = null;
    
}
};

页面:

function s2j_check()
{
    
return "ok";
};
function j2s_callback()
{
    
//to do 调用flash;
};

这样,就可以保证addCallback之前函数已经被初始化完毕,本步骤在as3里可能会报错,需要try一下.

flash摄像头被禁止之mms.cfg与AVHardwareDisable

Friday, August 7th, 2009

突然接到很多用户投诉摄像头开启不了,也没有任何提示.
查了半天原来是360还不知道金山的升级补丁把flash的影音功能完全禁止了.
神经病的,还让不让开发者活了.
mms.cfg 位置:

Windows (Vista, XP and 2000) %WINDIR%\System32\Macromed\Flash
Macintosh /Library/Application Support/Macromedia
Linux, Flash Player 9 /etc/adobe/

里面有很多管理员可以设置的属性,比如:AVHardwareDisable
不过很傻的是:

If this value is set to 1, the privacy pop-up dialog never appears. However, the user can still access the Privacy tab and the Settings Manager, as well as tabs to let them designate which camera or microphone an application can use. These settings will appear functional, but any choices the user makes are ignored.

设成1后,不会弹出setting选项让用户设置了,即使用户打开,设置的也都无效…
不过还好有这个,至少让人知道有没有被禁止:

In ActionScript, an author can query the System. capabilities. avHardwareDisable property to determine the value of this setting.

用flash cs4测试果然可以了,谁知道用flash8打开测试一下,无论mms.cfg里如何设置,System.capabilities.avHardwareDisable 都返回true,我下的文档明明是8的guide文档.
于是,只好无论如何都在舞台上放一个提示,并且exactly放到这个下面,

adobe

当被AVHardwareDisable阻止弹出的时候,这个modal的框就不会出来,用户就可以看到提示了.
……

iframe跨域函数调用

Wednesday, July 29th, 2009

子iframe页面如何跨域调用主页面的函数?
如果仅仅是二级域名不同,可以通过指定 document.domain = “xxx.com”; 来共享权限.
但如果是完全不同的两个域呢,一直以来都认为是实现不了的.
前段时间和淘宝项目合作的时候,发现他们可以做到,仔细研究了一下.原来是这样的.
当然前提条件是可以有两个域的控制权限.

情况如下,以下代码在页面A:

<script>
function waiting4Callback(_p)
{
    alert(_p)
}
</script>
<iframe id="IFrameMain" marginWidth=0 marginHeight=0 src="跨域页面B" frameBorder=0 scrolling="no" width="1000" height="500"></iframe>

如果你尝试在跨域页面B里调用:

window.parent.waiting4Callback("hello!");

结果,明显是不可以的.

这时,解决方法是先在页面A所在的域下放一个页面C,就叫 proxy.html 好了,代码如下:

<script type="text/javascript">
window.parent.parent.waiting4Callback(window.location.hash.substring(1));
</script>

这时候window.parent.parent就是页面A了,且A,C之间不跨域.

然后,在页面B里面再iframe一次页面C.代码如下:

<iframe id="ProxyWin" name="ProxyWin" marginWidth=0 marginHeight=0 src="" frameBorder=0 width="0" scrolling=0 height="0"></iframe>

这时候,页面B就可以通过iframe页面C来调用页面A的函数并传递参数了,这么写:

document.getElementById("ProxyWin").src = "页面C地址" + "?r="+Math.random()+"#"+"要传递的参数";

页面C好可怜,背叛了页面A不说,还要被页面B不停的重刷,刷到完全失去自我,就为了取个hash.
页面C说,我取的不是hash,是寂寞……

flash+php截图后保存图片

Monday, January 19th, 2009

as2时代要实现该功能只有在本地draw完bitmap后,把所有widthxheight的图片都储存到数组里然后post给php,php通过gd库来生成,虽然可以不过效率就…一张120×90的图就够flash运算半天了.
as3要实现这个功能虽然还要借助php,但是只是借助php把图片数据给echo出来而已.图片生成关键步骤都在客户端进行了.
另外还需要adobe官方的as3corelib包.

客户端:

import com.adobe.images.JPGEncoder;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.net.URLRequestHeader;
import flash.net.navigateToURL;
import flash.utils.ByteArray;
 
//画位图数据
var jpgSource:BitmapData = new BitmapData (picture.width, picture.height);
jpgSource.draw(picture);
//生成编码容器
var jpgEncoder:JPGEncoder = new JPGEncoder(95);
//将位图数据编码到容器内成为ByteArray流
var jpgStream:ByteArray = jpgEncoder.encode(jpgSource);
//压缩ByteArray流
jpgStream.compress();
//添加stream的header请求
var header:URLRequestHeader = new URLRequestHeader("Content-type", "application/octet-stream");
var jpgURLRequest:URLRequest = new URLRequest("save.php");
jpgURLRequest.requestHeaders.push(header);
jpgURLRequest.method = "POST";
jpgURLRequest.data = jpgStream;
//推送图片数据到服务器端
navigateToURL(jpgURLRequest, "_blank");
//用urlLoader的情况,需要指明Data数据是一个包含原始二进制数据的 ByteArray 对象
//loader.dataFormat = URLLoaderDataFormat.BINARY;

服务器端:

<?php
$jpg = gzuncompress($GLOBALS["HTTP_RAW_POST_DATA"]);
header("Content-Type: image/jpeg");
echo $jpg;
?>

搞了一个as3的开源项目到google code上

Wednesday, December 24th, 2008

只是为了自己备份下写过的功能而已,如果谁有兴趣也可以去checkout下来.注释和文档很完整的.
名叫astrois,会不断更新:
http://code.google.com/p/astrois/
IE支持在线文档地址:
http://astrois.googlecode.com/svn/trunk/docs/index.html

flash里的背景平铺

Monday, December 1st, 2008

其实有很多方法实现,这里就按播放器的版本从低到高的实现方法来说好了:

1.载入位图后duplicateMovieClip
如果播放器必须发布成<=7,就只能使用以下方法,原理就是载入一个swf,它的库里有个包含linkID的位图movieclip,attachMovie后遍历duplicateMovieClip到舞台上。

  1. var a:Number = Math.floor(Stage.width / img_width);
  2. var b:Number = Math.floor(Stage.height / img_height);
  3. for (var i:Number = 0; i<=b; i++) {
  4.     for (var j:Number = 0; j<=a; j++) {
  5.         bg_mc.duplicateMovieClip("bg_"+i+"_"+j, bg_mc.getNextHighestDepth(), {_x:j*img_width, _y:i*img_height});
  6.     }
  7. }

2.载入位图draw后,生成bitmap平铺。
如果播放器可以发布成8,就可以使用以下方法。其实原理和1差不多,不过8开始引入了Bitmap,因为平铺的是bitmap,所以肯定比1更节约资源。

  1. var bmpData:BitmapData = new BitmapData(img_width, img_height);
  2. bmpData.draw(img_target);
  3. for(var i:Number = 0;i<Math.ceil(h/img_height);i++)
  4. {
  5.      for(var j:Number = 0;j<Math.ceil(w/img_width);j++)
  6.      {
  7.          var bmp:Bitmap = new Bitmap(bmpData);
  8.          bmp.y = img_height*i;
  9.          bmp.x = img_width*j;
  10.      }
  11. }

3.载入位图draw后,通过位图填充功能填充graphic子对象。
如果播放器可以发布成9,就可以使用以下方法。9开始引入了位图填充,所以根本不用考虑什么平铺,直接就和Photoshop里的自定义图案填充一样方便。

  1. var bmpData:BitmapData = new BitmapData(img_width, img_height);
  2. bmpData.draw(img_target);
  3. var graphic:Graphics = shell.graphics;
  4. graphic.beginBitmapFill(bmpData);
  5. graphic.drawRect(0,0,w,h);
  6. graphic.endFill();

as2 对象查看函数

Wednesday, August 13th, 2008
  1. function traceObject(obj:Object, indent:Number):Void {
  2.     indent = indent ? indent : 0;
  3.     var indentString:String = "";
  4.     var i:Number;
  5.     var prop:String;
  6.     var val;
  7.     for (i=0; i<indent; i++) {
  8.         indentString += " ";
  9.     }
  10.     for (prop in obj) {
  11.         val = obj[prop];
  12.         if (typeof (val) == "object") {
  13.             trace(indentString+" "+prop+": [Object]");
  14.             traceObject(val, indent+2);
  15.         } else {
  16.             trace(indentString+" "+prop+": "+val);
  17.         }
  18.     }
  19. }

方便以后用。

发布成fp8++的swf中利用bitmapData平滑显示图片

Tuesday, August 5th, 2008

其实在flash7和更早的版本只要用_quality = “HIGH”或”BEST”就可以控制图片平滑显示了,不过这样有个缺点,所有场景和元素都会平滑,严重消耗资源。
在flash8里adobe不让通过调整_quality来平滑图片了,可以利用bitmapData来替换。
在图片的MovieClipLoader加载完毕的时候:

  1. import flash.display.BitmapData;
  2. function __onLoadInit(target:MovieClip):Void {
  3.     var bd:BitmapData = new flash.display.BitmapData(target._width, target._height);
  4.     bd.draw(target);
  5.     target.attachBitmap(bd, 1, "auto", true);
  6. }

然后,这个target就被平滑的bitmapData替换掉了。
不过adobe似乎忘记了他对bitmapData的安全限制,fp9以下的客户端根本无法跨域draw到bitmapData,即使是fp9 plus,也要去loadPolicyFile,所以当图片分布在很多台服务器上的时候,根本没有什么好的办法解决这个问题,总不至于每打开一个app就遍历去加载几十个crossdomain.xml吧。
你干脆就不要让MovieClipLoader加载他出来,这样就没什么安全性问题了,这个世界也清净了,既然能加载出来,又不让draw,自相矛盾的啊,倒不如用回7算了。

fdt升级后非常郁闷

Tuesday, October 23rd, 2007

每次build项目的时候都会出现假死,有时候就变成真死了。搞得每次切换项目后都提心吊胆的。
记得之前的版本不是这样的啊,是后台自动build,而且不会影响到前面的操作。准备用一段时间后再换回旧的试试感觉。
更郁闷的是,操作快一点经常会导致eclipse假死并被down掉(当然,我没有开自动build)。
总之就是不如之前的版本顺利,倒是反而用flex builder写Focuswing的过程中,一次都没有出现过问题。
所以我感觉,如果写as2的话,没什么必要升级fdt。如果写as3的话,用fb好了。

关于as3事件的笔记

Friday, August 17th, 2007

as2时代直接在dispatchEvent的时候跟上想跟的参数就可以了,as3增加了一个Event的继承类来承担其中的信息传递,不过看书看到关键时刻居然就没有了。于是笔记一下类实例怎么向外发送事件和传递参数,来点实用的。
发送事件的Guest,在Guest内发送”do_b”的Event:

  1. var e:GuestEvent = new GuestEvent(GuestEvent.DO_B);
  2. e.args = {author:"hirokimo",time:"21:10"};
  3. this.dispatchEvent(e);

这时候为了传递参数,使用一个继承Event的自定义事件类GuestEvent:

  1. package
  2. {
  3.     import flash.events.Event;   
  4.     public class GuestEvent extends Event
  5.     {
  6.         public static const DO_A:String = "do_a";
  7.         public static const DO_B:String = "do_b";
  8.         public static const DO_C:String = "do_c";      
  9.         public var args:*;   
  10.         public function GuestEvent(_type:String)
  11.         {
  12.             super(_type);
  13.         }
  14.     }
  15. }

最后,在类外面添加侦听和接收的地方:

  1. package
  2. {
  3.     public class EventTest
  4.     {
  5.         public function EventTest()
  6.         {
  7.             var guest:Guest = new Guest();
  8.             guest.addEventListener(GuestEvent.DO_B,handleB);
  9.         }
  10.         private function handleB(e:GuestEvent):void
  11.         {
  12.             trace("author:"+e.args.author
  13.             +" time:"+e.args.time);
  14.             //author:hirokimo time:21:10
  15.         }
  16.     }
  17. }

大功告成,之后就可以顺利的发送事件参数了。
不过有一点值得注意:Guest类里有时需要在初始化后直接dispatch一个Event出来,这时候因为外部addEventListener动作还没有完成,listener是收不到事件的。
这个问题很容易被忽略,如果一定要这么做,可以:
1.Guest初始化后timer几百毫秒再dispatch 或者
2.外面addEventListener完之后,主动调guest.xxx来发送。