The Push Notes App is a Gluon code sample. Refer to the Gluon website for a full list of Gluon code samples.

In this tutorial, we’ll explain how to modify the Notes application to support push notifications and deploy it on Android and iOS devices. Before you start, be sure that you have checked the list of prerequisites, and you have installed the Gluon plugin for your IDE. Otherwise follow these instructions.

Note: This tutorial will use the plugin for NetBeans, but it works as well on IntelliJ and Eclipse.

Code: The code for this project can be found in the samples repository at GitHub. The sample is located under the directory pushnotes. The reader can clone this repository or create the entire project from scratch, based on the following steps.

Creating the project

This project can be created from scratch using the Gluon plugin on your favourite IDE. But since this is a follow up of the Notes app, we’ll clone the original Notes sample instead and modify it to add new features. We’ll refactor the main package to com.gluonhq.pushnotes and the application class to PushNotes. Make sure to do the necessary adjustments in the FXML (fx:controller), build.gradle, AndroidManifest.xml and Default-info.plist files.

Modifying the project

Let’s start modifying the default project to create our PushNotes application, based on the Notes sample.

The model package

The model package contains the Note, Model and Settings classes, exactly the same as in the Notes sample.

The service

In the original Notes sample, we created a service that used Gluon CloudLink to persist the notes we created and/or edited locally on the device. We’ll now modify that same service by persisting the data in the cloud.

When creating the DataClient object, we’ll use OperationMode.CLOUD_FIRST to indicate that data will be directly stored into and retrieved from Gluon CloudLink. Using a DataProvider as an entry point to retrieve a GluonObservableList, we need to supply a proper ListDataReader, a valid entity with the ability to read a list of objects. For that, the DataClient instance already has one method: createListDataReader(). All it needs is an identifier (NOTES), and the object class to be read (Note.class).

You can read more about the Gluon CloudLink Data Storage service here.

Service.java
public class Service {

    private static final String NOTES = "notes-v4";

    private static final String NOTES_SETTINGS = "notes-settings-v4";

    private final ListProperty<Note> notes = new SimpleListProperty<>(FXCollections.observableArrayList());

    private final ObjectProperty<Settings> settings = new SimpleObjectProperty<>(new Settings());

    private DataClient dataClient;

    @PostConstruct
    public void postConstruct() {
        dataClient = DataClientBuilder.create()
            .operationMode(OperationMode.CLOUD_FIRST)
            .build();
    }

    public void retrieveNotes() {
        GluonObservableList<Note> gluonNotes = DataProvider.<Note>retrieveList(
                dataClient.createListDataReader(NOTES, Note.class,
                        SyncFlag.LIST_WRITE_THROUGH, SyncFlag.LIST_READ_THROUGH,
                        SyncFlag.OBJECT_WRITE_THROUGH, SyncFlag.OBJECT_READ_THROUGH));

        gluonNotes.stateProperty().addListener((obs, ov, nv) -> {
            if (ConnectState.SUCCEEDED.equals(nv)) {
                notes.set(gluonNotes);

                retrieveSettings();
            }
        });
    }

    ...

}

Registering the app

The DataClient uses a key and a secret token that are specific for the application. Those tokens are used for signing the requests that are made to Gluon CloudLink. To obtain a key and secret, you need a valid subscription to Gluon CloudLink. You can get it here (there is also a 30-day free trial). Sign up and get a valid account on Gluon CloudLink and a link to access the Gluon Dashboard.

Open the Dashboard in your browser, and sign in using the Gluon account credentials provided to create the account.

Dashboard

Go to the App Management link, and you will find a pair of key/secret tokens. Click on the download button to download the file gluoncloudlink_config.json, and then store it under your project src/main/resources/ folder.

Configuration File

The content of the file is a JSON object with the key and secret that will grant access to Gluon CloudLink:

src/main/resources/gluoncloudlink_config.json
{
  "gluonCredentials": {
    "applicationKey" : "f88XXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
    "applicationSecret": "7fbXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
  }
}

Running the app

After updating the project, let’s run it on desktop to test that everything is in place.

Notes View
Filter
Drawer

We can also create one note:

Edition View

and change the settings:

Settings View

and we should see the results on the main view:

Settings View

If we close the app and open it again, the list of notes and the settings should be the same, as everything is persisted in the cloud, thanks to the Gluon CloudLink.

Gluon Dashboard

To track all the changes that happen in the cloud application you can run the Gluon Dashboard web application in your browser again. Sign in with your credentials and go to the Data Management link, you will be able to see the actual content of the settings object (Object tab) and the notes list (List tab):

Settings and Notes list

At anytime you can delete any entry, and this will be propagated to the client app.

Push Notifications

We can add push notifications to our app in two simple steps: Adding the required Charm Down plugins and adding a PushClient instance.

Required Plugins

Right click on your project root, and select Gluon Mobile Settings.

Gluon Mobile Settings

On the left list, find and select Push Notifications, and click on the > button:

Push Notification plugin

Also add the Device plugin:

Add plugins

Notice that the list of plugins will be updated accordingly on your build.gradle file:

build.gradle
jfxmobile {
    downConfig {
        version = '3.8.0'
        // Do not edit the line below. Use Gluon Mobile Settings in your project context menu instead
        plugins 'device', 'display', 'lifecycle', 'push-notifications', 'runtime-args', 'statusbar', 'storage'
    }
    ...
}

Reload the project, so the new dependencies are resolved.

The PushClient

On the application class, add an instance of PushClient and call the enable method, passing in an authorizedEntity. The value for the authorizedEntity parameter is the Sender ID of your Google Cloud Messaging or Firebase Cloud Messaging application. Follow this guide to get the authorizedEntity key.

Note: this value is only required for Android apps. iOS apps don’t need any specific configuration for the PushClient.

Firebase Project
PushNotes.java
public class PushNotes extends MobileApplication {

    @Override
    public void postInit(Scene scene) {
        ...

        PushClient pushClient = new PushClient();
        pushClient.enable("43XXXXXXXXXXX");

    }
}

Android

Modify the AndroidManifest file

According to the documentation for the Push Notifications plugin, edit and modify the AndroidManifest.xml file to include the required changes for this plugin:

AndroidManifest.xml
<?xml version="1.0" encoding="UTF-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.gluonhq.pushnotes" android:versionCode="1" android:versionName="1.0">
        <supports-screens android:xlargeScreens="true"/>
        <permission android:name="com.gluonhq.pushnotes.permission.C2D_MESSAGE" android:protectionLevel="signature" />
        <uses-permission android:name="com.gluonhq.pushnotes.C2D_MESSAGE" />
        <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

        <uses-permission android:name="android.permission.INTERNET"/>
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
        <uses-permission android:name="android.permission.WAKE_LOCK"/>
        <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="21"/>
        <application android:label="pushnotes" android:name="android.support.multidex.MultiDexApplication" android:icon="@mipmap/ic_launcher">
                <meta-data android:name="com.google.android.gms.version" android:value="9452000"/>
                <activity android:name="javafxports.android.FXActivity"
                          android:label="pushnotes"
                          android:launchMode="singleTop"
                          android:configChanges="orientation|screenSize">
                        <meta-data android:name="main.class" android:value="com.gluonhq.pushnotes.PushNotes"/>
                        <meta-data android:name="debug.port" android:value="0"/>
                        <intent-filter>
                                <action android:name="android.intent.action.MAIN"/>
                                <category android:name="android.intent.category.LAUNCHER"/>
                        </intent-filter>
                </activity>
                <receiver
                    android:name="com.google.android.gms.gcm.GcmReceiver"
                    android:exported="true"
                    android:permission="com.google.android.c2dm.permission.SEND" >
                    <intent-filter>
                        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                        <category android:name="com.gluonhq.pushnotes" />
                    </intent-filter>
                </receiver>
                <service
                    android:name="com.gluonhq.impl.charm.down.plugins.android.PushGcmListenerService"
                    android:exported="false" >
                    <intent-filter>
                        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                    </intent-filter>
                </service>
                <service
                    android:name="com.gluonhq.impl.charm.down.plugins.android.PushInstanceIDListenerService"
                    android:exported="false">
                    <intent-filter>
                        <action android:name="com.google.android.gms.iid.InstanceID" />
                    </intent-filter>
                </service>
                <service
                    android:name="com.gluonhq.impl.charm.down.plugins.android.RegistrationIntentService"
                    android:exported="false" >
                </service>
                <activity android:name="com.gluonhq.impl.charm.down.plugins.android.PushNotificationActivity"
                    android:parentActivityName="javafxports.android.FXActivity">
                    <meta-data android:name="android.support.PARENT_ACTIVITY"
                                       android:value="javafxports.android.FXActivity"/>
                </activity>
        </application>
</manifest>

Deploy to Android

Connect your Android device and run ./gradlew clean androidInstall. Opening the app will already show the note with the desktop client:

Android App

Sending a Push Notification

Within the Gluon Dashboard web application, select the Push Notifications link and open the Configuration tab. Paste the Server Key from your Google Cloud Messaging or Firebase Cloud Messaging application:

Server Key

Back to the Push Notifications tab you can create a new notification, pressing the + button. Provide a title and a body and click Accept.

Send notification

Immediately you will hear the notification on your Android phone.

Android notification

Clicking on it will open the application if it was closed, or put it on the foreground if it was in the background.

iOS

Certificates

Follow this step-by-step guide to get a p12 certificate for the dashboard and the provisioning profile for your app.

Signing the app

At the Apple Developer portal create and download the provisioning profile for your application.

iOS provisioning profile

Edit the build.gradle file to configure the project to use this provisioning profile. Also include the apsEnvironment clause, with either 'development' or 'production', depending on the type of certificate you are using.

build.gradle
jfxmobile {
    ios {
        ...
        iosSignIdentity = 'iPhone Developer: ...'
        iosProvisioningProfile = 'Push Notes Provisioning Profile'
        apsEnvironment = 'development'
    }
}

Connect your iOS device and run ./gradlew clean launchIOSDevice. A confirmation dialog will pop up, asking if you want to allow notifications. Accept it to allow push notifications to be sent to your device for this application.

Gluon Dashboard

Create the p12 certificate and upload it to CloudLink using the Dashboard web application. Please make sure to upload the correct certificate type for the correct environment.

iOS p12 certificate

Sending a Push Notification

If you create a new notification and send it to all the devices, you should receive it in your Android and iOS devices (if both Key Server and p12 Certificate are provided).

iOS notification

Processing push notifications

When the push notification is delivered to the device, a notification shows up. When clicking on it, the application is opened if it wasn’t running, or it is resumed if it was running on the background.

You can listen to that moment, and perform some action based on the payload of the notification using the Runtime Args Service:

PushNotes.java
@Override
public void postInit(Scene scene) {
    ...
    Services.get(RuntimeArgsService.class).ifPresent(ras -> {
        ras.addListener(RuntimeArgsService.LAUNCH_PUSH_NOTIFICATION_KEY, f -> {
            System.out.println("Received a push notification with contents: " + f);
            });
        });
    ...
}

If the push notification sent from the Dashboard is marked as silent, there won’t be a visible notification, but the listener will be called and it will be able to process the payload.

Conclusion

During this tutorial we have accomplished several tasks after updating the existing Notes sample:

  • We have modified the Notes sample to add cloud persistence with DataClient and GluonObservableList. And by using the Dashboard application we’ve been able to track the changes in those persisted lists and objects.

  • We have added new plugins to the project: Device and Push Notifications.

  • We have registered the app in Google Cloud Messaging and/or the Apple Developer center, and retrieved the required keys and/or certificates.

  • We have enabled push notifications on Android and iOS, and by using the Dashboard web application we have tested them on both platforms.

If you have made it this far, congratulations, we hope this sample and the documentation was helpful to you! In case you have any questions, your first stop should be the Gluon support page, where you can access the latest documentation and the Gluon knowledge base. Gluon also recommends the community to support each other over at the Gluon StackOverflow page. Finally, Gluon offers commercial support as well, to kick start your projects.