Local/Push Notifications

This guide discusses how to implement local and push notifications.

Overview

Solar2D supports two types of notifications: local and push. The purpose of both notification types is to notify the user about something — a message or an upcoming appointment, for example — when the application isn't running in the foreground. The essential difference between local notifications and push notifications is simple:

Notifications are only supported on iOS and Android, not on macOS desktop, Windows desktop, Apple TV, or Android TV.

Usage Notes

To use push notifications, remember the following points:

App Interaction

How an app reacts to notifications depends on its state:

Project Settings

To use the Notifications plugin, add an entry into the plugins table of build.settings. When added, the build server will integrate the plugin during the build phase.

settings =
{
    plugins =
    {
        ["plugin.notifications.v2"] =
        {
            publisherId = "com.coronalabs"
        },
    },
}

Inside this build.settings file, also include the minSdkVersion of 16 or higher. For more info about setting minimum SDK version, see this

settings =
{
    android =
    {
        minSdkVersion = "16",
    },
}

Then, within the code module which uses notifications functions, simply require() the library as follows:

local notifications = require( "plugin.notifications.v2" )
Important
  • For Android, all new apps, or existing apps being updated with push notifications for the first time, must use Firebase Cloud Messaging (FCM), supported by the current Notifications plugin (above). If you have a legacy app already configured for Google Cloud Messaging (GCM), it will continue to work indefinitely, but you should continue using the legacy plugin instead of the current notifications plugin.

  • For iOS, you can either use the Apple Push Notification Service (APNS) or Firebase Cloud Messaging (FCM) for push notifications (see below).

iOS Setup

Much of the iOS configuration for push notifications is done within the Apple Developer portal. In addition, you must specify what types of notifications your app will use within the notificationiphonetypes table of config.lua:

application =
{
    notification =
    {
        iphone = 
        {
            types = 
            {
                "badge",
                "sound",
                "alert"
            },
        },
    },
}

Firebase

If you want to use Google Firebase Cloud Messaging (FCM) for push notifications, follow these additional steps:

  1. Copy GoogleService-Info.plist, provided in the Firebase console, to your project's root directory alongside main.lua.

  2. Add the following entries to the iphoneplist table of build.settings:

settings =
{
    iphone =
    {
        plist =
        {
            UIBackgroundModes = { "remote-notification" },
            FirebaseAppDelegateProxyEnabled = false,
        },
    },
}

Android Setup

Android also requires some additional configuration for push notifications:

  1. Copy google-services.json, provided in the Firebase console, to your project's root directory alongside main.lua.

  2. Add an additional useGoogleServicesJson entry into the android table of build.settings. When added, the build server will read the settings from the JSON file and integrate them into your app during the build phase.

settings =
{
    android =
    {
        useGoogleServicesJson = true,
    },
}

Android Icons

You can set custom notification icons in a project by adding the following files to the root of the project directory, just like custom application icons. Please see Google's official documentation for further details.

File Size (w×h)
IconNotificationDefault-ldpi.png 18 × 18
IconNotificationDefault-mdpi.png 24 × 24
IconNotificationDefault-hdpi.png 36 × 36
IconNotificationDefault-xhdpi.png 48 × 48
IconNotificationDefault-xxhdpi.png 72 × 72
IconNotificationDefault-xxxhdpi.png 96 × 96

Scheduling Local Notifications

To schedule a local notification, use the notifications.scheduleNotification() function and specify the time of the future event in one of two formats:

  1. Number of seconds from the call time when the notification should be delivered.

  2. Time specified in Coordinated Universal Time (UTC). This should be a time table as returned by os.date("!*t"). Note that a common pitfall is to forget the exclamation point and pass "*t" instead of "!*t" this will return the time structure in local time (your time zone) instead of UTC.

You should also pass an options table containing any of the following parameters:

To cancel a local notification before it triggers, use the notifications.cancelNotification() function and pass the ID returned by notifications.scheduleNotification().

Handling Notification Events

In accordance with the Solar2D event/listener model, if your app is running in either the foreground or background and a notification arrives, you'll receive a notification event. It's your responsibility to initialize the system and set up a listener function to handle these events. Please review the following framework and then read the detailed subsections below.

local function notificationListener( event )

    if ( event.type == "remote" ) then
        -- Handle the push notification

    elseif ( event.type == "local" ) then
        -- Handle the local notification

    end
end

Runtime:addEventListener( "notification", notificationListener )

Notification Data

A notification event returns a table of information which you can use to manage the specific notification. This table includes the following:

Launch Arguments

When the operating system, as the result of an incoming notification, starts your app from an inactive (not running) state, the app receives the data as part of launchArgs instead of triggering a notification event. You can use your notificationListener function to process the launch arguments.

local launchArgs = ...

if ( launchArgs and launchArgs.notification ) then
    notificationListener( launchArgs.notification )
end
Important

This launchArgs processing must be in main.lua since it's the code which receives the data.

Notification Badges (iOS)

Notification badges on iOS are easily recognized by a small circle/number overlaying the app icon. If a notification passes a badge value, a badge equal to that value will appear over the app icon.

It's your responsibility to read and set the badge number depending on its previous value. This is accomplished with the native.getProperty() and native.setProperty() functions. In almost every case, when the user opens/handles the notification, you should decrement the badge number by 1 as follows:

-- Decrement the badge number by 1
local function notificationListener( event )

    if ( event.type == "local" ) then
        -- Handle the local notification
        local badgeNum = native.getProperty( "applicationIconBadgeNumber" )
        if ( badgeNum > 0 ) then
            badgeNum = badgeNum - 1
            native.setProperty( "applicationIconBadgeNumber", badgeNum )
        end

    elseif ( event.type == "remote" ) then
        -- Handle the push notification
        if ( event.badge and event.badge > 0 ) then
            native.setProperty( "applicationIconBadgeNumber", event.badge - 1 )
        end
    end
end

Alternatively, you can clear the badge entirely:

native.setProperty( "applicationIconBadgeNumber", 0 )

Notification Sounds

By default, the device will play a sound when a notification comes in. You can specify a custom sound file in your project to play instead of the default sound. For instance, if you have the file notification.wav inside your app bundle, you can specify the string "notification.wav" as part of the push bundle (if the sending service supports it) and the operating system will play that custom sound instead of the default. In this case, the event.sound entry in the event listener will equal this string.

Remote Registration (iOS)

On iOS, when you're ready to ask the user for permission to allow push notifications, you should call notifications.registerForPushNotifications(). This will show the popup which asks the user if they want to enable push notifications. It's recommended that you only ask for this permission when you need it and not at the startup of your app.

Important

If you're using Google Firebase Cloud Messaging (FCM) for push notifications, you should pass an additional parameter to notifications.registerForPushNotifications(). This parameter should be a table containing the useFCM key with a value of true:

notifications.registerForPushNotifications( { useFCM=true } )

Calling notifications.registerForPushNotifications() will trigger a remote registration event to your notification listener function. To accommodate this, add an additional condition:

local function notificationListener( event )

    if ( event.type == "remote" ) then
        -- Handle the push notification

    elseif ( event.type == "remoteRegistration" ) then
        -- Code to register your device with the service

    elseif ( event.type == "local" ) then
        -- Handle the local notification

    end
end

The code required to register your device varies depending on the service. Please consult your preferred provider's documentation or seek assistance in the forums or Discord.