Разный код для разных версий Flash Player
Я пишу универсальный графический движок, который будет работать на FP11, используя преимущество крота, а также работает на FP10, используя старое программное обеспечение.
Итак, я задаюсь вопросом, как лучше всего достичь этого?
Сначала я подумал, что если я скомпилирую SWF для FP11 и не буду использовать новые классы, если версия проигрывателя не 11, все будет работать нормально. Но я был неправ. К моему удивлению, я получаю сообщение об ошибке "VerifyError: Ошибка № 1014. Не удается найти класс flash.display3D::Context3D", если я запускаю код с импортированными библиотеками FP11, даже если они не вызываются.
Я думал, что FP выдаст это сообщение только тогда, когда я попытаюсь получить доступ к отсутствующему классу, но это неправильно. Выдает ошибку только когда я пытаюсь запустить.swf
Так есть ли способ сделать это? Я думал о загрузке разных SWF-файлов в зависимости от версии с использованием preloader, но поддержка и компиляция двух разных SWF-файлов довольно запутанная.
Есть ли другие способы?
3 ответа
Если вы используете Flash (в отличие от Flex или какого-либо другого инструмента), я полагаю, что единственным вариантом может быть условная компиляция. Когда мне пришлось иметь дело с этим в CS5, я не мог найти ничего другого.
В итоге я определил несколько констант для различных конфигураций, а затем скомпилировал несколько версий.swf. Я загрузил правильный файл.swf на основе кода обнаружения игрока в браузере. Это действительно беспорядок, если вы хотите, чтобы ваш.swf находился в таких местах, как Newgrounds и т. Д.
редактировать
Извините, я не заметил, что вы не хотите поддерживать разные версии библиотеки. В этом случае нет никакого способа - когда FP обрабатывает байт-код SWF и когда он находит неизвестную ссылку, он выдает VerifyError. Конечно, вы можете использовать getDefinitionByName()
и динамический доступ, но он очень медленный.
Чтобы минимизировать количество отдельно поддерживаемого кода, вы можете использовать SWC с основными функциями и SWF с функциями, зависящими от версии, поэтому на этапе инициализации основной класс вашей библиотеки будет проверять версию FP и загружать соответствующий SWF.
Это называется динамическое связывание, и есть способ:
Создать интерфейс всех функций, зависящих от версии проигрывателя (
public interface MyInterface...
). Этот интерфейс не должен содержать ссылок на зависимые от версии API. Скомпилируйте этот интерфейс (это может быть только один файл.as) в SWC (пусть это будетlib-intf.swc
).Создайте две независимые реализации этого интерфейса; первый будет использовать новые API, второй - нет (он может быть просто заполнителем, но также может быть альтернативной реализацией). Позже нам нужно скомпилировать эти реализации в SWF, поэтому нам нужны основные классы, которые расширяют
Sprite
, Самый простой способ сделать это - заставить эти основные классы реализовать наш интерфейс (т.е.public class MyImplementationA extends Sprite implements MyInterface...
и то же самое дляMyImplementationB
). Они будут просто пустымиSprites
, но они будут содержать методы интерфейса.Скомпилируйте эти две реализации независимо в отдельные SWF(
lib-a.swf
а такжеlib-b.swf
). При компиляции включайтеlib-intf.swc
как внешняя библиотека (-external-library-path
параметр компилятора или "внешний" тип ссылки в IDE).Теперь, при компиляции вашего корневого приложения, включите
lib-intf.swc
как обычно библиотека (-library-path
параметр компилятора или тип ссылки "объединены в код" в IDE). Не включайте зависящие от версии классы вообще. Таким образом, в корневом приложении у вас будут только ссылки на интерфейс, который не зависит от версии. Когда ваше приложение запускается, проверьте версию FP и, в зависимости от этого, загрузите соответствующий SWF с помощью класса Loader. Вам придется загрузить его в основной домен приложения, а не в его дочерний элемент (это вариант по умолчанию; более подробная информация).Когда SWF загружен, приведите его к интерфейсу:
var versionDependentImpl:MyInterface = loader.content as MyInterface
, Помните, что основные классы наших SWFs реализуютMyInterface
, так что этот актерский состав будет работать.Вот и все - теперь вы можете использовать вашу реализацию:
versionDependentImpl.someMethod()
, Конечно,someMethod
должны быть определены вMyInterface
,
Итак, хитрость в том, чтобы динамически загружать реализацию из SWF-файла. Хотя корневое приложение ничего не знает о классах внутри этого SWF-файла, мы можем использовать методы его основного класса, потому что мы заставили его реализовать интерфейс, который мы скомпилировали в корневое приложение.
Этот подход является масштабируемым: например, вы можете определить основной интерфейс, у которого есть методы, которые возвращают другие интерфейсы. Вы даже можете включить конкретные классы, которые совместно используются реализациями, в lib-intf.swc
До тех пор, пока они не используют зависимые от версии API.
flash apis не поддерживает совместимость если вы хотите flash 11 api, вам нужно сделать flash 11+ swf. Причина этого в том, что SWF 10 может с радостью создать свой собственный класс Stage3D. если это вдруг конфликтует со встроенным классом в SWF 11, это нарушит обратную совместимость. так что вы можете иметь только одну, обратную или прямую совместимость.