Использование Google Cloud Messaging в Adobe AIR приложениях

This post is also available in: Английский

Использование Google Cloud Messaging в Adobe AIR приложениях

Мультиплатформенность технологии 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-файле описания приложения, помимо всего прочего, указать:

<!— TODO: Заменить везде где далее встречается ru.myDomain.myAppName идентификатором Вашего приложения, не забывая добавить префикс “air”. -->
<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>:

<!— TODO: Заменить ru.myDomain.myAppName везде, где он далее встречается, идентификатором вашего приложения, не забывая добавить префикс “air”. -->
<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.