How do I use Push Notifications with Android in LiveCode 9.6.5?
In LiveCode 9.6.5, the Android engine is built using version 30 of the Android API, a requirement for new apps submitted to the Google Play store.
This has required some changes for Android apps. One of them is that GMC (Google Cloud Messaging) has now been retired, and replaced with Firebase Messaging. This requires a small change to Android Standalone Application Settings: the Push Sender ID
should be replaced with the path to a google-settings.json
configuration file which can be downloaded from the Firebase console.
In this lesson we will go through all the necessary steps, from setting up a new project in Firebase Console to sending a push notification to your LiveCode Android app.
Basic setup in Firebase Console
First, visit https://console.firebase.google.com/u/0/ and click on "Add project"
Give your project a name and press Continue:
In the next screen, you can turn off Google Analytics if you wish, and then click Create Project:
Wait while your project is created:
Click Continue once the new project is ready:
Next step is to add an Android app to this project:
Click on the Android icon to add an Android app to the project:
In the next screen, enter the Android Package Name. This should match the "Identifier" field in the Android Standalone Settings, e.g. com.livecode.pushNotificationTestLC965
Once you enter a package name, the "Register app" button is enabled. Press it to register your app:
Now you should have reached the next step, which is to download the google-services.json
file:
Download this file (google-services.json) and store it in a safe place. You will need this file in the Android Standalone Settings
Configuring Push Notification in the Android Standalone Settings
You need to check the Push Notification
checkbox, and then select the google-services.json
file you downloaded in the previous step. Moreover, make sure you have enabled the "Internet" permission.
Writing a LiveCode Application with Push Notification Support
When you have registered with Firebase and activated the service you can create a LiveCode stack that tries to register with the Push Notification Server. Add the following code to the LiveCode stack script:
on pushNotificationRegistered pMessage
answer "Registered:" && quote & pMessage & quote with "Okay"
end pushNotificationRegistered
Once you start the application, you should receive a message that is similar to the one shown in this step. The token displayed is specific to your device and you need to record it, so that you can send to the device from an application or a server. In this test scenario you may want to e-mail the token to yourself, possibly by updating the code as follows:
on pushNotificationRegistered pMessage
answer "Registered:" && quote & pMessage & quote with "Okay"
// Update the e-mail address as required
revMail "[email protected]",,"token",pMessage
end pushNotificationRegistered
on pushNotificationReceived pMessage
answer "Push Notification:" && quote & pMessage & quote with "Okay"
end pushNotificationReceived
As of LiveCode 9.6.10, the Android engine is built using version 33 of the Android API.
When building for API33 and running on Android 13 and above, applications which send push notifications must check that the user has granted the necessary permission to do so and request it if not.
This could be done, for example, when the user enables an app feature which requires such notifications, or on startup of the app, in the app's main openStack
handler, using the following code:
=========================================================
if the platform is "android" and the systemVersion >= 13 then
local tPostNotificationsPermissionGranted
put androidHasPermission("android.permission.POST_NOTIFICATIONS") \
into tPostNotificationsPermissionGranted
if not tPostNotificationsPermissionGranted then
androidRequestPermission "android.permission.POST_NOTIFICATIONS"
end if
put androidHasPermission("android.permission.POST_NOTIFICATIONS") \
into tPostNotificationsPermissionGranted
if not tPostNotificationsPermissionGranted then
answer "This app is not permitted to post notifications. You can change this" && \
"in the Settings app"
end if
end if
===========================================================
Sending a Push Notification
Visit Firebase's Notification Composer here: https://console.firebase.google.com/u/0/project/_/notification and choose your project:
In the next screen, choose Send your first message:
In the next screen, you can compose your notification. Enter a title and text for the notification, and click Next:
In the Target section, choose your target app id from the dropdown, and click Next:
In the Scheduling section, choose "Now" and click Next:
In the Additional options section, you can specify the "Payload" value. Note that the key is "livecode.payload", not just "payload". Then enter a value for the key "livecode.payload". This will be the payload string that will be received in the pushNotificationReceived
message:
Now go back to the "Notification" section, and click on the Send test message button:
In the dialog that opens, enter the device token, i.e. the one you got in the pushNotificationRegistered
message:
Once you enter the device token, press Test:
The registered device will receive the notification:
simon schvartzman
Hi, many thanks for this great lesson. I was able to successfully follow it and get it working. Question now is how to send a notification from a Livecode script. In the depreciated lesson there was a script showing how to do it but I'm afraid it doesn't work anymore with the new Firebase service. Many thanks for any hints
simon schvartzman
Regarding my previous comment I found the problem. I was using an API key from the previous version of the API, once I changed it to what now appears as the "Server Key" in the Project Credentials the notification was delivered.
simon
Here I'm again. I found another problem when sending the notification using the LC stack. Even though the notification is received neither the title nor the body are displayed when the APP is closed. What could be wrong?
Panos Merakos
Hello Simon,
I think that if you replace this line in the card script:
put pPayload into tDataA["payload"]
with:
put pPayload into tDataA["livecode.payload"]
then things will work.
Kind regards,
Panos
--
Simon
Hi Panos, many thanks for your prompt reply. Unfortunately it didn't work. Any other suggestion?
Best!
Panos Merakos
Hello Simon,
I'll try to create an updated LC stack for sending push notifications in LC 9.6.5, but I do not think I'll manage to have a look at this earlier than next week. Just a clarification - what is the exact problem with this stack? If I understood correctly, the notification is received by the app if the app is already running, but not if the app is not running? Or it is received in both cases, but if the app is not running, the title and body are not displayed? And what is it displayed in this case?
simon
Hi Panos let me try to clarify. Notifications are received in both cases with the APP running or not. When the APP is not running and the Notification is sent from the Cloud Messaging Console the Notification Banner shows: APP Logo + APP Name + Notification Title + Notification Text. When the notification is sent from the LC stack the Notification Banner shows just: APP Logo + APP Name.
Panos Merakos
Thanks for the clarification, Simon.
One last quick change to try:
Add these lines to the card script, just after the line you replaced previously (do keep the replaced line):
local tNotifA
put pTitle into tNotifA["title"]
put pBody into tNotifA["body"]
put tNotifA into tNotificationA["notification"]
Simon
Panos your are almost there! Please see below the differences (hope is clear enough)
Cloud Messaging LC Stack
1st Line APP Logo + Name APP Logo + Name
2nd Line Notification Title APP Name
3rd Line Notification Text Notification Title
Simon
Sorry it ended up with the wrong formatting....let's try again
Line ==== Cloud Messaging ==== LC Stack
1st ==== APP Logo + Name ==== APP Logo + Name
2nd ==== Notification Title ==== APP Name
3rd ==== Notification Text ==== Notification Title
Panos Merakos
Hello Simon,
Just tried with the changes I suggested, and I get the same result with Cloud Messaging and LC stack, that is:
Line ==== Cloud Messaging ==== LC Stack
1st ==== APP Logo + Name ==== APP Logo + Name
2nd ==== Notification Title ==== Notification Title
3rd ==== Notification Text ==== Notification Text
Could you please doublecheck?
In the LC stack, the "notification text" is whatever you enter into the field "Body"
Cheers,
Panos
--
Simon
Hi Panos, you are right and I was wrong. I was using the wrong contents for the "notification text", everything is working as expected. Many thanks for your customary help (now I need your extra help to make notifications work on iOS...)
Best regards
Alfred DiMola
Panos,
I got the LCS notification stack working thanks to you and Simon. A few of questions
1) No matter what I set the Badge value to it just increments the icon on the device by one. I don't see a Badge option on the FCM console. FCM notifications just increments it by one like the LCS method.
2) On the FCM console there is an optional image field. It does not show up on the notification although the preview shows it.(setLargeIcon()).
3) I assume you (LC) picked the upper left icon ( setSmallIcon() ) ??
4) On the FCM console I can just send the notification (not a test). It says that the notification was sent. I assume this is to all installs? I don't get the notification on the device. If sending a notification all install should work can I also do this from an LCS script?
5) How do I get a list of all registered app installs?
6) Just a note: I use a stub stack model. If the app is open when the message is received the pushNotificationReceived message goes to the current main stack. I the app is closed then when the app is opened it goes to the stub stack.
7) I observed that the pushNotificationReceived message does not fire until preOpenStack is complete. Is this correct?
Thanks!
Panos Merakos
Hello Ralph,
Lots of questions here, I need to do some investigation first :)
RE (1), how do you set the badge value? I had a look at the sample stack attached to the other lesson, and I believe this line:
put pBadge into tDataA["badge_value"]
should be replaced by:
put pBadge into tDataA["badge value"]
(i.e. replace the underscore with space in tDataA["badge_value"])
Similarly, when using the FCM console, the key name should be "badge value", not "badge_value".
I'll try to answer the other questions in the next couple of days.
Cheers,
Panos
--
Panos Merakos
Hello Ralph,
RE (2) and (3), indeed, the optional icon in the FCM console uses setLargeIcon(), but LC only supports setSmallIcon(), which you can set in the Android Standalone Settings.
Cheers,
Panos
--
Panos Merakos
@Ralph,
RE (4) and (5), how do you send the notification? If I press the "Send Test Message" button, I have to enter a "FCM registration token", which is the DeviceID. You can get the DeviceID for each install with "on pushNotificationRegistered pMessage" (pMessage is the deviceID - I should have made this clearer in the lesson, but I'll update it asap)
Panos Merakos
@Ralph,
RE (6), I think this is the expected behaviour, isn't it?
RE (7), I just had a look at the source code and it seems that the pushNotificationReceived message is sent *before* the preopenstack/openstack/preopencard/opencard messages. Are you observing the opposite?
Cheers,
Panos
Ralph
(4) Other than using the test button with specific token(s) you can schedule a notification without specifying any tokens. The FMC says that it was sent(I assumed to all registered users) but I don't see it on the device. I once saw this notification when I sent a test message right after I sent the scheduled notification. The scheduled(now) message followed the test message. That was the only time I saw the scheduled notification.
(5) I was just wondering if there was anyway to get a list of all registered users. I guess the only way is to record them on a back-end server.
(7) Let me address this before #6. I wanted to see if I could put any of the push-notification handlers in a library stack so no matter what main stack was active I could still handle the message centrally. The first thing I do in the preOpen handler is to "start using" my library stacks. I send an email via my web service from the registered message and added the "stacksinuse" to the email and all my library stacks(five) were loaded so I assumed that my preOpenStack handler had already run unless LC is searching for all LiveCode files in the package and did "start using"s for me?
(6) Yes I see that only the active(on screen) stack will get the message. I want to handle these messages in one central library, so if my libraries are loaded will the push-notification messages all go thru the message path and find their way to the library stacks?
Like Simon said "Thanks for the timely responses"!
Panos Merakos
Hello Ralph,
(4) Hmm, indeed, I scheduled a notification as you described, planned for "now", and I received it after a couple of hours. Interesting..
(5) Correct, I did some research and it seems you have to record the device IDs in a back end server.
(6)(7) Well, according to the LC engine code, the push notification messages are sent before the (pre) openStack one, so I guess in this case, you could still have all the notification-related messages in a library stack, but slightly tweaked, e.g. do something like:
In the main stack:
on pushNotificationReceived pMessage
if "myLibraryStack" is not among the lines of the stacksInUse then
start using stack "myLibraryStack"
end if
send "libPushNotificationReceived pMessage" to stack "myLibraryStack"
end pushNotificationReceived
and in the library stack:
on libPushNotificationReceived pMessage
// code for handling pushNotificationReceived msg here
end libPushNotificationReceived
The alternative is to add an "on startup" handler to your mainstack (the one which is built into the standalone) - you should be able to load your library stack(s) there.
And "startup" will happen before the push notification messages I think.
Cheers,
Panos
JereMiami
As of July 22, 2024, you have to migrate to HTTP v1 API. This requires changing the endpoint to from "POST https://fcm.googleapis.com/fcm/send" to "POST https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send"
That is fairly easy to do, but the second step is not so easy. First, you need to change the headers from "Authorization: key=AIzaSyZ-1u...0GBYzPu7Udno5aA" to "Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA"
Then you need to obtain a short lived OAuth2 access key to place in the above header (which used to be a generated Firebase private key).
Any ideas how we can get that Oauth2 access key?
https://firebase.google.com/docs/cloud-messaging/migrate-v1
Panos Merakos
Hello JereMiami,
Thank you for bringing this into attention. We will have a look and let you know.
Kind regards,
Panos
--
JereMiami
Okay, thanks! So, here is where I am at. I am using node.js to get the bearer short lived token and also to send the push messages now. But, here is what I do not understand. When I was using the Legacy FCM APIs, I was able to receive push notifications when the Livecode App was in the background and when it was closed. Now, when using HTTP v1 API, the Livecode application will only receive the push notifications when it is in the foreground.
Do you have any suggestions on how I can get these push notifications to be received when the Livecode App is in the background or closed?
JereMiami
Migrating from Firebase Legacy API to HTTP v1 API, I use node.js to send notifications to the LiveCode app deployed on Android. It works successfully both in the foreground and in the background. However, you should know about a few things that need to be noted.
First, pushNotificationReceived continues to work as it should. It will handle the notification once the application is brough to the foreground.
Second, in the Standalone Application Settings, the "Status Bar Icon" setting will cause an error when the app is in the background. The notification is successfully received and broadcast to the app, BUT the "Status Bar Icon" path will cause an error and the notification will not show in the notification tray. You must leave the "Status Bar Icon" empty and specify it in the Firebase Notification request (e.g., in node.js for me).
Otherwise, most of this information on this page remains correct.
JereMiami
Correction to the above regarding the "Status Bar Icon." I linked the "Status Bar Icon" to a .png file in the /res/drawable folder and it works with the selected .png file.
JereMiami
I have a new issue. Out of nowhere, the standalone will not grant permission for notifications. When you view the app in the app settings, the toggle switch is grayed out (and unable to be switched on), and states below:
"All notifications from this app are blocked."
Any idea how to resolve this? Thanks again in advance.
Panos Merakos
Hello JereMiami,
As of Android 13, you need to explicitly ask for permissions for push notifications. You can add this in your openStack handler:
if the platform is "android" and the systemVersion >= 13 then
local tPostNotificationsPermissionGranted
put androidHasPermission("android.permission.POST_NOTIFICATIONS") \
into tPostNotificationsPermissionGranted
if not tPostNotificationsPermissionGranted then
androidRequestPermission "android.permission.POST_NOTIFICATIONS"
end if
put androidHasPermission("android.permission.POST_NOTIFICATIONS") \
into tPostNotificationsPermissionGranted
if not tPostNotificationsPermissionGranted then
answer "This app is not permitted to post notifications. You can change this" && \
"in the Settings app."
end if
end if
Regards,
Panos
--