Push Notifications on Droidscript

NOTE: Proof Of Concept

So, you are developing DroidScript application and your requirement is to send Push-Notifications to user phone. Also, you want to handle correctly those notification messages, so each message would have different outcome: open particular page on your app or do whatever is needed.

Looks like there are some options not to use Google Firebase infrastructure for notifications, but get away with other tool. As this project is more of PoC- there will not be very mature back-end solution or front end. This project is more like showing the way how Push-Notifications can be implemented in you DroidScript app. Obviously, there are more solutions available, and I assume each one witch supports JavaScript should work. But we are learning, so it good to know basics.

This project is to let you understand what it basically needed to have this functionality. No paid tools or licenses are required, event for testing purpose no back-end hardware is required- Public free options can be used.

Basic concept of a project is following: there is Droidscript application, it has Service that runs on background. Service utilise MQTT protocol for receiving messages and creating Android Push-Notifications. Clicks on notification is handled by Main application. Each client should subscribe to unique topic (for PoC I simply used topic notification). Then back-end engine should send messages to required topics.

For MQTT messages, you can fire up your own MQTT Broker or use the Public one. Droidscript MQTT plugin work by communicating with broker user Web Sockets. Wikipedia: WebSocket is a computer communications protocol, providing full-duplex communication channels over a single TCP connection. The WebSocket protocol was standardized by the IETF as RFC 6455 in 2011, and the WebSocket API in Web IDL is being standardized by the W3C

This is not needed if you want to test with public brokers. You can skip this part

If you have chosen to set up your own hardware- please follow this write-up further. For this example I use Mosquitto (by Eclipse) software broker that works on mostly any hardware and operating system.

Eclipse Mosquitto is an open source (EPL/EDL licensed) message broker that implements the MQTT protocol versions 5.0, 3.1.1 and 3.1. Mosquitto is lightweight and is suitable for use on all devices from low power single board computers to full servers.

My hardware is Raspberry Pi 2B+. The same broker can be used in IOT projects, for example with ESP32 to send you sensors value. Here I will cover configuration required for Web Sockets and MQTT Broker. How this can be installed search here. If you are on linux, after installing broker you need to chaneg configuration. Edit following file with a command sudo nano /etc/mosquitto/mosquitto.conf or any other way you like it.

# if you need to have closed system- you need to
# provide were login details are saved
# if allow_anonymous is set to false
password_file /etc/mosquitto/public/public.passwd
listener 1884
allow_anonymous false

# web sockets configuration
listener 9004
protocol websockets

After changing configuration, you should be able to connect to your Broker via MQTT. For checking it, you can use HiveMQ WebSocket Client. Provide your broker IP, port (and login if needed). If it connects succesfully, you can subscribe to topic $SYS/# Here you will get all statistics how your Mosquitto is running.

The next step is to prepare software side. To work with MQTT- plugin is needed that is can be downloaded from droidscript application. Install it

Create new JavaScript application in your DroidScript . Your project must have two files: main file that is named after you project, and another, named “Service.js”. This tells your DroidScript application to run Service.js as Android service and listed for DroidScript messages.

//Called when application is started.
function OnStart()
{
    //Start our service.
    svc = app.CreateService( "this","this", ()={
        // On service ready
        console.log( "Service Ready" );
    });
    svc.SetOnMessage( OnServiceMessage );
 
    //This will cause your service to start at boot.
    //(Set it to "none" if you need to stop it starting)
    app.SetAutoBoot( "Service" );
 
    var id = app.GetNotifyId();
    if( id ) HandleNotification(id);
}
 
//Called when application is resumed.
//(eg. When user returns from home screen)
// or after notification is clickeed while app was open
function OnResume() {
    app.ShowPopup( "On resume!", "Short" );
	var id = app.GetNotifyId();
    if( id ) HandleNotification(id);
}
 
 
function HandleNotification(id) {
    app.CreateNotification().Cancel(id)
    app.Alert( id, "Notification ID" );
}
 
//Called when messages comes from our service.
function OnServiceMessage( msg ) {
    console.log( "Service Message: " + msg );
}

Here is code for your service file. File must be named exactly this way to make it work as Android service

Service.js
app.LoadPlugin( "MQTT" );
//Note: When running background services on newer Huawei phones, you
//may need to go into the Android battery saving settings and enable 
//DroidScript to run in the background if you want background 
//notifications to work when the phone is locked.
 
//Called when service is started.
function OnStart()
{
	//Force service to foreground on newer devices (required).
	if( app.GetBuildNum() > 25 ) {
        app.SetInForeground( "Waiting for notification...");
	}
 
	// my private mosquitto configuration
	var mosquitto_options = {
    	servers:[{
    		host: "bukys.eu",
    		port: 9004
    	}],
    	keepalive: 1800,
    	username: "myUser",
    	password: "myPass",
    }
    // Unique identifier for each device
    if(app.IsAPK())
        mosquitto_options.clientId = "Android-" + app.GetDeviceId()
    else
        mosquitto_options.clientId = "IDE-" + app.GetDeviceId()
 
    // Public mosquitto connection
    // client = mqtt.connect( 'ws://broker.hivemq.com:8000/mqtt' );
 
	client = mqtt.connect( mosquitto_options );
    client.on( 'connect', ()=>{
        client.subscribe( 'notification', {qos:2} );
 
        // send client id as message to topic "clients"
        client.publish("clients", mosquitto_options.clientId)
    });
 
    // create Android notification when MQTT message arrives to subscribed topic
    client.on( 'message',  (topic, message)=>{
        not = app.CreateNotification();
        not.SetMessage(
            "ticker",
            "MQTT "+topic,
            "Msg: " + message,
            "Message: "+ message
        );
        not.Notify( message );
    });
 
    setInterval(()=>{
        client.publish("heartbeat", new Date().toLocaleString())
    }, 60000)
}

Word of warning- android system limits web services. In my POC i've set up message publication each 1 minute to HeartBeat topic, so I would know how service behaves under the hood. On Android 11 Samsung device, at first it sends message each 1 minute, but later gradually increasing time between hear-beets. On my test average is 7 minutes. Looks like it does work correctly and on receiving MQTT message- prepare notification. Sure, if you unlock your device, heartbeat is sent each minute. You may need to play around with various battery optimisation setting for your application.

There are various MQTT protocol settings (Retained and QoS) may ensure that message is received even if device is disconnected upon sending notification message to broker from back-end. Client will get it when it connect to it unique topic.

Enter your comment. Wiki syntax is allowed:
If you can't read the letters on the image, download this .wav file to get them read to you.
 
  • blog/211121_push_notifications_on_droidscript.txt
  • Last modified: 2021/11/21 15:30
  • by Ignas