Блог от AS3Coder'a о JavaScript, HTML, CSS... и немного о Flash.

среда, 23 декабря 2009 г.

Компиляция и использование SWC-библиотек во FlashDevelop

Нижепредставленный материал является дополнением к статье Алексея «Vooparker» Аникутина: "Компиляция совместимых с Flash CS3 swc-библиотек с помощью Flex 3 SDK", за которую ему огромное спасибо. Автор настоятельно рекомендует ознакомится с данной статьей.

Что такое SWC-библиотека?

SWC-библиотека - это библиотека классов с закрытым исходным кодом, которая хранится в файлах с расширением .swc. Также .swc-файлы используются для хранения отдельных компонентов, которые используются во Flash IDE.

Файлы с расширением .swc являются .zip-файлами, упакованными с помощью формата PKZIP. Внутри архива находится .swf-файл с классами, и catalogue.xml c описанием классов. Также в архив могут быть включены дополнительный файлы: картинки, .css-файлы и другие. Подробнее о формате .swc-файлов смотрите на Adobe.

SWC-библиотеки в основном используются в коммерческих проектах. Пользоваться ими легко (об этом ниже), а вот компилировать свои немного сложнее. В данной статье я рассмотрю компиляцию .swc-библиотек, на основе FlashDevelop.


Как компилировать .swc-библиотеку во FlashDevelop.

Подготовим среду разработки.

1. Компилировать .swc-файлы мы будем с использованием Flex Ant Tasks. Подробнее об этом смотрите в справке.

Для этого нам необходимо установить java-утилиту Apache Ant, которую можно скачать на официальном сайте: http://ant.apache.org/. Утилита распространяется в архиве, поэтому инсталлировать её нужно самостоятельно. Распакуйте корневую папку архива в любой каталог на локальном диске, желательно в "Program Files". Например, у меня - это "C:\Program Files\Apache\ant\1.7.1".

2. Перейдем к настройке FlashDevelop. В верхнем меню выбираем пункт "Tools", далее "Custom Arguments".


В появившемся окне внесем два пользовательских аргумента "FlexSDKDir" и "AntDir", в значениях которых пропишем пути соответственно. У меня получилось следующее:



Эти два аргумента нужны для нового типа проекта, который мы сейчас добавим.

Для этого скачиваем архив шаблонов проекта. Полученный архив нужно распаковать в директорию "Projects", которая находится в папке с установленным FlashDevelop. Например, у меня - это "C:\Program Files\FlashDevelop\Projects". Теперь после рестарта FlashDevelop,


в проектах у вас появится новый тип проекта "AS3 SWC Builder".




Попробуем что-нибудь скомпилировать.

Создаем новый проект типа "AS3 SWC Builder". В окне "Project" увидим следующее содержимое проекта:

  • bin - директория, в которой будет находится скомпилированный.swc-файл.
  • build - здесь, находятся файлы с настройками компиляции.
  • src - из этой папки будут браться классы, которые мы будем зашивать в нашу .swc-библиотеку.
  • build.bat - файл который запускает сборку (компиляцию) библиотеки.
Перенесем в директорию "src" необходимые нам .as-файлы. Например, мои:


Теперь перейдем к настройкам. Откроем файл compc-config.xml, который находится в папке "build", и в нем в теге , пропишем классы которые хотим включить в библиотеку.

<include-classes>
  <class>ru.as3coder.AS3CoderLibclass>
  <class>ru.as3coder.geom.Lengthclass>
  <class>ru.as3coder.graph.Edgeclass>
  <class>ru.as3coder.graph.Graphclass>
  <class>ru.as3coder.graph.GraphMethodsclass>
  <class>ru.as3coder.graph.Vertexclass>
</include-classes>

Запускаем build.bat (нажатием F5), и в директории "bin" появится .swc-библиотека с классами, которые мы включили в неё.


Единственный вопрос остался у меня, на который я так и не нашел ответ: "Что за посторонний класс появляется при сборке .swc-файла?"


Может быть кто-то из читателей мне подскажет.



Дополнительная информация.

Возможно не всегда удобно использовать директорию "src", для хранения исходных классов. Вы можете изменить директорию с исходными классами в файле build.xml в свойстве output.dir




<property name="source.dir" value="${basedir}/src" />

Также если вы хотите чтобы ваша .swc-библиотека была совместима с Flash CS3, нужно прописать классы еще в одном файле manifest.xml, следующим образом:

<componentPackage>
  <component id="AS3CoderLib" class="ru.as3coder.AS3CoderLib" />
  <component id="Length" class="ru.as3coder.geom.Length" />
  <component id="Graph" class="ru.as3coder.graph.Graph" />
  <component id="Edge" class="ru.as3coder.graph.Edge" />
  <component id="Vertex" class="ru.as3coder.graph.Vertex" />
  <component id="GraphMethods" class="ru.as3coder.graph.GraphMethods" />
</componentPackage>

Более подробно о дополнительных возможностях вы можете узнать в официальной справке Adobe:
Как использовать .swc-библиотеку в AS3-проекте?

Использовать .swc-библиотеку в AS3-проекте достаточно легко. Необходимо перенести .swc-файл в директорию "lib", нажать на файле правой кнопкой и в "Add To Library" поставить галочку.


Теперь вы можете использовать классы библиотеки, также как и классы, которые находятся в директории "src".


Смотрите также:

четверг, 10 декабря 2009 г.

Как узнать дату компиляции внутри AS3-приложения?

Работая над отладкой AS3-приложения, мы обычно заливаем обновленный .swf-файл на сервер, и идем проверять исчезла ли, только что исправленная, ошибка. Обнаруживаем, что не исчезла. Вспоминаем про кеш браузера, чистим его. Проверяем снова. Опять не исчезла. Думаем как же так получилось... Всё таки приходим к мнению, что кеш не сбросился, и повторяем всё снова...

А как бы было неплохо, показывать билд или дату компиляции .swf-файла.

Оказывается такое возможно благодаря трудам Igor Costa и Paul Sivtsov. Можно узнать дату компиляции внутри .swf-файла.

Компилирую .swf-файл при помощи Flex SDK в результирующий файл записывается некоторая информация. Во Flash IDE, такого не происходит. После полной загрузки .swf-файла, внутри родительского класса можно прочитать байты. А дальше, использую класс flash.utils.ByteArray, можно вытащить те самые данные которые записываются Flex SDK. В них можно найти и дату компиляции.

Для корректной работы в браузерах (исходный класс, взятый с сайта Igor Costa, работал только в дебаг-плеере), я немного изменил класс:

package org.igorcosta.hacks
{
  import flash.display.DisplayObject;
  import flash.display.LoaderInfo;
  import flash.utils.ByteArray;
  import flash.utils.Endian;
  /**
  * Direct reading of SWF file
  * Distributed under the new BSD License
  * @author Paul Sivtsov - ad@ad.by
  */
  public class SWF
  {
    /////////////////////////////////////////////
    // Reference to the parent class
    private var root:DisplayObject;
    //
    /////////////////////////////////////////////
    // Constructor
    function SWF (root:DisplayObject)
    {
      this.root = root;
    }
    //
    /////////////////////////////////////////////
    // Returns compilation date of current module
    public function readCompilationDate(serialNumber: ByteArray = null): Date
    {
      const compilationDate: Date = new Date;
      const DATETIME_OFFSET: uint = 18;
      //
      if (serialNumber == null)
        serialNumber = readSerialNumber();
      //
      /* example of filled SWF_SERIALNUMBER structure
      struct SWF_SERIALNUMBER
      {
        UI32 Id;         // "3"
        UI32 Edition;    // "6"
                         // "flex_sdk_4.0.0.3342"
        UI8 Major;       // "4."
        UI8 Minor;       // "0."
        UI32 BuildL;     // "0."
        UI32 BuildH;     // "3342"
        UI32 TimestampL;
        UI32 TimestampH;
      };
      */
      //
      // the SWF_SERIALNUMBER structure exists in FLEX swfs only, not FLASH
      if (serialNumber == null)
        return null;
      //
      // date stored as uint64
      serialNumber.position = DATETIME_OFFSET;
      serialNumber.endian = Endian.LITTLE_ENDIAN;
      compilationDate.time = serialNumber.readUnsignedInt() + serialNumber.readUnsignedInt() * (uint.MAX_VALUE + 1);
      //
      return compilationDate;
    }
    //
    ///////////////////////////////////////////////////////////////////////////
    // Returns contents of Adobe SerialNumber SWF tag
    public function readSerialNumber(): ByteArray
    {
      const TAG_SERIAL_NUMBER: uint = 0x29;
      return findAndReadTagBody(TAG_SERIAL_NUMBER);
    }
    //
    ///////////////////////////////////////////////////////////////////////////
    // Returns the tag body if it is possible
    public function findAndReadTagBody(theTagCode: uint): ByteArray
    {
      // getting direst access to unpacked SWF file
      //const src: ByteArray = LoaderInfo.getLoaderInfoByDefinition(SWF).bytes;
      const src: ByteArray = root.loaderInfo.bytes;
      //
      /*
      SWF File Header
      Field      Type  Offset   Comment
      -----      ----  ------   -------
      Signature  UI8   0        Signature byte: “F” indicates uncompressed, “C” indicates compressed (SWF 6 and later only)
      Signature  UI8   1        Signature byte always “W”
      Signature  UI8   2        Signature byte always “S”
      Version    UI8   3        Single byte file version (for example, 0x06 for SWF 6)
      FileLength UI32  4        Length of entire file in bytes
      FrameSize  RECT  8        Frame size in twips
      FrameRate  UI16  8+RECT   Frame delay in 8.8 fixed number of frames per second
      FrameCount UI16  10+RECT  Total number of frames in file
      */
      //
      // skip AVM2 SWF header
      // skip Signature, Version & FileLength
      src.position = 8;
      // skip FrameSize
      const RECT_UB_LENGTH:uint = 5;
      const RECT_SB_LENGTH:uint = src.readUnsignedByte() >> (8 - RECT_UB_LENGTH);
      const RECT_LENGTH: uint = Math.ceil((RECT_UB_LENGTH + RECT_SB_LENGTH * 4) / 8);
      src.position += (RECT_LENGTH - 1);
      // skip FrameRate & FrameCount
      src.position += 4;
      //
      while (src.bytesAvailable > 0)
        with (readTag(src, theTagCode))
      {
        if (tagCode == theTagCode)
          return tagBody;
      }
      //
      return null;
    }
    //
    ///////////////////////////////////////////////////////////////////////////
    // Returns tag from current read position
    private function readTag(src: ByteArray, theTagCode: uint): Object
    {
      src.endian = Endian.LITTLE_ENDIAN;
      //
      const tagCodeAndLength: uint = src.readUnsignedShort();
      const tagCode: uint = tagCodeAndLength >> 6;
      const tagLength: uint = function(): uint {
        const MAX_SHORT_TAG_LENGTH: uint = 0x3F;
        const shortLength:uint = tagCodeAndLength & MAX_SHORT_TAG_LENGTH;
        return (shortLength == MAX_SHORT_TAG_LENGTH) ? src.readUnsignedInt() : shortLength;
      }();
      //
      const tagBody: ByteArray = new ByteArray;
      if (tagLength > 0)
        src.readBytes(tagBody, 0, tagLength);
      //
      return {
        tagCode: tagCode,
        tagBody: tagBody
      };
    }
  }
}

SWF.as

Пример использования класса:

var swf:SWF = new SWF (root); // @param root  ссылка на родительский класс приложения.
trace("Complilation Date = " + swf.readCompilationDate().toString());

Пример работы:


    

пятница, 4 декабря 2009 г.

Использование Flex Metadata Tags в AS3-проекте

Продолжая тему создания AS3-приложения во FlashDevelop, хочу рассказать о использовании Flex Metadata Tags.

Об этом я уже заикался, рассказывая вам о работе с библиотекой во FlashDevelop. Так вот, вставка Embed, обрамленная квадратными скобками - это и есть Flex Metadata Tag, который сообщает компилятору (Flex SDK) о том, что нужно вставить указанный объект.

Кроме тега Embed, есть еще много чего интересного. Найти полный список тегов можно в справочнике по Flex или здесь. Большинство из них используется при разработке Flex-проектов, поэтому при разработке AS3-проекта они нам не понадобятся, кроме SWF и Embed. Embed я уже описывал, теперь о SWF.

[SWF]

Этот тег отвечает за публикацию результирующего .swf-файла. Теперь не нужно лазить в настройки публикации проекта, можно всё настроить прямо в коде.

Атрибуты тега SWF (опишу только те, которыми реально можно пользоваться):
  • width - Ширина
  • height - Высота
  • scriptRecursionLimit - Ограничения времени рекурсий сценария
  • scriptTimeLimit - Ограничения времени сценария
  • frameRate - Частота кадров
  • backgroundColor - Цвет фона

[SWF(width = "640", height = "480", backgroundColor = "#FFFFFF", frameRate = "100")]
Прописывать тег SWF, необходимо непосредственно перед определением класса, там где прописывается импорт других классов.

Поиск по блогу

Обо мне



Farid Shamsutdinov (AS3Coder)
Russia, Tatarstan, Kazan
as3coder@gmail.com

Подробнее...

Постоянные читатели

© 2014 Farid Shamsutdinov. При копировании материалов, ссылка на источник обязательна. Технологии Blogger.