Flash

2014年05月10日 15:16GMT+8

可以说 haxe 的目标平台最稳定的就是 flash 平台了

  • flash.Lib 提供几个方法,也许会很有用, 如:

    // 在浏览器中将 trace 输出到浏览器的 console
    // 当你的 flash 需要在浏览器中调试时这非常有效
    Lib.redirectTraces()
    
    // 调用 flash 原生的 trace,例如当你在处于 Worker 时,就能能用这个方法了
    // 如果你用 flashdevelop 可以在 视图 -> flash 日志视图里看到输出,
    Lib.trace(arg:Dynamic)
    // 或者加上 -D fdb 参数将重定向所有 trace 语句
    

跨域安全沙箱错误

crossdomain.xml 中文参考: http://www.adobe.com/cn/devnet/adobe-media-server/articles/cross-domain-xml-for-streaming.html

很可能需要添加编译参数 -D network-sandbox 使得 swf 只能访问网络.

注意: 使用 Workder 时,工作线程总是为 只访问网络.

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
	<site-control permitted-cross-domain-policies="all" />
    <allow-access-from domain="*" />
    <allow-http-request-headers-from domain="*" headers="*"/>
</cross-domain-policy>

编译

仅针对 flash 平台, 这个清单可能并不完整, 详细通过 haxe --help 查询

# 将 hx 源码直接编译成 swf 文件
haxe -swf out.swf -main Main

# 将 hx 源码打包成 swc, 将输出文件名改为 swc, 并且不需要指定 -main 参数
# 其它一些细节后边再述
haxe -swf out.swc Main.hx


# 将 hx 源码编译成 as3 文件, 通过 -as3 并指定 outdir 目录,注意: 生成的代码仅供参考
haxe -as3 outdir -main Main

调试

在编译时指定 -D fdb, 这时 trace 将不再以 Textfiled 的形式输出了

相关命令行参数

用于 haxe 命令行参数

# 更严格的类型检测, 反正加上就是
--flash-strict 			: more type strict flash API

# 指定 flash 版本, 例: -swf-version 10.3, 或 -swf-version 11.6
-swf-version <version>	: change the SWF version

# 指定 flash 文件头, 例	: -swf-header 800:600:FFFFFF
-swf-header <header>: define SWF header (width:height:fps:color)

# 添加 swf 库, 文件通常为 swc 格式
-swf-lib <file>			: add the SWF library to the compiled SWF

#
-swf-lib-extern <file>	: use the SWF library for type checking

# (个人认为)实际上这是被弃用的, 见补充说明小节,
--gen-hx-classes		: generate hx headers for all input classes

关于 flash 版本的问题, haxe 的 -swf-header 使用第一行的样式, 其实可以查看 flashdevelop 的 flash生成项目属性可以看得能够生成哪些版本

f: 9.0	10.0  10.1  10.2  10.3	11.0  11.1 ~ 11.9  12.0  13.0  14.0  15.0  16.0  17.0
i:  9    10    10    11    12    13    14  ~  22    23    24    25    26    27    28

Defines

通过 -D 或相关宏定义的值

# 启用交互式调试的 Flash 内容。它在 SWF 输出中包含调试器标记,并添加额外的调试信息。
# 这也将把 trace 输出重定向到 flashlog.txt, 而不是 swf 中的 Textfiled
fdb                    : Enable full flash debug infos for FDB interactive debugging

# 使用 `haxe` 名, 作为 flash 的引导类名, 替换掉默认的 boot_xxx 名, 这项定义将会 自动用于编译成 swc 时
haxe-boot              : Given the name 'haxe' to the flash boot class instead of a generated name

# 更改 flash 网络沙箱模式,  定义后将为 只访问网络, 默认为只访问本地
network-sandbox        : Use local network sandbox instead of local file access one

# 禁用 swf 压缩
no-swf-compress        : Disable SWF output compression

# flash 硬件加速 第 1 级 - 直接
swf-direct-blit        : Use hardware acceleration to blit graphics

# flash 硬件加速 第 2 级 - GPU
swf-gpu                : Use GPU compositing features when drawing graphics

## 注: swf-gpu 和 swf-direct-blit 只适用于 Flash Player 独立播放器时
## 当 位于浏览器中播放时, swf-direct-blit 对应 wmode="direct", 而 swf-gpu 则是 wmode="gpu"

# 嵌入元数据 xml文件到 swf,以便搜索引擎检索信息, 示例: -D swf-metadata=data.xml
# 元数据 xml文件 格式参见 http://www.adobe.com/products/xmp.html
swf-metadata           : =<file> Include contents of <file> as metadata in the swf.

# 示例: http://old.haxe.org/doc/flash/preloader
swf-preloader-frame    : Insert empty first frame in swf, To be used together with -D flash-use-stage and -swf-lib

# 配合 swf-preloader-frame 的.
flash-use-stage        : Keep the SWF library initial stage. To be used together with -swf-lib. Place objects found on the stage of the SWF lib. (Not to be used together with -swf-header)


# 编译时将 private 属性将变成 protected 而不是 public
# 实际上 hx 中的 private 仅仅只用于限制 hx 代码, 生成 swf 后, 都为 public
swf-protected          : Compile Haxe private as protected in the SWF instead of public

# 设置 swf 超时时间
swf-script-timeout     : Maximum ActionScript processing time before script stuck dialog box displays (in seconds)

# ???
swf-use-doabc          : Use DoAbc swf-tag instead of DoAbcDefine

# 添加 Scout (aka Monocle) 支持. Since SVN r5429
advanced-telemetry     : Allow the SWF to be measured with Monocle tool

# 编译时将 private 属性将变成 protected 而不是 public
# 实际上 hx 中的 private 仅仅只用于限制 hx 代码, 生成 swf 后, 都为 public
swf-protected          : Compile Haxe private as protected in the SWF instead of public

Metas

标记在源码上的特殊元数据

@:bind				  : 覆盖 flash 的同名定义, 当在 Haxe 中声明了一个类(不是extern类)已经存在于 SWF 库, 将会报错.

@:setter(property)    : 示例: 见补充说明的 "override flash"

@:getter(property)    : 同 @:setter

@:meta                : 生成相应的 Flash 元数据, 例: @:meta(Event(name="test",type="Foo")).

@:ns("namespace")     :指定的字段或方法的命名空间


@:sound		: 用于嵌入声音,
			  例: @:sound("blit.mp3") class MySound extends flash.media.Sound{}

@:file		: 以 ByteArray 的方式嵌入文件,
			  例: @:file("a.dat") class MyByteArray extends flash.utils.ByteArray{}

@:font		: 嵌入字体,仅限 ttf. 第二个参数为可选字符,而不是全部字符
			  例: @:font("font/ceri0553.ttf", "a-zA-Z0-9~!@#$%^&*()_+=-][}{.,;\":><") class MyFont extends Font { }

@:bitmap	: 以 bitmapData 形式嵌入图片,
			  例: @:bitmap("path/logo.png|jgp|gif") class MyBitmapData extends flash.display.BitmapData{}

黑魔法

用于直接在 haxe 中直接写 AS3 代码. 参看 http://old.haxe.org/doc/advanced/magic 由于太多这里就不全部列出了.

# __global__ 调用 as3 的全局成员
untyped __global__["undefined"];
untyped __global__["uint"]; //basic type
untyped __global__["flash.display.DisplayObject"];

# 创建 as3 源生类
__new__(className, arg1, arg2 ...)


__keys__(obj)		# 将构建一个数组包含 obj 的 keys. 例: for(k in __key__(obj))

__delete__(o, f)	# delete o.f

__in__ (e,f) 		# e in f

__is__(e, t)		# e is t

__has_next__(o, i)	# 见 ds.unsafeStringMap, 这个将会修改 i 的值

__forin__(o, index)	# 复制 UnsafeIntMapValuesIterator 即可用.
__foreach__(o, index)#

# 对于 flash 平台, 使用 __keys__ 遍历要比使用 Reflect.Fields 要更有效率
var obj = Lib.current.stage.loaderInfo.parameters;
for(k in untyped __keys__(obj)){
	trace(k +": "+untyped obj[k]);
}

extern class

haxe 能直接引用并解析 AS3 的 swc 库, 因此没特别的地方(参看 patch files)根本不需要写 extern class;

swc

导出

一些参考 https://github.com/jcward/HaxeSWCExample 和 http://old.haxe.org/manual/swc?lang=cn , 示例:

# 单个文件或多个文件, 每个 hx 文件不要带有扩展名, 因为会与包名混淆
# A, B C 分别代表 A.hx B.hx com/some/C.hx....
haxe -swf bin/hxlib.swc A B com.some.C


# 导出整个文件夹, 这种方法仅用于导出带有 **包名** 的整个目录.
# 参考 haxe.macro.Compiler.include 方法
haxe -swf bin/hxlib.swc --macro "include('com.some')"

NOTE: 在 AS3 中使用 haxe 导出的 swc 库.需要初使化 haxe.initSwc(root_sprite)

引用

在 haxe 引用 AS 的 swc 的外部库很简单, 只要指编译参数 -swf-lib libname.swc 就行了,

haxe -main Test -swf-lib libname.swc -swf Test.swf

如果你使用 openfl, 那么则在 project.xml 中配置

<haxeflag name="-swf-lib" value="pathto/libname.swc" if="flash" />

错误 1: You cannot have both a static and a non static member or function with the same name…

问题解决原文, 需要建一个 patch 文件如:

// haxe 调用 starling.swc 示例
// 将这个文件 保存为 Starling.patch 或其它任意文件名.
// 项目中添加 haxeflag 编译选项 --macro "patchTypes('Starling.patch')"

-starling.core.RenderSupport.clear
-starling.core.Starling.context
-starling.core.Starling.juggler
-starling.core.Starling.contentScaleFactor

错误 2: 当调用 flash alchemy 打包的 swc 库时,将会出错, 但使用 -debug 编绎选项却能通过. 问题#1976

此问题已经解决, 只是还没合并

patch files

当在 haxe 中调用 flash 的 swc 库时, haxe 编译器能自动提取里边的定义,虽然大多数情况下不会造成问题,

但在某些情况下你可能必须创建 patch file, patch file 将修改 flash库中已经存在类的字段类型,

// Removes a class field from Haxe definition
-flash.accessibility.Accessibility.new

// Adds metadata to a given class
@:require(flash10) flash.desktop.Clipboard

// Adds metadata to a given class field
@:require(flash10) flash.display.BitmapData.setVector

// Modifies a given field type
flash.display.DisplayObject.blendMode : BlendMode;

// Modifies a static field type
static flash.system.IME.conversionMode : IMEConversionMode;

// Modifies all function parameters with this specific name
flash.display.BitmapData.$blendMode : BlendMode;

// Modifies a single function parameter
ClassName.$functionName__parameterName : Type;

// Convert a class made of statics vars into an Haxe enum
enum flash.text.TextFieldAutoSize;

大量这样的例子可以从 this patch file 获取,这对是对flash的定义的一个补充。

You can use a patch file with –macro patchTypes(‘patchFile’)

自定义 Preloader

总的来说不算太复杂, 只是需要一些耐心

  • Preloader

  • openfl 项目, haxepunk 库源码有一个很好的示例.

    <app preloader="MyPreloader" />
    <!-- 源码中必须能查找得到MyPreloader这个类,也可以指定包名如: -->
    <app preloader="com.myname.Preloader" />
    

补充

override flash

覆盖 flash 的 setter 时要注意 返回值类型应该为 Void, 而 Haxe 的 setter 却应返回对应类型.

class LEByteArray extends ByteArray{
	public function new(len:UInt) {
		super();
		super.length = len;
		super.endian = Endian.LITTLE_ENDIAN;
	}
	override public function clear():Void {}
	@:setter(length) function set_length(len:UInt):Void {
		if(len > super.length){
		  super.length = len;
		}else if(len < super.length ){
			throw 'You are not allowed to change the length.';
		}
	}
	@:setter(endian) function set_endian(endian:String):Void {
		//throw new Error( 'You are not allowed to change the endian.' );
		throw 'You are not allowed to change the endian.';
	}
}

–gen-hx-classes

解析 swc 库,并自动生成库中所有类的 extern class, 但是目前 haxe3 已经可以直接使用 flash 的 swc 库, 不需要做这多余的步骤了. 所以不用关心这个能做什么.

haxe -swf nothing.swf --no-output -swf-lib lib.swc --gen-hx-classes

SWF文件结构

SWF = HEADER + TAGS, 数据结构描述:

  • swf使用 twips 表示 Rect 数据,1 twips=1/20 pixel

  • 无特别说明,使用 litle endian 结构,后边用 LE 表示

  • 定点数, (8-8),(16-16) 二种 使用 litle endian.

  • 浮点数, 16(半精度) ,32(单精度) ,64(双精度)

  • 变长数,通常为低于32位, 使用 符号位扩展成 Int 类型. signExtend1, signExtend8, signExtend16

  • 字符串,字符串是以全0结束的byte序列,采用utf-8编码

通过参考 format 库中的 swf 目录:

# ----- SWF HEADER -----
#偏移(字节)	大小		描述
00~02		 3		 # CWS(deflate算法)已压缩, 而 FWS 则未压缩, ZWS 表示为 lzma压缩
03			 1		 # flash 版本号
04~07		 4		 # LE小头 Int 类型,解压后, 整个 swf 的大小

# 1. 获得后边的二进制数据, 如果压缩则解压(这里没有考虑到 lzma 算法生成的压缩),
# 2. 然后使用 bitsInput(位) 的方式读取一个 Rect 数据: 参考 format/tools/bitsIntput
#偏移(位)		大小		描述
b0~b04		 5		 # 获得 left ,right ,top ,bottom 所占用的位数 SB(符号位扩展), 5个二进制最多表示 31 位
b05+SB		SB		 # left, 单位为 twip, 1 twip等于1/20象素
+= SB 		SB 		 # right
+= SB		SB		 # top
+= SB		SB		 # bottom

# 切换回 字节模式
#偏移(字节)	大小		描述
00~01		 2		# 定点数8-8, 帧率
02~03		 2		# 定点数8-8, 总帧数

# ----- SWF TAGS -----