This post is also available in: Английский
Мультиплатформенность технологии AIR — это, безусловно, палка о двух концах. С одной стороны мы можем написать приложение Flex или ActionScript, которое будет корректно работать на всех возможных платформах, поддерживаемых AIR. С другой стороны, разработчики очень сильно ограничены тем, что AIR не всегда может предоставить весь набор инструментов для использования функционала, присущего только определенной платформе или конкретному устройству. К счастью, существует возможность написания расширений на родном для конкретной платформы языке. В такие расширения мы можем заложить функционал, присущий только этой среде. Данные расширения называются Native Extensions и подключаются к AIR-проектам как внешние библиотеки.
В своей работе мы очень часто используем подобные расширения. В данной статье речь пойдет о расширении as3c2dm, разработанным Piotr Walczyszyn, позволяющем получать push-сообщения и отображать их в панели уведомлений. Мы в своей работе активно используем данное расширение. В процессе его использования был выявлен ряд ошибок и неудобств, которые мы постарались исправить.
Основная ошибка, с которой мы столкнулись – это неверное отображение иконки приложения в панели уведомлений в случае, если приложение было собрано вместе со средой выполнения AIR (captive runtime package). Мы часто используем сборку приложений именно таким образом, что позволяет устанавливать и использовать приложения на устройствах, на которых не установлен Adobe AIR. Данная ошибка была исправлена.
Доработанное нами расширение, помимо всего прочего, позволяет разделить логику получения push-сообщений и отображения их в панели уведомлений. Это дает возможность не отображать уведомления каждый раз при получении push-сообщений, а отображать их в любой удобный для нас момент времени.
Доработанное расширение мы выложили на github.
Добавление расширения в проект
Для использования push-сообщений в проекте приложения необходимо подключить файл c2dm.ane как расширение (свойства проекта > Flex Build Path > вкладка «Native Extensions» > кнопка «Add ANE…»).
Далее необходимо в xml-файле описания приложения, помимо всего прочего, указать:
<id>ru.myDomain.myAppName</id>
<android>
<manifestAdditions><![CDATA[
<manifest android:installLocation="auto">
<permission android:protectionLevel="signature" android:name="air. ru.myDomain.myAppName.permission.C2D_MESSAGE" />
<uses-permission android:name="air.ru.myDomain.myAppName.permission.C2D_MESSAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<application android:hardwareAccelerated="true">
<receiver android:name="com.riaspace.c2dm.C2DMBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="air.ru.myDomain.myAppName" />
</intent-filter>
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="air.ru.myDomain.myAppName" />
</intent-filter>
</receiver>
</application>
</manifest>
]]></manifestAdditions>
</android>
<extensions>
<extensionID>com.riaspace.c2dm</extensionID>
</extensions>
Ну и, естественно, необходимо добавить соответствующий код в приложение, о чем будет рассказано ниже.
Автоматическое отображение уведомлений
Мы решили оставить возможность использования старого функционала, автоматически отображающего сообщение в панели уведомления. По умолчанию этот функционал отключен. Для его включения необходимо вызвать метод enableAutoNotify()
из класса C2DM
:
1 2 | var c2dm:C2DM = new C2DM(); c2dm.enableAutoNotify(); |
Для выключения автоматического отображения уведомлений используется метод disableAutoNotify()
:
1 | c2dm.disableAutoNotify (); |
При отключении автоматического отображения уведомления приложение должно получить событие, уведомляющее его о том, что push-сообщение получено. Затем, анализируя параметры сообщения, приложение должно иметь возможность принять решение, что делать дальше: показать уведомление пользователю, проигнорировать его, отобразить всплывающее окно, и т.п.
Обязательные поля при отправке push сообщения
Для корректной работы данного расширения необходимо передавать объект данных с правильными именами свойств.
При использовании автоматических уведомлений Piotr Walczyszyn предусмотрел следующие поля в данных:
tickerText
– сообщение на короткое время появляющееся в строке статуса, в момент получения уведомления;contentTitle
– заголовок сообщения при открытой панели уведомлений;contentText
– текст сообщения;parameters
– параметры, передающиеся приложению при открытии уведомления пользователем.
Более подробно о работе расширения с использованием автоматических уведомлений можно ознакомиться здесь.
При отключенном автоматическом отображении уведомлений мы решили использовать другие поля:
messageType
— тип сообщения. Указывая данный параметр, мы можем разделить сообщения на различные группы;itemName
– название элемента о котором говорится в уведомлении;itemId
– идентификатор элемента, содержащиегося в уведомлении;
Параметры itemName
и itemId
используются в том случае, если в уведомлении фигурирует определенный элемент. Например, начинается трансляция матча Лиги чемпионов Зенит – Малага (тип сообщения – «начало трансляции»), или закончилось действие абонемента «Неделька» (тип сообщения – «окончание действия абонемента»).
Получение уведомления приложением
Сразу после получения сообщения экземпляр класса C2DM
генерирует событие C2DMMessageEvent.MESSAGE
. Для получения информации о push-сообщении в обработчике данного события, необходимо воспользоваться методом message()
из класса C2DM
. Этот метод возвращает экземпляр класса C2DMMessage
, содержащий данные о полученном сообщении.
Класс C2DMMessage
содержит свойства, в которых будут содержаться данные, отправленные в push-сообщении, о которых мы уже писали выше: messageType, itemName, itemId
.
Отображение сообщения в панели уведомлений
Для отображения сообщения в панели уведомлений мы в классе C2DM
предусмотрели метод showNotification(tickerText:String, contentTitle:String, contentText:String, parameters:String)
, который может принимать следующие параметры:
tickerText
— текст, который появляется на короткое время в строке статуса;contentTitle
— заголовок сообщения;contentText
— текст сообщения;parameters
— строка с кастомными параметрами, которые передаются в приложение при открытии сообщения пользователем.
Используя данный метод, мы можем отобразить уведомление в любой момент времени, в том числе для событий, не связанных с получением push-сообщений, и это очень приятный бонус.
Приведем пример кода, в котором обрабатывается полученное push-сообщение, формируется уведомление и, впоследствии, отображается в панели уведомлений.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | private var c2dm:C2DM; private function init():void { if (C2DM.isSupported) { c2dm = new C2DM; ……………………………………. // Слушаем события о получении push-сообщения c2dm.addEventListener(C2DMMessageEvent.MESSAGE, onMessage); } } private function onMessage(event:C2DMMessageEvent):void { var msg:C2DMMessage = c2dm.message(); var notifyTickerText:String; var notifyContentTitle:String; var notifyContentText:String; switch (msg .messageType) { // начало трансляции case 0: notifyTickerText = "Начинается трансляция " + msg.itemName; notifyContentTitle = "Начинается трансляция"; notifyContentText = "Начинается трансляция " + msg.itemName + ". Посмотрим?"; break; // окончание абонемента case 1: notifyTickerText = "Закончился абонемент"; notifyContentTitle = "Закончился абонемент"; notifyContentText = " Закончился абонемент \«"+ msg.itemName+"\»."; break; default: break; } // Если все параметры заданы корректно, отобразим сообщение в панели уведомлений // Параметры для типа сообщения и идентификатора элемента передадим как строку JSON if (notifyTickerText && notifyContentTitle && notifyContentText) { c2dm.showNotification(notifyTickerText,notifyContentTitle,notifyContentText, JSON.stringify({type: msg.messageType, itemId: msg.itemId})); } } |
Открытие уведомления пользователем
В показанном выше примере для параметра parameters
мы передали JSON-строку, в которой закодирован объект с указанием типа сообщения и идентификатора элемента, о котором идет речь в сообщении. При открытии пользователем уведомления именно эту строку мы будем декодировать в объект, анализировать и принимать решение, что делать дальше. Например, при открытии пользователем сообщения о том, что начинается трансляция матча «Лиги чемпионов» Зенит — Малага, нужно открыть видеоплеер для просмотра матча, а при открытии сообщения об окончании действия абонемента — открыть окно с предложением продлить абонемент и т.п.
В parameters
совсем не обязательно передавать JSON-строку. Можно ограничиться и обычной строкой, если параметр один, или передать значения через запятую. Это все на усмотрение разработчика.
Приведем пример обработки приложением события об открытии пользователем уведомления:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | private function init():void { if (C2DM.isSupported) { ……………………… // подписываемся на событие об открытии пользователем уведомления NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE, onApplicationInvoke); } } private function onApplicationInvoke(event:InvokeEvent):void { if (event.arguments.length > 0) { // декодируем полученную строку в объект для получения переданных параметров var result:Object = JSON.parse(event.arguments[0]); var type:String = result.type; var itemId:String = result.itemId; switch(int(type)) { // начало трансляции case 0: { // отображаем видеоплеер, передавая в него itemId, содержащий идентификатор трансляции break; } // закончилось действие абонемента case 1: { // отображаем окно с предложением продлить абонемент с идентификатором itemId break; } } } |
Таким образом, даже при наличии большого количества непрочитанных сообщений, находящихся в панели уведомлений, мы можем идентифицировать каждое из них в случае открытия его пользователем.
Отладка приложения, получающего push-сообщения
Достаточно подробно о том, как правильно осуществлять отладку push-сообщений Piotr Walczyszyn рассказывет в своем видео as3c2dm getting started.
Сделаем короткую выдержку из этого видео.
В числе прочих свойств в XML-файле описания приложения внутри тега <id>
указывается идентификатор, уникальный для каждого приложения:
1 | <id>ru.myDomain.myAppName</id> |
AIR автоматически добавит к этому идентификатору префикс air. Главная же особенность при запуске приложения в режиме отладки заключается в том, что к этому идентификатору автоматически добавляется суфикс «debug». Поэтому в случае, если нужно отладить приложение, необходимо внести соответствующие изменения в файл описания приложения, добавив «.debug» везде, где встречается идентификатор приложения, за исключением содержимого тега <id>
:
<id>ru.myDomain.myAppName</id>
<android>
<manifestAdditions><![CDATA[
<manifest android:installLocation="auto">
<permission android:protectionLevel="signature" android:name="air. ru.myDomain.myAppName.debug.permission.C2D_MESSAGE" />
<uses-permission android:name="air.ru.myDomain.myAppName.debug.permission.C2D_MESSAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<application android:hardwareAccelerated="true">
<receiver android:name="com.riaspace.c2dm.C2DMBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="air.ru.myDomain.debug.myAppName " />
</intent-filter>
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="air.ru.myDomain.debug.myAppName " />
</intent-filter>
</receiver>
</application>
</manifest>
]]></manifestAdditions>
</android>
<extensions>
<extensionID>com.riaspace.c2dm</extensionID>
</extensions>
Для удобства мы рядом с файлом описания приложения храним два «файла-близнеца», в которых содержатся параметры для запуска приложения в режиме отладки и без него.
Надеемся что наши доработки помогут Вам при написании приложений, использующих Google Cloud Messaging.