четверг, 25 сентября 2008 г.

SWF compilation date

Бывают случаи, когда разработчикам нужно решить достаточно простую, я бы сказал даже, банальную задачу: вставить в код программы номер версии или дату компиляции приложения. Эта информация чрезвычайно полезна при последующем сопровождении: ведь всегда нужно знать, с какой версией имеешь дело.

Столкнувшись с этой задачей, я с удивлением обнаружил, что готовых средств для её решения во Flex3/Flex4 нет. Это крайне странно. Не могли же профессиональные разработчики забыть о такой необходимой вещи! И действительно, расследование показало, что внутри SWF-файлов всегда присутствуют определенные части, изменяющиеся при каждой компиляции. Именно этим и объясняется тот факт, что при перекомпиляции проекта результат часто имеет другой размер — файлы SWF сжаты, а результат работы упаковщика зависит от входных данных, которые, как я уже говорил, меняются всегда. Более пристальный взгляд показал, что в файле изменяется часть структуры, которая именуется декомпиляторами не иначе как SERIALNUMBER. Эта структура не документирована, но исследование показало, что в конце её лежит целое число 8-ми байт длиной. Число это - количество миллисекунд с начала 1970-года. Т.е. это ровно то, что возвращает свойство time у объекта Date. Осталась самая малость - прочесть из SWF своё код, найди в нем эту структуру и прочитать её последние 8 байт. Вопрос доступа к собственному коду — это, безусловно, интересная головоломка, но решилась достаточно быстро:
    LoaderInfo.getLoaderInfoByDefinition(this).bytes;
Структура SWF-файла документирована, так что далее было легко.

Готовый код выложен на http://code.google.com/p/flex-ad-by/
Достаточно просто вызвать метод SWF.readCompilationDate().
Лицензия — BSD, что, по моему, свободнее некуда. Проверено во Flex3/Flex4. Пользуйтесь на здоровье.

7 коммент.:

hissorrow комментирует...

А как вытащить из SWF метаданные XMP, которые включает Flash CS4 при компиляции?

Павел комментирует...

Увы, не могу ничем помочь. С XMP не сталкивался.

hissorrow комментирует...

Жаль :(
Но спасибо за быстрый ответ.

Адоби везде, где только можно пишут, как встраивать XMP данные в файлы, а как их потом считывать - молчат. А вот, например, Adobe Bridge показывает метаданные XMP у SWF-файла.

И, кстати, по теме: почему по данной ссылке http://code.google.com/p/flex-ad-by/ нет ничего? :) Попробовал пример отсюда http://www.igorcosta.org/?p=220
SWF.readCompilationDate() возвращает null

Павел комментирует...

Опа, глюк. Восстановил исходники. Попробуй ещё раз, Коста, насколько я помню, брал не последнюю версию.

А вообще, должен сказать, что сейчас эта библиотека заброшена, т.к. флешем/флексом я больше почти не занимаюсь.

И выявились следующие ограничения:
1) Чтение метаданных доступно не всегда. Я делал это для отладки локальной флешки - все работает, а вот для подгружаемой с другого домена - нет. О полиси звависит что-ли.
2) Генерация нормальных GUID'ов во флешке всё-таки очень затруднена. Т.к. судя по исходникам тамарина random() основан на new Date().getTime(). Соответственно рандом использовать бессмысленно, нужно брать время, разрешение экрана, версию плеера и т.д.

hissorrow комментирует...

У меня даже у локальной флэшки не хочет читать.
На счет генерации GUID-ов понял, а вот как бы этот самый идентификатор хранить в SWF-ке?.. Можно как-то дописывать свои данные в header?

Павел комментирует...

О, Вспомнил! Флеш не пишет метаданные о своей версии в файл. Только флекс!

В заголовок кое что можно засунуть. В неиспользуемые поля. Например можно на место высоты и ширины положить свои значения.

hissorrow комментирует...

Да, можно некоторые поля заменять своими значениями. Но, наверно, покопаю еще немного в сторону XMP.

Вообще, передо мной лежит задача проверки соответствия версии SWF и FLA-исходника. Вот и думаю, как бы это узнать по SWF-ке. В идеале бы просто читать какие-нибудь метаданные, которые меняются при каждой компиляции флэшки. Только вроде нашел ваш замечательный SERIALNUMBER, а его нет в Flash IDE =)

Большое спасибо за помощь)