NOTE: This article has been revisited, here. Please read that article as the code has now been updated to use that method.
Firebase Services from Google are becoming very popular, and Firebase Cloud Messaging (FCM) is just one part of it. In this article I show how you can incorporate support for FCM in your Delphi apps for Android and iOS.
Firstly, some acknowledgements: Many thanks to Stephane Vanderclock (aka Loki) from whom I gleaned much information, for the countless late nights he spent tearing his hair out working out how to make this all work, and for the code he wrote (which you can find here) which I’ve based almost all of my work on. Thanks also to Steven Chesser who was a willing guinea pig, and who is also thankful to Stephane and myself for probably saving his job, and thanks to Allen Drennan and company from Grijjy, for their amazingly excellent blog articles (particularly this one, from which this article is partly based) and their tools (one of which is used for this article).
Secondly, a few caveats: This article and the accompanying code is close to the bare minimum for incorporating Firebase Cloud Messaging. Stephane and I are not exactly experts in Firebase Cloud Messaging, and this implementation doesn’t pretend to cover everything. The Firebase libraries contain a number of other services (such as Firebase Crash, Analytics etc) that are not used by the code presented here: a future article may include how to use these. Also, the message payload that is passed to the OnMessageReceived event is completely raw: it is left up to the reader as to how the data might be dealt with when a notification is received while the app is running. Most importantly however, is that (as per step 9) this implementation requires that you disable all of the Google Play Services that Delphi adds automatically, so if your app relies on any of these, they will not work.
Thirdly, because this article grew a lot after I started it, I’ve decided to split it into two. This first part, although there are some pointers related to iOS, will feature Android, and iOS will follow shortly in part 2.
Fourthly, this article heralds the release of the free version of the Delphi Worlds “Kastri” library, which includes the framework for Firebase Cloud Messaging support, and the starter project which you will find in the demos folder. More features and demos will be added to this free library in the future, and the commercial version of the library will be released in the next few weeks.
Last of all: I used Delphi 10.2 Tokyo for this project, however it also works with at least Delphi 10.1 Berlin.
1. Creating a project in Firebase Console:
If you’ve never used Firebase before, the first thing you’ll want to do is to create a project in the Firebase console. Google provide some how to’s on YouTube for Firebase, so you might want to check them out. I recommend watching the one for iOS first, and pay attention up to the 2:23 mark, as the rest is specific to Xcode. Next, watch the video for Android, paying attention to the following sections: 0:59 – 1:14, 1:43 – 2:44, 2:59 – 3:03 and 3:46 – 4:04
If you already have a project set up for iOS and Android, you’ll need to download the files (if you haven’t done so already) that have information about your app, for the specific platforms. The one for iOS is GoogleService-info.plist. Please refer to the following images as to where in Firebase console you’ll need to download it from:
The file for Android is google-services.json:
Later you’ll be using these files in your project.
2. Download the required packages using the Android SDK Manager
The Android version of Firebase requires two packages that can be downloaded using the Android SDK Manager, which can be found at the root of the Android SDK installed on your system. If you opted to install the Android SDK with Delphi, it will be located in the folder:
Where xx refers to the version of BDS on your system. Run SDKManager.exe, and scroll down to the Extras section in the list of packages. There you will see Android Support Repository and Google Repository:
Select these two packages and click Install, then accept the license agreements and the packages will install. These packages contain files in .aar format, which are really just .zip files.
In order to make it easier to extract the required files from these packages, I have developed a tool called ACTED, which stands for Android Companion Tool Enhancing Delphi, and contains functions that automate extraction of files, create required jar files, and transform your google-services.json file into a resource required by Android. ACTED can be downloaded from here. For this demo, you will also need the configuration file (firebase-aars.json) from the starter project, to be used by ACTED when extracting the .aar files. If you’ve read the articles at Grijjy, this process may be familiar to you, however ACTED wraps everything up into two easy steps and removes the need for merging .dex files, which is done by Delphi at build time anyway.
3. Download the starter project:
As indicated in the introduction, there is a starter project that is contained in the demos of the Kastri Free library, which you will need to download (use the green “Clone or Download” button) if you wish to use the starter project. The companion jar file (dw-firebase.jar) in the Lib folder contains code for the service portion of the application.
The first thing you should do is modify the package name value in the project options, to match the identifier for your project in Firebase console, e.g:
4. Extracting the resources from the .aar packages:
Note: As per the Grijjy article, you will need to select JDK 1.7 in order for this to work. If you do not have JDK 1.7 installed, you can download it from here.
Once you have the required JDK 1.7, start the ACTED tool, click the Options button, and select the appropriate options, and click OK e.g:
Next, click the “Extract AAR Files” button, click the Load button, navigate to the firebase-aars.json file in the Configuration folder of the Kastri Free library, and click OK. This should load the list box with all required packages, and automatically select which packages that need their res files extracted from them:
Click the ellipsis button for the Extract Path edit, and select a folder for the extracted files. I recommend that you choose a folder which will be common to apps that require Firebase services, however you can choose a subfolder of your project if you desire.
Click the “Extract” button, and ACTED will extract all necessary files, and merge the xml files (where necessary) that contain resources.
5. Creating the jar containing the R classes:
In ACTED, click the “Create R Jar” button, then click the ellipsis button for the Path to libraries and resources edit, and select the folder which you specified in the previous step. Click the ellipsis button for the R Jar Filename edit, and select a location for the jar that will contain the R classes. I recommend using the \lib folder under the folder which is in the “Path to libraries and resources” edit, and to name the jar play-services-r.jar, e.g:
Click the Create R Jar button, and ACTED will use the Java compiler to build the jar.
6. Creating the required strings.xml resource:
If you watched enough of the video of Firebase and Android, you may have noticed that in Android Studio, you can just add the google-services.json file to an Android Studio project, and you’re good to go. With Delphi, the google-services.json file will need to be transformed into strings.xml, which is deployed with the application resources. Start ACTED (if it isn’t running already), and click the “Create strings.xml from google-services.json” button, click the ellipsis button for where the resulting strings.xml will go. Since this is specific to an application, I recommend that this file go somewhere under the project folder. Click the Import button, and ACTED will prompt you for the location of your google-services.json file, e.g:
Click Open, and the strings.xml file will be created with all the required information.
7. Using DeployMan to deploy the resources:
The DeployMan tool from the Grijjy site is a great tool for deploying files in bulk, which is the case for this demonstration. NOTE: Before using this tool, make sure you close the project in Delphi, and make sure you have a backup of your project files.
Close your project in Delphi, download and extract DeployMan, run it, and select the Android tab. Click File, Import .dproj and select your Delphi project. You will need to ensure that both the resources extracted in step 4, and your strings.xml, are included. Click the Add Folder button, select the res folder under the folder of the extracted resources, modify the target directory to be .\res, ensure you have the desired configurations selected (i.e. debug and/or release) and ensure that include subdirectories is checked. Click Add File, select your strings.xml file (generated in the previous step) and modify the target directory to be .\res\values. e.g.:
Click File, Save project
8. Modifying the application manifest:
The AndroidManifest.template.xml file in the project folder will need to be modified in order for Firebase Cloud Messaging to work. The manifest template in the starter project has already been modified, so you may use it as a reference for what changes need to be made. The changes are highlighted with xml comments that contain the text:
**** FCM ****
so that you know where they go. The rest of the manifest is what you would find in a typical manifest for a Delphi application for Android.
9. Managing the .jar files in the project:
The first part of this step is very important, and may affect you if your app relies on any of the Google Play Services that Delphi adds automatically. You must disable all but fmx.dex.jar and dw-firebase.jar in order for Firebase Cloud Messaging to work in your application.
In the Delphi project manager, expand the Target Platforms node, expand the Android node. Right-click each of the jars (except for fmx.dex.jar and dw-firebase.jar) and click Disable:
There are a number of other jar files required for this project, including those that were extracted in step 4. Right-click the Libraries node and click Add. Navigate to the lib folder under the extracted resources folder (from step 2) and select all the jar files, eg:
Click Open. If the jar containing the R classes that was built in step 5 is in a different folder, you will need to follow the same steps to add that, too.
10. Build, run and test the project:
Before running the starter project, you should start the Monitor program that comes with the Android SDK. You’ll find a batch file called monitor.bat in the tools folder of the SDK root. For the default Android SDK install for Tokyo, monitor.bat is located in:
It is wise to then create a filter, so you see only the messages for your application. To do this, click the green “+” button located in the LogCat tab, in the lower left, enter a name for the filter, and enter the package name for your application in the Application Name box:
Now go back to Delphi, select the debug configuration, compile, and run. Switch to the Monitor application, and watch for the messages when the application runs. The last message you should see is: “Token at startup:” followed by the token. You will need this value to send individual messages to the device, so select the message in Monitor, press Ctrl-C, the message will be copied to the clipboard, and you’ll be able to extract the token from it.
One convenient way of testing Firebase Cloud Messaging is to use the Hurl website. Go to the website, select the POST request type, and in the URL box, paste the following:
The request will require 4 header values, like pictured here:
The Authorization header requires a name/value pair where the name is: key, and the value is the Server API key, which can be found in your project on Firebase console in the project settings, on the Cloud Messaging tab:
Due to an apparent limitation in Firebase Cloud Messaging, messages must have a “data” section, otherwise Firebase will not process the message on the device when the application is not running (i.e. the associated service for the application receives the message). This is an example message:
"notification_title": "Firebase Cloud Messaging rules!",
"notification_text": "Congratulations, you received a message",
As per the example, in the “to” value, supply the device token that was copied earlier. On the Hurl page, click Add Body, and paste the message into the Parameters box.
Click “Launch Request”, and all things being well you should receive a 200 OK response, and the notification should appear in your app! Next, terminate the app on the device so that you know it is not running, and send another message. Now press the power button on your device so that the display turns off (don’t turn it off completely!), and send another message. You should see the notification appear in the lock screen.
Now for an explanation of the “non-obvious” items in the message:
notification_largeicon can be a url to an image somewhere on the internet. If you use this value, make sure the image is relatively small so that it doesn’t use too much data.
notification_vibrate is either 0 or 1
notification_priority of 1 ensures that the message also appears in the “home” screen.
notification_onlyalertonce is either 0 or 1, and a value of 1 means that the user isn’t repeatedly bothered by the notification
With this implementation, you can include whatever other data you wish as long as it is a valid json pair, and it will be passed to the application if it is already running, or when the user launches it from the notification.
Again, please bear in mind that I am no expert in Firebase Cloud Messaging; Stephane and myself have only just managed to have come this far just recently, and we’re still making refinements to the process. We hope however, that this article can give you a huge “leg up”. Sometime in the next few days, Part 2 will be published, outlining the requirements for making this work on iOS.