This guide discusses how to implement local and push notifications.
Corona SDK 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:
Local notifications are scheduled by an app locally and are delivered by the same device.
Push notifications are sent by a remote server (its provider) which sends these notifications to devices on which the app is installed.
Notifications are only supported on iOS and Android, not on macOS desktop, Windows desktop, Windows Phone, Apple TV, or Android TV.
To use push notifications, remember the following points:
The app has to support a registration process and it must support incoming messages.
You must configure your app and devices so that Apple and/or Google recognizes them. Apple/Google will send the actual messages out to devices.
If using iOS/Apple, your app cannot send push requests directly to their servers.
We recommend that you use a
Another option to handle push notifications on iOS is EasyAPNS. This is a PHP/MySQL setup that registers devices in your own database and allows you to send push notifications from your own server. Please visit www.easyapns.com for more information.
How an app reacts to notifications depends on its state:
Not running — the app has exited by design, user decision, reboot, etc. In this state, if the user interacts with the notification, the operating system will launch the app. Information about the notification event will be passed to the app using "launch arguments". The app should watch for these and react accordingly, for example, show a "snooze" button for an alarm or open a native.newWebView() if it has a URL. Note, however, that if the user starts the app by tapping directly on its icon, the notification will not be presented.
Backgrounded — the app is running but it's not the active app. In this state, if the user interacts with the notification by swiping on the unlock screen while the notification is showing or tapping on it in the notification center, the operating system will bring the app to the foreground and make it active. At this time, the app will receive the notification event but not receive launch arguments.
Foregrounded — the app is active and the user is currently interacting with it. In this state, the app will receive the notification event.
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"] = { publisherId = "com.coronalabs" }, }, }
Then, within the code module which uses notifications functions, simply require()
the library as follows:
local notifications = require( "plugin.notifications" )
Much of the iOS configuration for push notifications is done within the Apple Developer portal. Please refer to the guide for details.
In addition, you must include a notification
table in the config.lua
file (guide) to enable various features for push notifications. This tells the system which of the alert types you plan to use.
application = { content = { width = 320, height = 480, scale = "letterbox", xAlign = "center", yAlign = "center" }, notification = { iphone = { types = { "badge", "sound", "alert" } } } }
For iOS, the app must explicitly register for push notifications via the notifications.registerForPushNotifications() API. This will show the popup which asks the user if they want to enable push notifications.
Android also requires some additional configuration for push notifications. In the config.lua
file (guide), add a notification
table as follows. When you register with the Google GCM service, you'll get the projectNumber
value needed for the google
table.
application = { content = { width = 320, height = 480, scale = "letterbox", xAlign = "center", yAlign = "center" }, notification = { google = { projectNumber = "3982849975315" }, } }
In addition, you must include the following permissions in the build.settings
file (guide). Failure to include these entries will cause your push notifications to fail.
settings { android = { permissions = { { name = ".permission.C2D_MESSAGE", protectionLevel = "signature" }, }, usesPermissions = { "android.permission.INTERNET", "android.permission.GET_ACCOUNTS", "android.permission.RECEIVE_BOOT_COMPLETED", "com.google.android.c2dm.permission.RECEIVE", ".permission.C2D_MESSAGE", }, }, }
You can set custom notification icons in a Corona project by adding the following files to the root of the project directory, just like custom application icons. Note that different Android OS versions support different notification icon themes. You must support all of them or the app may get rejected in the review process. Please see Google's official documentation for details on icon sizes and themes.
File | Size (w×h) |
---|---|
IconNotificationDefault-ldpi-v11.png |
18 × 18 |
IconNotificationDefault-mdpi-v11.png |
24 × 24 |
IconNotificationDefault-hdpi-v11.png |
36 × 36 |
IconNotificationDefault-xhdpi-v11.png |
48 × 48 |
IconNotificationDefault-xxhdpi-v11.png |
72 × 72 |
IconNotificationDefault-xxxhdpi-v11.png |
96 × 96 |
IconNotificationDefault-ldpi-v9.png |
18 × 18 |
IconNotificationDefault-mdpi-v9.png |
24 × 24 |
IconNotificationDefault-hdpi-v9.png |
36 × 36 |
IconNotificationDefault-xhdpi-v9.png |
48 × 48 |
IconNotificationDefault-ldpi.png |
18 × 18 |
IconNotificationDefault-mdpi.png |
24 × 24 |
IconNotificationDefault-hdpi.png |
36 × 36 |
IconNotificationDefault-xhdpi.png |
48 × 48 |
-v11
set is for Android 3.0 or higher. These icons are expected to be white.-v9
set is for Android 2.3. These icons are expected to be grey.If you're a Corona Enterprise developer, please refer to the Enterprise and Android Icons notes below.
To schedule a local notification, use the notifications.scheduleNotification() function and specify the time of the future event in one of two formats:
The UTC option 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 timezone) instead of UTC.
You should also pass an options
table containing any the following parameters:
alert
(string) — The notification message to be displayed to the user. If the application is not currently running, a system alert will display this message.
badge
(number) — The badge number to be displayed on the application icon when the scheduled notification triggers. This replaces the last badge number that was applied. Set to 0
to omit the badge number. This option is not supported on Android.
sound
(string) — Name of the sound file in the system.ResourceDirectory to be played when the scheduled notification triggers. This sound is only played if the app is not currently in the foreground. On iOS, there are limitations on the kinds of sound that can be played (consult Apple's documentation for more details).
custom
(table) — A table that will be delivered with the notification event. This allows you to pass custom information with the notification.
To cancel a local notification before it triggers, use the notifications.cancelNotification() function and pass the ID returned by notifications.scheduleNotification().
In accordance with the Corona 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 --The notification Runtime listener should be handled from within "main.lua" Runtime:addEventListener( "notification", notificationListener )
A notification event returns a table of information which you can use to manage the specific notification. This table includes the following:
event.alert
— string value consisting of the message to display.event.applicationState
— string value of either "active"
or "inactive"
.event.badge
— number representing the badge count (iOS only).event.custom
— if this table exists, there may be data from the push service that helps your app react to the data. This is known as deep linking.event.name
— string value of "notification"
.event.sound
— string value representing a sound file, i.e. "alarm.caf"
.event.type
— string value of "local"
for local notifications or "remote"
for push notifications.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
This launchArgs
processing must be in main.lua
since it's the code which receives the data.
Notification badges (iOS only) are easily recognized by a small circle/number overlaying the app icon. They are available only on iOS. 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 or clear it entirely.
-- Decrement the badge number by 1 local function notificationListener( event ) if ( event.type == "local" ) then -- Handle the local notification local badge_num = native.getProperty( "applicationIconBadgeNumber" ) badge_num = badge_num - 1 native.setProperty( "applicationIconBadgeNumber", badge_num ) 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 -- Or clear the badge entirely native.setProperty( "applicationIconBadgeNumber", 0 )
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.
For push notifications, your app must register with the push provider's servers (Apple and Google). Corona handles the registration process for you in the background. Because you'll typically use a service to send push requests to the Apple and Google servers, that service needs to know about your app and device. Once registered, Corona will trigger the "remoteRegistration"
notification event.
To accommodate this, add an additional condition to your notification listener:
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 end end --The notification Runtime listener should be handled from within "main.lua" Runtime:addEventListener( "notification", notificationListener )
The code required to register your device varies depending on the service. Please consult your preferred provider's documentation or seek assistance in the Corona Forums.
If you're implementing notifications via Corona Enterprise for iOS, the following must be added to build.settings
:
settings = { iphone = { plist = { CoronaDelegates = { "CoronaNotificationsDelegate" } }, }, }
When developing natively for Android, Google wants all icons in the project's res
directory. This is important because Google's Android build process generates code, creating a R.java
file containing unique integer IDs to every resource that your project and its libraries contain. The IDs are needed to access these resources, including the notification icons.
First, you should become familiar with how Android handles resources by reading Google's official documentation.
When developing with Corona Enterprise, you need to override Corona's notification icon resources with your own. Before proceeding, inspect the Corona library's resource directory:
./CoronaEnterprise/Corona/android/lib/Corona/res
In this directory, every drawable
directory contains a file named corona_statusbar_icon_default.png
. This is the image file to override. Note that this action should be an "override" and not a replacement. You should not modify the contents of the Corona library directory!
To override these notification image files with your own, you need to set up the Android project with the same drawable
directories under your res
directory. Add each IconNotification*.png
icon to its respective drawable
directory by resolution and version (see Android Icons above). You also must rename these files to corona_statusbar_icon_default.png
.
If your Enterprise project is Android Studio-based, you'll need to make a small change to the build.gradle (Module: app)
's copyCoronaResources
task to ignore the notification icons provided in the Corona library project. Do this by replacing the from fileTree(...)
line with the following:
from fileTree(dir: "$coronaEnterpriseAndroidLibDir/res", exclude: '**/corona_statusbar_icon_default.png')
For Ant-based projects, this works as follows: when you do an Android build, it builds the app's libraries first, then it builds the app. If the Android build process finds resources files named identically between your app and its libraries, the app's resource files always take precedence and will be used instead of the library's resources. This is why most