В то время как Adobe выпустили бесплатный SDK для разработки Flex-приложений, просто неприлично не уметь собирать приложения с его помощью. А если вы работаете на заказ, то бессвязный набор ваших исходных кодов вряд ли вдохновит заказчика: что ему с ними делать? Как собрать из них приложение в случае необходимости? Тем более, что часто заказчик неспециалист: ему что, покупать себе Flex Builder, осваивать его? Если в разработке Flash-приложений мы отдавали fla с классами и на пальцах объясняли что куда (а заказчик вынужден был смириться с тем, что ему понадобится среда разработки Flash - отнюдь не бесплатная), то с бесплатным SDK мы просто обязаны дать заказчику код, который он в любой момент может использовать для сборки приложения.
В качестве лирического отступления замечу, что раньше для того чтобы удовлетворить потребности заказчика во внезапной кастомизации вашего детища, вы вынуждены были создавать конфигурационные xml-и, совершать действия по их загрузке и парсингу: все только для того чтобы снизить вероятность необходимости перекомпилировать приложение. Если предоставить заказчику возможность легко собирать приложения, мы можем дать ему на откуп кастомизацию средствами css, xml-файлов, включаемых в mx:Model, а также resource bundles (то есть упрощенная локализация и тексты менюшек-заголовков-кнопочек, которые могут по вашему незнанию языка содержать ошибки), которые компилируются в приложение. Представьте, как можно упростить жизнь разработчику! При этом вовсе не умаляя преимуществ заказчика, а, возможно, лишь увеличивая их!
Ну и, опять же, все преимущества, которые дает автоматическая сборка: возможность автоматических билдов, легкость в поддержке сложных проектов, возможность запускать с билдом тесты (об этом - в следующих сериях).
В общем, перейдем к демонстрации.
Повторю цель моих изысканий: дать возможность любому, у кого на компьютере распакован Flex SDK, собрать ваше приложение, указав при этом лишь путь к папке с SDK. Причем любому - это любому вне зависимости от платформы (Windows, MacOS, Unix...). При этом я, лично, не хотел бы включать в проект файлы самого sdk без необходимости: зачем? Они ведь и так есть!
Пока вы изучаете ссылки, вкратце скажу, что компилятор может принимать параметры как из коммандной строки, так и из специального файла flex-config.xml (который может называться и по-другому). А может и оттуда, и оттуда. Вообще, это довольно сложный и неочевидный путь подобрать все опции чтобы ничего не конфликтовало и все компилилось. Потому я и выкладываю тут проверенный результат. Flex SDK содержит темплэйт такого файла, используемый по умолчанию (в том числе, как я понимаю, и самим Flex Builder'ом). Он находится flex_sdk_2_root\frameworks\flex-config.xml. Понятно, что менять параметры в нем некошерно: во-первых, это отразится и на остальных ваших проектах, а, во-вторых, у другого человека, компилирующего ваш проект, настройки могут оказаться другими.
А содержится там многое: пути к библиотекам, опции компилятора, информация о шрифтах, метаданные генерируемого swf-файла (для тех, кто не в танке: mxmlc занимается только генерацией swf. html и прочее он не генерирует). То есть все, что можно задать компилятору в командной строке. Но представьте себе такую командную строку и структурированный читаемый xml-файл. По-моему, с xml работать приятнее.
Для простоты манипуляции я решил задавать пути к классам из командной строки (чтобы в любой момент легко их было поменять в ant'овском скрипте используя его переменные итд. Хотя и в flex-config.xml
имеются для этого токены.). Но мое решение не абсолютное - вы сами можете выработать свое. Остальные опции, не требующие путей, будут задаваться во flex-config.xml. В частности, для задания пути к стандартным библиотекам мы будем использовать токен flexlib, который сами же и зададим.
Далее приведу мой билд-файл чтобы можно было его изучить (весь тестовый проект можно будет скачать - ссылка внизу :):
<?xml version="1.0"?>
<!-- ======================================================================
Jul 15, 2006 7:02:58 PM
Test App
A simple test app
Constantiner (constantiner (at) gmail.com)
====================================================================== -->
<project
name="Test App"
default="build"
basedir=".">
<property file="local.properties"/>
<!-- dirs -->
<property name="flex.sdk.dir" location="."/>
<property name="build.dir" location="build/"/>
<property name="src.dir" location="src/"/>
<property name="lib.src" location="lib/src/"/>
<property name="lib.swc" location="lib/swc/"/>
<property name="flex.config.xml" location="flex-config.xml"/>
<!-- files -->
<property name="mxmlc.jar" location="${flex.sdk.dir}/lib/mxmlc.jar"/>
<property name="main.application" location="${src.dir}/Main.mxml"/>
<property name="output.swf.name" value="test_app"/>
<property name="main.application.out" location="${build.dir}/${output.swf.name}.swf"/>
<!-- wrapper -->
<property
name="wrapper.dir"
location="${flex.sdk.dir}/resources/html-templates/express-installation-with-history"/>
<property name="output.html.name" value="${output.swf.name}.html"/>
<property name="output.html" location="${build.dir}/${output.html.name}"/>
<property name="unnamed.output.html" location="${build.dir}/index.template.html"/>
<property name="swf.width" value="640"/>
<property name="swf.height" value="480"/>
<property name="swf.title" value="Пример очень простого приложения"/>
<property name="swf.version.major" value="9"/>
<property name="swf.version.minor" value="0"/>
<property name="swf.version.revision" value="0"/>
<property name="swf.application" value="${output.swf.name}"/>
<property name="swf.swf" value="${output.swf.name}"/>
<property name="swf.bgcolor" value="#FFFFFF"/>
<description>
A simple test app
</description>
<!-- =================================
target: build
================================= -->
<target
name="build"
depends="clear,init,compile,copy.wrapper,prepare.wrapper"
description="-->Simple test application">
</target>
<!-- - - - - - - - - - - - - - - - - -
target: copy.wrapper
- - - - - - - - - - - - - - - - - -->
<target name="copy.wrapper">
<copy todir="${build.dir}">
<fileset dir="${wrapper.dir}" />
</copy>
</target>
<!-- - - - - - - - - - - - - - - - - -
target: prepare.wrapper
- - - - - - - - - - - - - - - - - -->
<target name="prepare.wrapper">
<move
file="${unnamed.output.html}"
tofile="${output.html}" />
<replaceregexp
file="${output.html}"
flags="gs"
match="\$\{width\}"
replace="${swf.width}"/>
<replaceregexp
file="${output.html}"
flags="gs"
match="\$\{height\}"
replace="${swf.height}"/>
<replaceregexp
file="${output.html}"
flags="gs"
match="\$\{title\}"
replace="${swf.title}"
encoding="utf-8"/>
<replaceregexp
file="${output.html}"
flags="gs"
match="\$\{version_major\}"
replace="${swf.version.major}"/>
<replaceregexp
file="${output.html}"
flags="gs"
match="\$\{version_minor\}"
replace="${swf.version.minor}"/>
<replaceregexp
file="${output.html}"
flags="gs"
match="\$\{version_revision\}"
replace="${swf.version.revision}"/>
<replaceregexp
file="${output.html}"
flags="gs"
match="\$\{application\}"
replace="${swf.application}"/>
<replaceregexp
file="${output.html}"
flags="gs"
match="\$\{bgcolor\}"
replace="${swf.bgcolor}"/>
<replaceregexp
file="${output.html}"
flags="gs"
match="\$\{swf\}"
replace="${swf.swf}"/>
</target>
<!-- - - - - - - - - - - - - - - - - -
target: compile
- - - - - - - - - - - - - - - - - -->
<target name="compile">
<java
jar="${mxmlc.jar}"
fork="true"
maxmemory="512m"
failonerror="true">
<arg value="+flexlib=${flex.sdk.dir}/frameworks"/>
<arg value="-load-config=${flex.config.xml}"/>
<arg value="-output=${main.application.out}"/>
<arg value="-source-path"/>
<arg value="${src.dir}"/>
<arg value="${lib.src}"/>
<arg value="-library-path+=${lib.swc}"/>
<arg value="${main.application}" />
</java>
</target>
<!-- - - - - - - - - - - - - - - - - -
target: clear
- - - - - - - - - - - - - - - - - -->
<target name="clear">
<delete failonerror="false">
<fileset dir="${build.dir}" includes="**/*.*" />
</delete>
</target>
<!-- - - - - - - - - - - - - - - - - -
target: init
- - - - - - - - - - - - - - - - - -->
<target name="init">
<mkdir
dir="${build.dir}"/>
</target>
</project>
По традиции в файле local.properties мы указываем путь к папке, содержащей Flex SDK (той, что содержит в себе bin, framework, lib итд.). Это единственная переменная величина в проекте, задаваемая ручками при компиляции на другой машине (свойство
flex.sdk.dir).
Структура проекта проста: она содержит папку src, содержащую Main.mxml (само приложение) и другие написанные нами as- и mxml-классы. То есть это те артефакты, которые созданы в рамках данного проекта. Есть также папочка lib, которая содержит внешние библиотеки (реюзабельную составляющую). Она делится на две подпапки: src и swc. В первой содержатся библиотеки, поставляемые в виде исходного кода, а во второй, соответственно, в виде swc (в данном проект е таковых нет, но я эту возможность занес).
Ну и по целям нашего билд-файла:
- clear очищает каталог с прежним билдом.
- init создает каталог с билдом.
- compile компилирует наш проект.
- copy.wrapper копирует наш html-wrapper.
- prepare.wrapper приводит его в вид, пригодный для использования.
И действительно, мы можем заметить, что в свойстве wrapper.dir ant-файла мы указываем каталог с нужным нам темплейтом (из шести имеющихся). Также в отдельном блоке свойств мы задаем все возможные параметры нашего html-фйла, в него подставляемые. Можно создать и свой вариант по образу и подобию предзаготовленных.
Вот такая вот приятная вещь. И, главное, что с этим можно баловаться: менять wrapper (очень просто!), менять тему (тоже просто: compile.theme в flex-config.xml). Куча приятных вкусностей.
Ну вот, такая сумбурная заметка, которая будет полезна профессионалам. В принципе, можно задавать вопросы :)