到目前为止,@rvmook 的部分解决方案在我看来是最接近的。如果您使用 DisplayObjectContainer 的 getObjectsUnderPoint() 方法来获取您翻转的显示对象列表,然后遍历它们并检查哪个具有翻转/鼠标悬停事件处理程序,然后继续向下钻取,这将有所帮助。
所以一个简短的解决方案是:
- 加载您要查找该翻转/鼠标悬停处理程序名称的 swf。*
- 添加翻转处理程序(气泡设置为 true)
- 在翻转处理程序中循环遍历鼠标下具有翻转/鼠标悬停处理程序的对象并获取它们的详细信息。
注意! getObjectsUnderPoint() 如果加载的 swf 具有来自托管加载的 swf 的域的权限,则可以工作。一种查找areInaccessibleObjectsUnderPoint() 方法的方法。如果您拥有已加载的 swf,则应该没有任何问题。否则,您要么需要托管已加载 swf 的域上的 crossdomain.xml,以授予加载程序 swf 的域访问权限(加载程序 swf 应传递 new LoaderContext(true) 作为 Loader 实例的 load() 方法的第二个参数)或使用服务器端以您选择的语言编写的脚本,以首先代理/复制加载的 swf。
这是我的意思的一个基本示例:
package{
import flash.display.*;
import flash.events.*;
import flash.geom.Point;
import flash.net.URLRequest;
import flash.sampler.getMemberNames;
public class BasicInfoTest extends Sprite{
private var cursor:Point = new Point();
public function BasicInfoTest(){
init();
}
private function init():void{
var loader:Loader = addChild(new Loader) as Loader;
loader.load(new URLRequest('B.swf'));
addEventListener(MouseEvent.ROLL_OVER,onOver);
}
private function onOver(event:MouseEvent):void{
cursor.x = mouseX;cursor.y = mouseY;
var obj:Array = getObjectsUnderPoint(cursor);
var numObj:int = obj.length;
for(var i:int = 0 ; i < numObj ; i++){//look for objects under cursor that have rollover/mouseover event handlers
if(obj[i].hasEventListener(MouseEvent.ROLL_OVER) || obj[i].hasEventListener(MouseEvent.MOUSE_OVER)){
var members:Object = getMemberNames(obj[i]);//use @rvmook's method to get listeners
for each (var name:QName in members){
if (name.localName == "listeners"){
for (var j : int = 0; j < obj[i][name].length; j++){
var func:Function = obj[i][name][j];
try{
func.call();
}catch(error:Error){
trace('Methods called on mouse over:',error.message.split('on ')[1].split('.')[0]);//parse error message, you might need to adapt this
trace('StackTrace',error.getStackTrace());
}
}
}
}
}
}
}
}
}
如果您只需要找出方法的名称,就应该这样做。
如果您需要更多信息,您可以访问加载的 swf 的 bytearray 并解析 actionscript 字节码以获取信息。我必须承认二进制和汇编有点超出我的能力范围,但幸运的是,有一些很棒的库可以在运行时在 as3 中反编译 swf 文件。 AS3SWF 是一个很棒的库,但对动作脚本标签的处理不多,而 as3commons 是一个很棒的库集合,专门用于代码方面。
这是对前面示例的改编,它使用 as3-commons 库(bytecode、lang、logging 和 reflect)来显示方法签名和主体(作为 AVM2 指令):
package{
import flash.display.*;
import flash.events.*;
import flash.geom.Point;
import flash.net.*;
import flash.sampler.getMemberNames;
import flash.utils.ByteArray;
import org.as3commons.bytecode.swf.SWFFile;
import org.as3commons.bytecode.swf.SWFFileIO;
import org.as3commons.bytecode.tags.DoABCTag;
public class AdvancedInfo extends Sprite{
private var cursor:Point = new Point();
private var methodInfo:Array;
public function AdvancedInfo(){
init();
}
private function init():void{
var byteLoader:URLLoader = new URLLoader(new URLRequest('B.swf'));
byteLoader.dataFormat = URLLoaderDataFormat.BINARY;
byteLoader.addEventListener(Event.COMPLETE,bytesLoaded);
}
private function bytesLoaded(event:Event):void{
var ba:ByteArray = event.target.data as ByteArray;//get swf bytes
var swfFile:SWFFile = new SWFFileIO().read(ba);//read the bytes using as3-commons
var abcTags:Array = swfFile.getTagsByType(DoABCTag);//get actionscript bytecode (ABC) tags
for each(var tag:DoABCTag in abcTags) methodInfo = tag.abcFile.methodInfo;//loop though tags and get method information
//display and rollOver
var d:Loader = addChild(new Loader()) as Loader;
d.loadBytes(ba);
addEventListener(MouseEvent.ROLL_OVER, rolledOver,true,0,true);
}
private function getMethodDetails(methodName:String):String{
var result:String = '';
for(var i:int = 0 ; i < methodInfo.length; i++){
if(methodInfo[i].methodName == methodName){
result += 'signature:\t'+methodInfo[i]+'\n';
result += 'body:\t'+methodInfo[i].methodBody;
return result;
}
}
return result;
}
private function rolledOver(event:MouseEvent):void{
cursor.x = mouseX;cursor.y = mouseY;
var obj:Array = getObjectsUnderPoint(cursor);
var numObj:int = obj.length;
for(var i:int = 0 ; i < numObj ; i++){
if(obj[i].hasEventListener(MouseEvent.ROLL_OVER) || obj[i].hasEventListener(MouseEvent.MOUSE_OVER)){
var members:Object = getMemberNames(obj[i]);
for each (var name:QName in members){
if (name.localName == "listeners"){
for (var j : int = 0; j < obj[i][name].length; j++){
var func:Function = obj[i][name][j];
try{
func.call();
}catch(error:Error){
var methodName:String = error.message.split('on ')[1].split('.')[0].split('/')[1].split('()')[0];
trace(getMethodDetails(methodName));
}
}
}
}
}
}
}
}
}
出于文档目的,这里是我加载的 SWF 的代码:
package {
import flash.events.*;
import flash.display.*;
public class B extends Sprite {
public function B() {
addEventListener(Event.ADDED_TO_STAGE, init)
}
private function init(event:Event = null) : void {
for (var i : int = 0; i < 1000 ; i++) {
var b:Sprite = addChild(new Sprite()) as Sprite;
b.graphics.lineStyle(Math.random()*3);
b.graphics.drawCircle(-3, -3, 3);
b.x = 3+Math.random() * stage.stageWidth - 6;
b.y = 3+Math.random() * stage.stageHeight - 6;
b.buttonMode = true;
b.addEventListener(MouseEvent.ROLL_OVER, onRollOver);
}
}
private function onRollOver(event : MouseEvent) : void {
event.currentTarget.scaleX = event.currentTarget.scaleY = .1 + Math.random() * 2.1;
}
}
}
这是在我的 AdvancedInfo 示例中使用 getMethodDetails 的方法详细信息跟踪示例:
signature: private function QName[Namespace[private::B]:onRollOver](QName[Namespace[public::flash.events]:MouseEvent]) : QName[Namespace[public]:void]
body:
private function QName[Namespace[private::B]:onRollOver](QName[Namespace[public::flash.events]:MouseEvent]) : QName[Namespace[public]:void]
{
//maxStack=5, localCount=3, initScopeDepth=9, maxScopeDepth=10
0:debugfile [/Users/george/Documents/Flex Builder 3/Del/src;;B.as]:2
2:debugline [28]:4
4:getlocal_0 :5
5:pushscope :6
6:debug [1, 18, 0, 28]:11
11:debugline [29]:13
13:getlocal_1 :14
14:getproperty [QName[Namespace[public]:currentTarget]]:16
16:getlocal_1 :17
17:getproperty [QName[Namespace[public]:currentTarget]]:19
19:pushdouble [0.1]:21
21:getlex [QName[Namespace[public]:Math]]:23
23:callproperty [QName[Namespace[public]:random], 0]:26
26:pushdouble [2.1]:28
28:multiply :29
29:add :30
30:dup :31
31:setlocal_2 :32
32:setproperty [Multiname[name=scaleY, nsset=[Namespace[private::B], Namespace[public], Namespace[private::B.as$25], Namespace[packageInternalNamespace], Namespace[namespace::http://adobe.com/AS3/2006/builtin], Namespace[protectedNamespace::B], Namespace[staticProtectedNamespace::B], Namespace[staticProtectedNamespace::flash.display:Sprite], Namespace[staticProtectedNamespace::flash.display:DisplayObjectContainer], Namespace[staticProtectedNamespace::flash.display:InteractiveObject], Namespace[staticProtectedNamespace::flash.display:DisplayObject], Namespace[staticProtectedNamespace::flash.events:EventDispatcher], Namespace[staticProtectedNamespace::Object]]]]:34
34:getlocal_2 :35
35:kill [2]:37
37:setproperty [Multiname[name=scaleX, nsset=[Namespace[private::B], Namespace[public], Namespace[private::B.as$25], Namespace[packageInternalNamespace], Namespace[namespace::http://adobe.com/AS3/2006/builtin], Namespace[protectedNamespace::B], Namespace[staticProtectedNamespace::B], Namespace[staticProtectedNamespace::flash.display:Sprite], Namespace[staticProtectedNamespace::flash.display:DisplayObjectContainer], Namespace[staticProtectedNamespace::flash.display:InteractiveObject], Namespace[staticProtectedNamespace::flash.display:DisplayObject], Namespace[staticProtectedNamespace::flash.events:EventDispatcher], Namespace[staticProtectedNamespace::Object]]]]:39
39:debugline [30]:41
41:returnvoid :42
}
traits=(no traits)
有关 AVM2 说明的更多信息,请访问 documentation 或 SWF File format specs(PDF 链接)。
涉及我尚未完全探索的第 3 方软件的其他选项是:
- 使用FlashFirebug - 就我个人而言,我还没有设法得到它
正在运行,可能我没有正确设置。
- 使用 getObjectsUnderPoint 通过翻转/鼠标悬停处理程序跟踪有关对象(实例名称等)的信息,然后使用商业反编译器使用获得的信息查找处理程序。
HTH