How to Use Google Cloud Messaging in Adobe AIR Applications

This post is also available in: Russian

Using \Google Cloud Messaging in Adobe AIR applications

However nice the multi-platform nature of AIR is, still it is a double-edged sword. On the one hand, we can write a Flex or ActionScript application that would work correctly on all possible platforms supported by AIR. On the other hand, developers feel much restricted by that AIR sometimes fails to provide all tools to fully use the functionality unique to a particular platform or device. Fortunately, we can write native extensions for a particular platform to implement features specific to this environment only. Such extensions are called Native Extensions and are attached to the AIR project as external libraries.

In our work, we often use such extensions. Here we are going to discuss the as3c2dm extension developed by Piotr Walczyszyn. It allows you to receive push-messages and display them in the notification bar. In our work, we are actively using the extension. As we have detected a number of errors and inconveniences in it, we have tried to correct them.

The main error that we have faced is invalid application icon in the system tray if the application was built using captive runtime package. We often build applications so as to be able to install and use them on devices that do not have Adobe AIR. We have corrected this error.

With our update, the extension also allows you to split the logic of push-messages and their display in the notification bar. This way you can avoid displaying notifications each time a push-message arrives and do it later, whenever needed. Please feel free to use our update on github.

Adding Extension to the Project

To use push-messages in the application project, connect c2dm.ane (Project Properties → Flex Build Path → “Native Extensions” tab → “Add ANE …” button).

Next, in the XML file describing the application, among other things, specify:

<!— 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>

And, naturally, you’ll need to add relevant code to the application. We are going to discuss this below.

Automatic Notification Display

We have decided to also leave the old functionality that automatically displays a message in the notification bar. By default, this functionality is disabled. To enable it, call enableAutoNotify() from the C2DM class:

1
2
var c2dm:C2DM = new  C2DM();
c2dm.enableAutoNotify();

To disable automatic notification display, the disableAutoNotify() method is used:

1
c2dm.disableAutoNotify();

When automatic notification display is disabled, the application should receive an event notifying it of a push-message received, and, by analyzing its parameters, be able to make a decision on what to do next: show a notification to the user, ignore it, show a popup, etc.

Required Fields on Sending Push Messages

To run the extension properly, the data object shall be passed with valid property names.

For automatic notifications, Piotr Walczyszyn has provided the following data fields:

  • tickerText – a message that briefly appears in the status bar at the time of receipt of the notification
  • contentTitle – a message title shown when the notification panel is open
  • contentText – message text
  • parameters – parameters passed to the application when the user opens notification.

More detailed information on the extension using automatic notifications can be found here.

When automatic notification display is disabled, we decided to use other fields:

  • messageType – is the message type. By specifying this option, we can classify messages into different groups;
  • itemName – is the name of the element contained in the notification
  • itemId – ID of the element contained in the notification

The itemName and itemId parameters are used in the event that a notification contains a certain element. For example, a Championship League match begins (message type – broadcast start), or Week’s subscription has ended (message type – subscription end).

Notification Arrival to the Application

Immediately after receiving a notification the C2DM class instance generates the C2DMMessageEvent.MESSAGE event. To get details of the push-message, in the handler of the event use the message() method from class C2DM returning an instance of the C2DMMessage class containing the message details.

The C2DMMessage class includes properties to contain the data sent in the push message that we have already mentioned above: messageType, itemName, itemId.

Display a Message in the Notification Bar

To display a message in the notification bar, from the C2DM class we have taken the showNotification(tickerText:String, contentTitle:String, contentText:String, parameters:String) method accepting the following parameters:

  • tickerText – the text that appears briefly in the status bar
  • contentTitle – message title
  • contentText – message text
  • parameters – a string with custom parameters passed to the application when the user opens the message.

Using this method, we can display a notification at any time, even for events not related to receiving of push-messages, and this is a very nice bonus.

Here is an example of code that processes the push-message received, generates a notification, and, subsequently, shows it in the notification bar.

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;
        ...........................................
        / / Listen to events of arrival of push-message
        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)
    {
        // broadcast start
        case 0:
            notifyTickerText = "Starting broadcast " + msg.itemName;
            notifyContentTitle = "Starting broadcast ";
            notifyContentText = "Starting broadcast " + msg.itemName + ". View it? ";
        break;

        //end subscription
        case 1:
            notifyTickerText = "End of subscription";
            notifyContentTitle = "End of subscription";
            notifyContentText = "End of subscription "+ msg.itemName+" \ ».";
        break;

        default:
        break;
    }

    // If all settings are correct, let's show the message in the notification bar
    // Pass parameters containing message type and element ID as JSON string
    if (notifyTickerText && notifyContentTitle && notifyContentText)
    {
        c2dm.showNotification(notifyTickerText,notifyContentTitle,notifyContentText, JSON.stringify({type: msg.messageType, itemId: msg.itemId}));
    }
}

Opening of Notification by User

In the example above, for the parameters parameter we passed a JSON string encoding the object by its message type and ID of the element referred in the message. When a user opens notification, this string will be decoded into an object, analyzed and a decision made as to what to do next. For example, when a user opens a message that a UEFA Champions League match begins, we’ll need to open the video player to watch the match. Also, when a user opens the subscription end message, we should invoke a window with a proposal to extend subscription, etc.

In parameters you should not necessarily pass a JSON string. We even can use one string if it contains a single parameter, or pass comma-separated values. It’s all up to the developer.

Here is an example of how an application can handle event of user opening the notification:

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)
    {
        ………………………
        // Subscribe to the event of user opening of notification NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE, onApplicationInvoke);
    }
}
private function onApplicationInvoke(event:InvokeEvent):void
{
    if (event.arguments.length > 0)
    {
        // decode the resulting string into an object to receive the passed parameters
        var result:Object = JSON.parse(event.arguments[0]);
        var type:String = result.type;
        var itemId:String = result.itemId;
        switch(int(type))
        {
            // broadcast start
            case 0:
            {
                // Display the video player, passing to it an itemId containing the broadcast identifier
                break;
            }
            // subscription ended
            case 1:
            {
                // Display a window suggesting to extend subscription itemId
                break;
            }
        }
    }
}

Therefore, even if there is a large number of unread messages in the notification bar, we can identify each of them when they are opened by the user.

Debugging of Application that have Received Push-Messages

In his video as3c2dm getting started, Piotr Walczyszyn provides much detail on how to debug push-messages.

Let’s view a short extract from the video.

Among other properties, the xml-file that describes the application uses the the <id> tag to set an unique identifier for each application:

1
<id>ru.myDomain.myAppName</id>

AIR will automatically add the air prefix to this identifier. When the application is run in the debug mode, the main specifics is that this identifier is automatically extended with the “debug” suffix. So in case you need to debug your application, you have to amend the application description file by adding “.debug” wherever you find the application ID, except inside <id>:

 <!— TODO: Replace all occurrences of  ru.myDomain.myAppName to your application ID, without forgetting the "air" prefix. -->

<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>

For convenience, next to the description file we store two twin files with parameters to run the application with/without the debug mode.

We hope that our enhancements will help you write applications based on Google Cloud Messaging.

Leave a Reply