Apache Flex 4.16.1 快速入门与集成示例
用 10 分钟在 Apache Flex 4.16.1 上写出并编译第一个 MXML 加 ActionScript 的 SWF 应用,覆盖 mxmlc 编译验证、file 与 swfdump 产物检查、高频坑排查、Ant flexTasks 集成与 SWC 组件库复用,并给出 RIA 技术选型建议,全部已在 Ubuntu 22.04 实测。
Apache Flex 4.16.1 快速入门与集成示例
目标:10 分钟内在 Apache Flex 4.16.1 上写出第一个 MXML + ActionScript 应用并编译出 SWF,掌握 file/swfdump 两步产物验证;踩平 playerglobal 缺失、locale 中文等高频坑;完成 Ant flexTasks 构建集成与 SWC 组件库复用两个最常用的工程化场景。以下全部命令与回显均已在 Ubuntu 22.04(x86_64)、OpenJDK 1.8.0_504、Apache Flex SDK 4.16.1(build 20171115)实测通过。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS(x86_64)
- JDK:OpenJDK 1.8.0_504(
java -version实测) - 构建工具:Apache Ant 1.10.12(第四章 Ant 集成使用)
- SDK:Apache Flex 4.16.1(build 20171115),安装于
/opt/apache-flex-sdk-4.16.1-bin,含 playerglobal 32.0(安装过程见 Ubuntu 安装指南篇) - 编译产物验证工具:
file命令 + SDK 自带bin/swfdump - 示例工程目录:
/root/hello(最小应用)、/root/libdemo(SWC 库)
确认基线(实时回显):
java -version 2>&1 | head -1
mxmlc -version
openjdk version "1.8.0_504"
Version 4.16.1 build 20171115
⚠️ 注意:本文所有
mxmlc调用假定PATH已含/opt/apache-flex-sdk-4.16.1-bin/bin(配置方法见安装指南篇第七章);未配置时把mxmlc换成全路径即可。编译链在 JDK 8/11/17 实测均可运行,但 asdoc 需要 JDK 8,统一基线选 8 最省心。
二、10 分钟最小可用
本节从空目录到编译出第一个 SWF 共 4 步,全程约 10 分钟:建目录写 MXML(3 分钟)→ 编译(1 分钟,首次加载框架库略慢)→ file 验证(1 分钟)→ swfdump 深检(5 分钟)。
2.1 编写第一个 MXML 应用
创建工程目录与 HelloWorld.mxml:
mkdir -p /root/hello
/root/hello/HelloWorld.mxml 全文(最小可用,直接照抄):
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
width="400" height="200">
<fx:Script>
<![CDATA[
import mx.controls.Alert;
[Bindable]
private var msg:String = "Hello Apache Flex 4.16.1";
private function onClick():void {
var n:int = int(inputBox.text);
msg = "平方 = " + (n * n);
}
]]>
</fx:Script>
<s:VGroup x="24" y="24" gap="10">
<s:Label text="{msg}" fontSize="18" color="0x1B5E20"/>
<s:TextInput id="inputBox" text="12" width="160"/>
<s:Button label="计算平方" click="onClick()"/>
</s:VGroup>
</s:Application>
逐项说明:
<s:Application>:Spark 组件体系的根级可视组件,命名空间library://ns.adobe.com/flex/spark由 SDK 内置清单(mx-manifest 等文件)映射到真实类。<fx:Script>:内嵌 ActionScript 3 代码块,[Bindable]让msg变化时自动刷新绑定它的Label。click="onClick()":MXML 内联事件绑定;onClick()把输入框文本转成整数并平方,回写msg。- 编译器会把这份 MXML 编译为一个 SWF:入口类是自动生成的
_HelloWorld_mx_managers_SystemManager,这就是 2.3 节 swfdump 里 FrameLabel 的由来。
2.2 编译
cd /root/hello && mxmlc HelloWorld.mxml 2>&1 | tail -2
Loading configuration file /opt/apache-flex-sdk-4.16.1-bin/frameworks/flex-config.xml
/root/hello/HelloWorld.swf (511462 bytes)
不传任何参数时,编译器从默认配置 frameworks/flex-config.xml 读取目标 player(32.0)、SWF 版本(43)、库路径(frameworks/libs 与 libs/player/32.0)等全部设定,源文件名即输出文件名(同目录同名 .swf)。
2.3 验证产物:file 与 swfdump
第一层验证,file 识别文件魔数与版本:
file HelloWorld.swf
HelloWorld.swf: Macromedia Flash data (compressed), version 43
第二层验证,SDK 自带的 swfdump 解析 SWF 内部结构:
/opt/apache-flex-sdk-4.16.1-bin/bin/swfdump HelloWorld.swf 2>/dev/null | head -12
<!-- Parsing swf file:/root/hello/HelloWorld.swf -->
<!-- ?xml version="1.0" encoding="UTF-8"? -->
<swf xmlns='http://macromedia/2003/swfx' version='43' framerate='24' size='8000x4000' compressed='true' >
<!-- framecount=2 length=1097190 -->
<FileAttributes useDirectBlit='false' useGPU='false' hasMetadata='true' actionScript3='true' suppressCrossDomainCaching='false' swfRelativeUrls='false' useNetwork='true' brokerProductManager='false' brokerLocalConnection='false'/>
<Metadata>
<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'><rdf:Description rdf:about='' xmlns:dc='http://purl.org/dc/elements/1.1'><dc:format>application/x-shockwave-flash</dc:format><dc:title>Apache Flex Application</dc:title><dc:description>http://flex.apache.org/</dc:description><dc:publisher>Apache Software Foundation</dc:publisher><dc:creator>Apache Software Foundation</dc:creator><dc:language>en_US</dc:language><dc:date>Oct 15, 2026</dc:date></rdf:Description></rdf:RDF>
</Metadata>
<ScriptLimits scriptRecursionLimit='1000' scriptTimeLimit='60'/>
<SetBackgroundColor color='#FFFFFF'/>
<ProductInfo product='Apache Flex' edition='' version='4.16' build='20171115' compileDate='10/15/26 7:56 AM'/>
关键信息解读:version='43' 与配置的 target-player 32.0 对应;size='8000x4000' 是 twips 单位(1 px = 20 twips),即 MXML 里的 400x200;actionScript3='true' 确认是 AVM2 字节码;ProductInfo 记录了编译器版本与编译时间。标签里还能看到入口 FrameLabel(续行):
/opt/apache-flex-sdk-4.16.1-bin/bin/swfdump HelloWorld.swf 2>/dev/null | grep FrameLabel
<FrameLabel label='_HelloWorld_mx_managers_SystemManager'/>
<FrameLabel label='HelloWorld'/>
2.4 验证点与预期结果
拿到以下结果即编译闭环成功,任一不符按第三章排查:
| 检查项 | 预期(实测值) | 不符时排查 |
|---|---|---|
| mxmlc 退出后产物 | HelloWorld.swf (511462 bytes) 量级(约 511 KB) | 报 unable to open 'libs/player/11.1/playerglobal.swc' → 3.1 节 |
file 识别 | Macromedia Flash data (compressed), version 43 | data 而非 Flash → 检查是否编译成功 |
| swfdump 首行 | version='43' framerate='24' | 打不开 → 文件损坏或非 SWF |
| ProductInfo | product='Apache Flex' version='4.16' build='20171115' | 版本不符 → 多 SDK 共存时 FLEX_HOME 指错 |
⚠️ 注意:SWF 无法像 Java 的 jar 那样直接「跑起来看输出」——运行它需要 Flash Player 运行时(浏览器插件已于 2020 年底停止服务)。服务器端的可信验证就是本文的 file + swfdump 组合;需要在浏览器播放存量 SWF 时,用 swfobject 包装页加带 Flash 插件的历史浏览器环境(第四章给出包装页与发布步骤)。
三、快速入门高频坑
以下三个坑在第一次编译 Flex 应用时出现频率最高,均为实测复现。
3.1 坑一:目标 player 版本没有对应的 playerglobal
现象:编译报错(实测回显):
/opt/apache-flex-sdk-4.16.1-bin/frameworks/flex-config.xml(65): Error: unable to open 'libs/player/11.1/playerglobal.swc'
定位:-target-player 指定的版本必须在 frameworks/libs/player/<版本>/playerglobal.swc 有对应文件。本文环境只安装了 32.0。修复:去掉 -target-player 参数使用配置默认值(32.0),或安装对应版本的 playerglobal(下载方法见安装指南篇第五章)。
3.2 坑二:跳过官方安装器导致配置未修正
现象:编译报错(实测回显):
/opt/apache-flex-sdk-4.16.1-bin/frameworks/flex-config.xml(85): Error: unable to open '{playerglobalHome}/32.0'
定位:原始 bin 包里的 flex-config.xml 用 {playerglobalHome} 占位 library-path 前缀,跑过 ant -f installer.xml 后才被替换为 libs/player。这个报错与 JDK 版本无关(实测在 JDK 17 上同样触发)。判断与修复:
grep -c playerglobalHome /opt/apache-flex-sdk-4.16.1-bin/frameworks/flex-config.xml
2
计数大于 0 即未修正;跑安装器或按安装指南篇 5.3 节手工 sed 三个占位值。
3.3 坑三:POSIX locale 下中文日志变问号
现象:编译含中文的 MXML 时,编译器报错回显里的中文显示为问号(实测 <mx:Button label="推送 66.6"> 在错误提示中变成问号),但 SWF 本身的字符串编译是正确的。修复:会话设置 export LANG=C.UTF-8 后重跑,日志恢复正常显示。
四、与 Ant flexTasks 集成
SDK 自带 ant/lib/flexTasks.jar,把 mxmlc 封装成 Ant 任务,并附带 HTML 包装生成器。工程上用它替代裸命令行,实现一次构建出 SWF 加播放页。
4.1 build.xml 全文
/root/hello/build.xml(实测可用版本,直接照抄;路径全部显式写出,便于跨机器复现):
<?xml version="1.0" encoding="UTF-8"?>
<project name="flex-hello" basedir="/root/hello" default="build">
<property name="FLEX_HOME" value="/opt/apache-flex-sdk-4.16.1-bin"/>
<taskdef resource="flexTasks.tasks" classpath="/opt/apache-flex-sdk-4.16.1-bin/ant/lib/flexTasks.jar"/>
<target name="build">
<mxmlc file="/root/hello/HelloWorld.mxml" output="/root/hello/ant-hello.swf" target-player="32.0">
<load-config filename="/opt/apache-flex-sdk-4.16.1-bin/frameworks/flex-config.xml"/>
<source-path path-element="/root/hello"/>
</mxmlc>
<html-wrapper title="Apache Flex HelloWorld"
width="400" height="200" bgcolor="0xffffff"
application="ant-hello"
swf="/root/hello/ant-hello.swf"
version-major="11" version-minor="1" version-revision="0"
history="true"
output="/root/hello/wrapper"/>
</target>
</project>
预建输出目录并构建(html-wrapper 不会自建目录,见 4.2 节坑二):
mkdir -p /root/hello/wrapper && ant -f /root/hello/build.xml 2>&1 | tail -4
Buildfile: /root/hello/build.xml
build:
[mxmlc] Loading configuration file /opt/apache-flex-sdk-4.16.1-bin/frameworks/flex-config.xml
构建成功的收尾(实测回显):
BUILD SUCCESSFUL
Total time: 3 seconds
核对产物:
ls -l /root/hello/ant-hello.swf && ls /root/hello/wrapper/
-rw-r--r-- 1 root root 511460 Oct 15 08:08 /root/hello/ant-hello.swf
history
index.html
swfobject.js
wrapper/ 里的 index.html 引用同目录 ant-hello.swf 与 swfobject.js,用 SWFObject 做 player 版本探测与嵌入;history/ 是浏览器历史管理辅助文件。
4.2 flexTasks 的两个实测坑
坑一:FLEX_HOME must be set to use the Flex Ant Tasks。 不在 project 里声明 FLEX_HOME 属性直接用 <mxmlc> 时报(实测回显):
BUILD FAILED
/root/hello/build.xml:5: FLEX_HOME must be set to use the Flex Ant Tasks
修复:在 <taskdef> 之前加 <property name="FLEX_HOME" value="/opt/apache-flex-sdk-4.16.1-bin"/>(4.1 节 build.xml 已含)。
坑二:html-wrapper 的 template 属性不存在,输出目录需自建。 给 <html-wrapper> 加 template 属性会报 The <html-wrapper> task doesn't support the "template" attribute.(该任务固定使用 SDK 内 templates/swfobject/ 模板,不需要也不允许指定);且输出目录不存在时报 output directory does not exist: /root/hello/wrapper。修复:去掉 template 属性,构建前 mkdir -p 输出目录。
4.3 本地发布验证
wrapper 目录就是一个可直接发布的静态站点。用任意静态 HTTP 服务验证(实测用 Python 内置服务器):
cd /root/hello/wrapper && nohup python3 -m http.server 8000 >/tmp/httpd.log 2>&1 &
curl -sI http://127.0.0.1:8000/index.html | head -3
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.10.12
Date: Thu, 15 Oct 2026 08:16:39 GMT
⚠️ 注意:SWF 必须与 index.html 同目录(或在 index.html 引用的相对路径上)才可访问。实测把 SWF 编译在 wrapper 之外时,访问
http://127.0.0.1:8000/ant-hello.swf返回 404(HTTP/1.0 404 File not found);把ant-hello.swf复制进 wrapper 后同 URL 返回 200。验证结束记得停掉测试服务(kill %1)。
五、与 SWC 组件库复用
SWC 是 Flex 的库分发格式(一个 zip:catalog.xml 描述清单 + library.swf 字节码)。工程上把通用工具类编译成 SWC,供多个应用通过 -library-path 引用,避免源码复制。
5.1 用 compc 打一个工具库
/root/libdemo/src/com/example/StringUtils.as 全文:
package com.example {
public class StringUtils {
public static function isBlank(s:String):Boolean {
return s == null || trim(s).length == 0;
}
public static function trim(s:String):String {
return s == null ? null : s.replace(/^\s+|\s+$/g, "");
}
public static function repeat(s:String, n:int):String {
return new Array(n + 1).join(s);
}
}
}
编译成 SWC:
cd /root/libdemo
mxmlc -version
compc -source-path src -include-classes com.example.StringUtils -output libs/strutils.swc 2>&1 | tail -1
ls -l libs/
Version 4.16.1 build 20171115
/root/libdemo/libs/strutils.swc (2141 bytes)
total 4
-rw-r--r-- 1 root root 2141 Oct 15 08:23 strutils.swc
看一眼 SWC 内部结构(就是标准 zip):
unzip -l libs/strutils.swc | tail -5
--------- ---------- ----- ----
1224 2026-10-15 08:23 catalog.xml
1347 2026-10-15 08:23 library.swf
--------- -------
2571 2 files
5.2 应用引用 SWC 并验证类被嵌入
/root/libdemo/SwcUse.mxml 全文:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" width="300" height="120">
<fx:Script>
<![CDATA[
import com.example.StringUtils;
[Bindable]
private var out:String;
private function run():void {
out = "isBlank(空串)=" + StringUtils.isBlank("") +
" repeat(ab,3)=" + StringUtils.repeat("ab", 3);
}
]]>
</fx:Script>
<s:Button label="Run" click="run()" x="10" y="10"/>
<s:Label text="{out}" x="10" y="60"/>
</s:Application>
编译时用 -library-path+=libs 把库目录追加进编译期类路径:
cd /root/libdemo && mxmlc -library-path+=libs SwcUse.mxml 2>&1 | tail -1
/root/libdemo/SwcUse.swf (283919 bytes)
用 swfdump -abc 验证 com.example.StringUtils 确实被静态嵌入(编译成功但类没进包是 SWC 引用最常见的假成功):
/opt/apache-flex-sdk-4.16.1-bin/bin/swfdump -abc SwcUse.swf 2>/dev/null | grep -c "com.example"
17
验证点:计数 17(类名、包名与脚本条目多次出现),说明库类随应用一起打进了 SWF;若为 0,检查 -library-path 是否写对目录与 SWC 内包名。注意 -library-path+=libs 中的加号表示「追加」而非覆盖默认库路径,漏写加号会把 framework 系列库全部替换掉导致大片报错。
六、选型建议
Apache Flex 生态内几套发行物各管一段,按需求对号入座:
| 组件 | 定位 | 本文是否使用 | 适用判断 |
|---|---|---|---|
| Apache Flex SDK 4.16.1 | MXML/AS3 编译器 + Spark/MX 框架库 | 是(全部示例基于它) | 编译存量 Flash 应用 |
| Apache FlexJS / Royale | 把 MXML/AS3 编译为 JS 的后继项目 | 否 | 新项目想保留 Flex 开发模式但目标 HTML5 |
| FlexUnit | Flex 的单元测试框架 | 否 | 给 ActionScript 代码写测试 |
| BlazeDS | Java 后端消息/远程调用网关 | 否 | 需要 AMF 远程通道的存量系统 |
| SWFObject(包装模板) | 浏览器嵌入 SWF 的 JS 工具 | 是(第四章 wrapper) | 生成可直接发布的播放页 |
按场景落到具体建议:
- 维护存量 Flash/Flex 工程 → Apache Flex SDK 4.16.1(本文方式,10 分钟出第一个 SWF)。
- 新项目但团队只会 MXML/AS3 → 评估 Apache Royale,语法迁移成本低,产物是 JS。
- Flash 游戏资产迁移 → Haxe + OpenFL 路线(生态成熟,支持 SWF 资产导入)。
- 只需要在页面播放已有 SWF → 不装 SDK,直接用 SWFObject 包装页(第四章 4.3 节的发布方式)。
七、参考链接
- Apache Flex 官方主页:https://flex.apache.org/
- Flex 4.16.1 发行说明:https://downloads.apache.org/flex/4.16.1/RELEASE_NOTES
- flexTasks(Ant 任务)源码与说明(SDK 内
ant/src/flex/ant/与官方 Wiki):https://cwiki.apache.org/confluence/display/FLEX/Ant+tasks - SWFObject:https://github.com/swfobject/swfobject
- Apache Royale(后继项目):https://royale.apache.org/
- SWF 文件格式规范(swfdump 输出各标签含义):https://www.adobe.com/devnet/swf.html