Pull to refresh

Разработка мобильных приложений на Adobe Flash + AIR: обзор возможностей

Reading time 14 min
Views 26K
Original author: Oliver Goldman
Недавно замечательная flash-игра Machinarium заняла 1 место в рейтинге платных игр для iPad. Тем не менее много талантливых разработчиков flash-игр с опаской смотрят в сторону мобильных платформ. На русском языке информации по теме крайне мало. Надеюсь эта статья немного улучшит положение вещей. Желаю приятного прочтения.



Изначально Adobe AIR задумывалась как платформа для настольных приложений. Однако сейчас она поддерживает разработку stand-alone приложений для мобильных устройств, настольных компьютеров, домашних цифровых устройств. Такой широкий охват делает ее привлекательной платформой для разработки. В то же время каждая среда имеет свою уникальную специфику, которую надо учитывать.

Например мобильные приложения чаще всего запускаются на небольшие промежутки времени. Пользовательский интерфейс таких приложений должен быть удобен для использования на маленьких экранах, масштабироваться для корректного отображения на планшетах и поддерживать различную ориентацию устройств. Он должен работать на тачскринах и использовать программные и аппаратные возможности, уникальные для конкретного класса устройств. Кроме того надо учитывать требования к памяти и графике.

Эта статья описывает возможности, предоставляемые AIR разработчикам приложений для смартфонов и планшетов под управлением iOS, Android и Blackbery Tablet OS.

Экраны


Пожалуй первым и наиболее очевидным предметом рассмотрения является экран мобильного устройства. Он относительно небольшой как в плане физических размеров, так и в плане количества отображаемых пикселей и характеризуется большой плотностью (в пикселях на дюйм). Различные устройства имеют различные комбинации плотности пикселей и физических размеров. Кроме того само устройство можно удерживать как в портретной так и в пейзажной ориентации.

Чтобы работать со всем этим многообразием размеров и плотностей, AIR предоставляет следующие ключевые API:
  • Stage.stageWidth, Stage.stageHeight: Эти два свойства хранят фактические размеры экрана. Причем их значение может изменяться в процессе выполнения, например когда приложение входит/выходит из полноэкранного режима или когда меняется ориентация устройства (про ориентацию чуть ниже)
  • Capabilities.screenDPI: Это свойство хранит количество пиксей на дюйм

Используя эти значения, приложение может адаптироваться под экраны с различными характеристиками.

Примечание: если вы ранее разрабатывали десктопные приложения на AIR, обратите внимание на то, что при разработке для мобильных платформ используется Stage, а NativeWindow не используется. Т.е. вы конечно можете проинстанцировать ссылку на него, но это не даст никакого эффекта. Эта возможность оставлена, чтобы можно было писать код, работающий одновременно и на мобильных устройствах и на десктопах. Чтобы узнать, доступен ли NativeWindow используйте NativeWindow.isSuppoted.

Мобильные приложения не обязаны поддерживать вращение экрана, но вы должны помнить, что не у всех мобильных устройств портретная ориентация (высота больше ширины) используется по-умолчанию. Приложения, которые не заинтересованы в возможности автоматического вращения экрана, могут отказаться от нее установив в значение flase в дескрипторе приложения. И напротив, вы можете установить в true и слушать события StageOrientationEvents у Stage.

Сенсорный ввод


С момента, когда приложение отрисовалось на экране, оно как правило уже готово принимать пользовательский ввод. Для мобильного приложения это означает ввод посредством тачскрина.

AIR автоматически сопоставляет событиям мышки простые однопальцевые жесты, такие как нажатие одним пальцем на кнопку (tap). Это позволяет писать код, который без дополнительных изменений работает одинаково как на мобильных устройствах, так и на настольных компьютерах.

Для более сложного мультитач-взаимодействия AIR включает следующие API:
  • Multitouch: предоставляет информацию о том, какие виды тач-взаимодействия доступны
  • TouchEvent: События, получаемые приложением в процессе обработки прикосновений
  • GestureEvent, PressAndTapGestureEvent, TransformGestureEvent: Приложение получает эти события при обработке жестов (gestures)

Для приложений, которые работают со стандартными жестами системы (например щипок и разведение пальцев для масштабирования) установите Multitouch.inputMode в MultitouchInputMode.GESTURE. Единичные касания будут преобразованы в соответствующие жесты системой автоматически. Например для жеста уменьшения/увеличения будут возникать события TransformGestureEvent с типом TransformGestureEvent.GESTURE_ZOOM.

Если же приложения желает получать “сырую” информацию о прикосновениях, выставите Multitouch.inputMode в MultitouchInputMode.TOUCH_POINT. Система будет генерировать серии событий начала касания, перемещения и окончания касания, причем касание экрана может происходить в нескольких точках одновременно. Задача интерпретации таких множественных касаний ложится на приложение.

Ввод текста


Мобильные устройства с программной клавиатурой (т.е. отображаемой на экране, без физических клавиш) требуют особого внимания. Хотя такая клавиатура присутствует не везде, но использующие ее устройства начинают преобладать, и вы должны убедиться, что все работает хорошо.

При отображении, программная клавиатура закрывает собой часть экрана. Чтобы учесть это, AIR сдвигает Stage таким образом, чтобы оставались одновременно видны и поле ввода и клавиатура, скрывая верхнюю часть приложения за пределами экрана. Такое поведение можно отключить и реализовать свое собственное. Для этого нужно установить параметр softKeyboardBehavior в дескрипторе приложения в значение none (значение по-умолчанию — pan).

Поле Stage.softKeyboardRect хранит размеры области, занимаемой программной клавиатурой. Слушайте событие SoftKeyboardEvent, чтобы знать, когда это значение изменяется.

Приложению, как правило, не надо заботится об открытии программной клавиатуры, это происходит само по себе, когда текстовое поле получает фокус. Однако, можно запросить автоматическое открытие клавиатуры для любого InteractiveObject, когда тот получает фокус (свойство InteractiveObject.needsSoftKeyboard) или открыть ее самостоятельно, вызвав InteractiveObject.requestSoftKeyboard(). Данные API не окажут никакого эффекта на устройствах, не поддерживающих программную клавиатуру.

Датчики


Взаимодействие пользователя с мобильным устройством не ограничивается одним мультитач-экраном. Приложения могут использовать информацию о местонахождении пользователя, а также реагировать на ориентацию и перемещения устройства в пространстве. AIR поддерживает оисанные возможности через следующие ключевые API:
  • Geolocation: Обрабатывает события, связанные с географическим положением устройства (широта и долгота), а также его передвижением (направление и скорость)
  • Accelerometer: Обрабатывает события, сообщающие о силах приложенных к устройству по осям x, y и z

Для некоторых приложений возможность геолокации — неотъемлемая часть (пример — приложение, определяющее местоположение ближайшего банкомата). В других приложениях геолокация может использоваться для удобства (пример — голосовая заметка, снабженная информацией о том, где она записана).

Как отмечалось ранее, акселерометр может быть полезен, когда вы хотите узнать фактическое положение устройства в пространстве, а не просто логическую ориентацию. Акселерометр позволяет превратить ваше устройство само по себе в средство ввода наподобие джойстика. Многие приложения используют эту возможность.

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

Отображение web-контента


Современная среда выполнения должна содержать средства поддержки HTML-контента. В AIR для этого присутствует StageWebView API. StageWebView предоставляет AIR-приложениям доступ ко встроенным возможностям устройства по отображению HTML. Стоит отметить, что так как StageWebView использует HTML-движок самой платформы, то одинаковое отображение на разных платформах не может быть гарантировано.

Еще одним следствием использования нативных средств является то, что содержимое StageWebView не интегрировано со списком отображения приложения. Однако это содержимое может быть сохранено как растровое изображение методом drawViewPortToBitmapData(), а затем помещено в список отображения. Это можно использовать, например, для создания скриншота страницы или создания эффектов плавного перехода.

Для тех, кто знаком с HTMLLoader API в AIR, стоит отметить, что StageWebView не является его заменой. HTMLLoader содержит встроенную поддержку HTML и допускает размещение HTML и JavaScript, выполняемых вне песочницы браузера. StageWebView работает с HTML и JavaSctipt контентом в рамках традиционной песочницы браузера.

Если вы захотите отправить пользователя из своего приложения в браузер или приложения вроде YouTube или Google Maps, используйте navigateToURL().

Изображения


Когда разговор заходит о получении фотоснимков, не стоит вопрос “умеет ли устройство фотографировать”, а стоит другой: “сколько камер в этом устройстве?”. AIR для мобильных устройств включает API позволяющие работать как непосредственно с камерой, так и с уже полученными фотографиями.

Классы CameraUI и CameraRoll

Функционал встроенной камеры доступен через класс CameraUI. Как можно догадаться из названия, класс отличается от похожего класса Camera тем, что работает с пользовательским интерфейсом камеры а не непосредственно с ней. В зависимости от устройства это может выражаться в возможности пользователя выбирать между фото- и видеосъемкой, указывать разрешение снимков, включать/выключать вспышку, переключаться между фронтальной и тыльной камерами и т.п.

Однако мобильные устройства не только делают снимки, но и хранят их. Библиотека сделанных пользователем фотографий доступна через класс CameraRoll. Метод browseForImage() может быть использован для открытия стандартного диалога выбора изображения из библиотеки. Кроме того в эту область можно писать свои данные при помощи метода addBitmapData().

Класс MediaPromise

CameraUI и CameraRoll возвращают медиаконтент с помощью события MediaEvent. В нем нет ничего необычного, за исключением поля data, которое имеет тип MediaPromise, через которое доступна соответствующая информация.

Как следует из названия, MediaPromise обещает предоставить содержимое, однако совсем не обязательно хранит его в себе. Это важный нюанс, поэтому стоит уделить несколько минут на его понимание.

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

Класс MediaPromise является оберткой, призванной упростить работу с этой неопределенностью, предоставляя доступ к медиаобъекту посредством единого интерфейса. Если приложение хочет работать с объектом прямо с запоминающего устройства, проверить его наличие там можно через MediaPromise.file (должно быть не null).

Если приложение пожелает обрабатывать медиаобъект в памяти, он всегда может быть прочитан через поток, доступный с помощью MediaPromise.open(). MediaPromise автоматически вернет содержимое медиаобъекта, независимо от того, где он находится — в памяти или на запоминающем устройстве. При использовании open() не забудьте проверить MediaPromise.isAsync, чтобы определить вид потока.

Наконец, если понадобится напрямую поместить медиафайл в список отображения, избегая лишнего копирования в коде, в классе Loader есть метод Loader.loadFilePromise(). Как видно из названия он работает с любыми FilePromise (MediaPromise реализует интерфейс IFilePromise).

Жизненный цикл приложения


На мобильных устройствах у приложений мало возможностей для управления своим жизненным циклом. Они не могут запускаться сами, а лишь при непосредственном участии пользователя (например с домашнего экрана или через URL, привязанный к приложению). В любой момент приложение может быть отправлено в фоновый режим, а затем и вовсе остановлено (обычно это происходит, когда текущему активному приложению не хватает ресурсов).

На некоторых мобильных платформах NativeApplication.exit() неприменима (inoperable, “no-op”). Вместо того, чтобы сохранять свое состояние при выходе, приложениям следует делать это при переходе в фоновый режим и/или через определенные промежутки времени.

Приложение получает события DEACTIVATE и ACTIVATE соответственно при переходе в ждущий режим и возвращении из него. AIR помимо этого дополнительно предпринимает некоторые специфические действия, детали зависят от платформы.


Фоновое поведение в Android

На андройде приложения стремятся выпонять как можно меньше работы в фоне, однако жестких ограничений нет. Когда AIR-приложение переходит в фоновый режим, частота кадров снижается до 4 fps, и, хотя обработка событий продолжается, фаза рендеринга в цикле обработки событий опускается.

Таким образом, AIR-приложение на Android может в фоне выполнять такие задачи как скачивание/загрузка файлов, синхронизация информации. Тем не менее, приложение при переходе в фоновый режим должно самостоятельно предпринимать дополнительные шаги для уменьшения частоты кадров, отключать ненужные таймеры и.т.п.

Фоновое поведение в iOS

В iOS у приложений нет реальной многозадачности. Приложения должны указывать, что они намереваются проявлять определенную активность в фоне (например удерживать voip-звонок или докачивать файл)

AIR не поддерживает такую модель работы, поэтому когда приложение переходит в фоновый режим, оно просто ставится на паузу. Это значит, что частота кадров выставляется в 0 fps, события не обрабатываются, рендеринг не происходит. Состояние приложения тем не менее хранится в памяти и восстанавливается при выходе из фонового режима.

Производительность


Чтобы достичь хорошей производительности вашего приложения, необходимо внимательно подходить ко всем его аспектам.

Время запуска

Уменьшение времени запуска — непростая задача, т.к. запуск как правило затрагивает множество сторон приложения. Прежде всего направьте усилия на уменьшение количества выполняемого кода, нежели на его ускорение.

Например, вы пишете игру и хотите отобразить на первом экране таблицу очков, хранящуюся локально. Выполнение этого кода может оказаться на удивление затратным. Поскольку код будет выполняться впервые, возникнут издержки, связанные с его интерпретаций/компиляцией, и выполнение пройдет чуть медленнее, чем обычно работает ActionScript-код в steady-state. Во-вторых, затраты на чтение информации из файловой системы. И наконец, затраты на позиционирование и отображение информации на экране.

Вместо этого, рассмотрите возможность выполнить всю эту работу уже после того, как первый экран отобразился. А затем, пока пользователь занят разглядыванием всех достоинств вашего арта, вы можете подготовить таблицу очков и отобразить ее при помощи анимации.

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

Рендеринг

Применение графических процессоров (GPU) изменило подход к оптимизации рендеринга. При рендеринге с использованием CPU работать с большими объемами пикселей — расточительно, целесообразнее использовать математическое описание форм объектов и их преобразование, и лишь после этого отрисовывать. Это традиционный подход, который используется в AIR для работы с векторным содержимым.

GPU, напротив, используя конвеерную обработку, может черезвычайно быстро оперировать большими массивами пикселей, а вот с векторными изображениями дела обстят значительно хуже.

AIR позволяет взять лучшее из обоих подходов. Вы можете использовать все возможности flash по работе с векторными изображениями, а затем, закешировав результат как набор растровых изображений, эффективно отрисовать его на экране. Используйте BitmapData.draw() для этих целей.

Отметим также, что остается возможность использовать заранее подготовленные растровые изображения, вместо того, чтобы получать их из векторной формы на лету. Однако, это не так эффективно, в силу многообразия размеров и плотностей экранов мобильных устройств.

Память

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

На мобильных устройствах такой подход, как правило, неприменим. Если запрошенный размер памяти превышает доступный на данный момент, фоновые приложения вынуждено завершаются, высвобождая таким образом память. Если запрос на выделение памяти все еще не может быть удовлетворен, тогда запрашивающее приложение вынуждено прекратить свою работу.

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

Обе эти задачи могут быть достигнуты за счет явного управления памятью из приложения. Сначала это может показаться странным, ведь для этих целей существует сборщик мусора. Однако лучше думать о нем, как о механизме, который только очищает мусорную корзину, однако мусор в эту корзину вы должны отправлять сами.

Первый шаг на пути к явному управлению памятью — убедиться, что вы очищаете все ссылки на объект, если он больше не нужен. Вот пример: предположим, что у нас есть приложение, читающее при запуске XML-файл с настройками. После того, как настройки прочитаны и применены, в памяти хранится ссылка на корень дерева и соответственно связаное с ней дерево XML, которое нам уже не нужно. В таком случае нужно явно присвоить значение null ссылке на корень дерева, позволяя таким образом сборщику мусора освободить память.

Явное управление памятью также важно в случае работы с множеством однотипных объектов. Например приложение, подгружающее набор изображений, если оно написано неграмотно, и если этот набор достаточно большой, обязательно столкнется с нехваткой памяти. И наоборот, если программно ограничить максимальное количество изображений, пребывающих в памяти одновременно, проблем с памятью можно избежать. В нашем примере можно удалять старое изображение перед подгрузкой нового или циклически перезаписывать фиксированное количество изображений, находящихся в памяти.

Хранилище


Мобильные устройства предоставляют доступ к локальной файловой системе, где приложение может хранить свои настройки, документы и т.п. Как правило, приложение должно рассчитывать на то, что данные доступны только ему, и нет возможности делиться этими данными с другими приложениями. На всех устройствах хранилище доступно через свойство File.applicationStorageDirectory.

Addroid, помимо того, предоставляет дополнительную возможность использовать файловую систему на SD-карте, доступную по пути “/sdcard”. В отличие от основного хранилища, она доступна для чтения и записи всем приложениям на устройстве. Следует однако помнить, что SD-карта может быть извлечена из устройства или быть вставлена, но не смонтирована.

Учитывая распространенность камер на мобильных устройствах, не стоит забывать, что есть еще специальное общее хранилище для фотографий. Доступ к нему можно получить через CameraRoll API, упомянутое ранее в разделе “Изображения”. И хотя на некоторых платформах доступ к фотографиям можно получить непосредственно через файловую систему, это плохо сказывается на портируемости приложения и является плохой практикой.

Развертывание


В мире мобильных устройств распространение приложений происходит в основном через специальные магазины (app marketplaces). Эти магазины включают в себя специальный функционал на устройствах, для поиска, установки и обновления приложений.

Для размещения в конкретном магазине, AIR-приложение должно быть преобразовано в специальный формат, специфичный для каждой платформы. Например для размещения в Apple App Store это .ipa-файл, а для Android marketplace — .apk. Сделать это можно прямо из Flash Builder или, например, используя утилиту ADT.

Все магазины мобильных приложений требуют, чтобы приложение было подписано. Для iOS сертификаты выдает Apple. Для Android-устройств разработчики сами создают сертификаты, действительные как минимум 25 лет, и которыми они должны подписывать каждое свое приложение и обновления к нему. Таким образом, если вы публикуете свое приложение на разных площадках, вам нужно оперировать несколькими сертификатами.

Когда вы готовите приложение к размещению в Android market, помните что AIR там устанавливается отдельно (на iOS копия AIR идет в составе каждого приложения). Если ваше приложение запускается на устройстве с неустановленным AIR, пользователь будет перенаправлен на его установку (см. также флаг -airDownloadURL у ADT).

Что дальше?


Разработка с использованием Adobe AIR дает возможность создать единое мобильное приложение, которое может быть развернуто на множестве мобильных устройств, включая смартфоны и планшеты под управлением Android, iOS или BlackBerry Tablet OS.

Это достигается путем использования кроссплатформенных абстракций (например при доступе к фотографиям), предоставления информации о динамических свойств устройств (например размер экрана). В то же время AIR не мешает, когда помощь не требуется (например при использовании API файловой системы).

Разработка кроссплатформенных мобильных приложений требует от программиста знаний об эфективном использовании памяти и о жизненном цикле приложения. Объеденив эти познания со средой выполнения AIR, можно быстро создавать кросплатформенные приложения.

Полезные ссылки


Блоги

Разработка мобильных игр на flash + AIR

Книги

High Performance Flash: Performance tuning for Flash, Flex, AIR and Mobile applications, E. Elrom, 2012 — предзаказ на Амазоне
Developing Android Applications with Adobe AIR, V. Brossier, O'Reilly, 2011
Adobe AIR, Дж. Лотт, 2009 — Первая русскоязычная книга по Adobe AIR
Adobe AIR Bible, B. Gorton, Wiley, 2008

Форумы

Форум Adobe по мобильной разработке на AIR

Статьи

Статья «Что нового в AIR 3?»
Flex/AIR for iOS Development Process Explained!
Создание iOS приложения при помощи Flash CS5.5 + AIR 2.7

Разное

AIR Native Extentions (ANE): подборка инфы
Коллекция полезных ссылок по мобильной разработке на Adobe AIR
Официальная страница Adobe AIR
Adobe AIR Developer Center
Adobe Mobile and Devices Developer Center
Adobe AIR Cookbook
TourDeFlex — сборник информации по flash-платформе. В том числе и по мобильной разработке
Tags:
Hubs:
+40
Comments 38
Comments Comments 38

Articles