← All extensions

Native extension

KlugPush

com.klug.push.Push

NO APM NEEDED. Download and enjoy. It can’t get any simpler. Just update the Adobe AIR SDK. If you need help, we are here.

Push notifications for AIR apps on iOS, Android and macOS. A tap on a notification opens your app exactly where it should, even from a cold start.

iOS Android macOS In production From €9 / year · Buy

Overview

KlugPush brings remote push notifications to AIR apps on iOS, Android and macOS with one extension and one ActionScript API. It asks for permission, registers the device, gives you the token for your server and delivers incoming notifications to ActionScript.

On iPhone, iPad and Mac the notifications come directly from Apple's push service. There is no Firebase SDK in your app. On Android KlugPush uses Firebase Cloud Messaging; Google's messaging library is added automatically when the app is packaged, without any extra extensions.

When the user taps a notification, your app learns which one it was, also when the tap started the app. So you can open the right screen directly, for example a live view, a chat or an order.

KlugPush is in daily use in our apps on iOS, Android and macOS, our proof of concept.

Features

  • Self-contained: one ANE, no core library or dependency ANEs to add
  • iOS and macOS: directly through Apple's push service, no Firebase SDK in the app
  • Android: Firebase Cloud Messaging, Google's library is added at packaging
  • Tap to open: the payload of the tapped notification, also after a cold start
  • Notifications while the app is in the foreground: shown as a banner and delivered to ActionScript
  • Android notification channel with your own sound and importance
  • Permission prompt, live permission status and a shortcut to the notification settings
  • Android 13 and later: the notification permission is asked at runtime
  • Callbacks or StatusEvents, whichever fits your code

Supported platforms

iOS iPhone · iPad · Apple push service
Android phones · tablets · foldables · Firebase Cloud Messaging
macOS Apple silicon · Intel · Apple push service

On other platforms isSupported returns false, so the same code can stay in a cross-platform app.

Getting started

Add the extension to your application descriptor:

app.xml
<extensions>
    <extensionID>com.klug.push.Push</extensionID>
</extensions>

iOS and macOS: sign the app with the push notifications entitlement (aps-environment) and a provisioning profile that includes the Push Notifications capability.

Android: put the google-services.json of your Firebase project into the root of the app package and add these entries to the manifest additions:

app.xml · Android manifest
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<application>
    <service android:name="com.klug.push.KlugPushMessagingService" android:exported="false">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT"/>
        </intent-filter>
    </service>
    <activity android:name="com.klug.push.KlugPushPermissionActivity" android:exported="false"
              android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
    <provider android:name="com.klug.push.KlugPushFileProvider"
              android:authorities="air.YOUR.APP.ID.pushnotificationsfileprovider"
              android:exported="false" android:grantUriPermissions="true"/>
</application>

The provider lets the notification channel play a sound file from your app package.

Code examples

Four complete flows, taken from the API that runs in our apps on iOS, Android and macOS. Every call returns at once; results arrive through your callbacks and as StatusEvents. Full documentation →

1 · Set up, ask for permission and send the token to your server
Push.as
import com.klug.push.Push;

var push:Push = Push.getInstance();

if ( push.isSupported )   // iOS, Android, macOS
{
    // Android: notification channel with your sound file from the app root (created once).
    // iOS: only the last argument counts (show banners while the app is open).
    push.setup( "alerts", "Alerts", "alert.wav", Push.IMPORTANCE_HIGH, true );

    push.requestAuthorisation();   // system prompt, only while not decided yet
    push.register( onToken, onPushError, onNotification );
}

function onToken( token:String ):void
{
    // iOS / macOS: the APNs device token (64 hex). Android: the FCM registration token.
    if ( token != loadSavedToken() )   // your app functions
        sendTokenToServer( token );    // e.g. a POST to https://your.server/push
}

function onPushError( message:String ):void
{
    // typical causes: missing push entitlement (Apple) or google-services.json (Android)
    trace( "push registration failed: " + message );
}
2 · Open the right screen when the user taps a notification
TapToOpen.as
import flash.events.Event;
import flash.events.StatusEvent;
import flash.desktop.NativeApplication;

// cold start: the tap launched the app
openFromPayload( push.consumeSelectedNotification() );

// warm start: the app was in the background
NativeApplication.nativeApplication.addEventListener( Event.ACTIVATE, function( e:Event ):void {
    openFromPayload( push.consumeSelectedNotification() );
});

// iOS: the app was open and the user tapped the banner.
// Consume here too, so the next ACTIVATE does not open the same screen again.
push.addEventListener( StatusEvent.STATUS, function( e:StatusEvent ):void {
    if ( e.code == Push.NOTIFICATION_SELECTED ) openFromPayload( push.consumeSelectedNotification() );
});

function openFromPayload( json:String ):void
{
    if ( json == "" ) return;                     // not opened from a notification
    var payload:Object = JSON.parse( json );       // your own keys are included
    if ( payload.hasOwnProperty( "stationId" ) )
        openLiveView( payload.stationId );           // your app function
}

consumeSelectedNotification() returns each tap only once, so calling it at startup and on every activation never opens the same screen twice.

3 · Notifications while the app is running
Incoming.as
function onNotification( json:String ):void
{
    // the payload as your server sent it, plus your own keys
    var payload:Object = JSON.parse( json );
    showInAppHint( payload );   // your app function; the system banner shows as well
}

// later, e.g. after the user signed in to another account
function onLogin():void
{
    if ( push.token != null )        // the last token; null until registration finished
        sendTokenToServer( push.token );
}
4 · Permission status and notification settings
Settings.as
import flash.events.Event;
import flash.events.StatusEvent;
import flash.desktop.NativeApplication;

function updateNotificationSwitch():void
{
    var status:String = push.authorisationStatus();
    if ( status == Push.AUTHORISED )          showSwitch( "on" );    // your app function
    else if ( status == Push.DENIED )         showSwitch( "off" );
    else if ( status == Push.NOT_DETERMINED ) showSwitch( "not asked" );
}

// after a denial the system does not ask again: the way back is the settings page
function onSwitchTapped():void
{
    if ( push.authorisationStatus() == Push.DENIED ) push.openSettings();
    else push.requestAuthorisation();
}

// the answer to the prompt arrives as an event
push.addEventListener( StatusEvent.STATUS, function( e:StatusEvent ):void {
    if ( e.code == Push.AUTHORISATION ) updateNotificationSwitch();
});

// the user may have changed it in the settings: read the live status when the app comes back
NativeApplication.nativeApplication.addEventListener( Event.ACTIVATE, function( e:Event ):void {
    push.refreshStatus( function( status:int ):void { updateNotificationSwitch(); } );
});

API overview

Push.getInstance()Returns the single instance.
isSupportedTrue on iOS, Android and macOS, false elsewhere.
setup(channelId, channelName, sound, importance, showWhenActive)Android: creates the notification channel with a sound file from the app root. iOS: showWhenActive shows banners while the app is open. macOS: no effect.
requestAuthorisation()Shows the system prompt while the user has not decided yet. The answer arrives as AUTHORISATION.
authorisationStatus()AUTHORISED, DENIED, NOT_DETERMINED or UNKNOWN.
register(onToken, onError, onNotification)Registers for push. All three callbacks are optional; the token also arrives as TOKEN. Returns false where push is not supported.
tokenThe last token, or null until registration finishes.
consumeSelectedNotification()The JSON payload of the notification the user tapped to open the app, returned once; an empty string otherwise.
refreshStatus(onStatus)Reads the live permission status; onStatus(status:int) receives the raw value.
authStatusThe last raw status value: 0 not determined, 1 denied, 2 authorised; -1 until known.
openSettings()Opens the notification settings of your app.
unregister()iOS: stops receiving notifications until register() runs again.

Events

All events are StatusEvent.STATUS: the code names the kind, the level carries the value.

Push.TOKENlevel = the device token
Push.ERRORlevel = the error message from registration
Push.NOTIFICATIONlevel = the payload as JSON, received while the app is running
Push.NOTIFICATION_SELECTEDlevel = the payload as JSON, the user tapped the notification
Push.AUTHORISATIONlevel = AUTHORISED, DENIED or NOT_DETERMINED
Push.UNREGISTEREDthe device no longer receives notifications

Buy KlugPush

A yearly licence for one AIR application, with all updates for 12 months. After payment you receive the extension, the ActionScript library and the documentation by e-mail, usually within one business day. Licence and terms

Simple
€9 / year
  • Licence for one AIR application
  • All updates for 12 months
  • No support
Buy Simple
Standard
€39 / year
  • Licence for one AIR application
  • All updates for 12 months
  • Answer by e-mail within 7 days
Buy Standard
Priority
€79 / year
  • Licence for one AIR application
  • All updates for 12 months
  • Answer by e-mail within 48 hours
Buy Priority
Taxes are calculated at checkout by Link (Stripe). You enter the application ID of your AIR app during checkout.

Requirements

AIR SDK51.x (HARMAN)
iOSiOS 13 or later
AndroidAndroid 6.0 (API 23) or later
macOSmacOS 11 or later
SigningiOS and macOS: push notifications entitlement and a matching provisioning profile
ServeriOS and macOS: Apple's push service (token-based .p8 key). Android: Firebase Cloud Messaging HTTP v1