Contents Hide
While BrightForms is typically used to initiate synchronisation of table records to and from the server, the BrightXpress mobility suite also supports pushing these records directly to devices, or pushing a request for the device to initiate a sync. This allows the server to initiate data to/from the device at runtime, without requiring the device to trigger this process via the sync engine.
On the BSP side, projects must have 'Enable Push Listener' property turned on to utilise either implementation of push. The 'Enable Background Listener' flag should also be activated in conjunction with this, in order to synchronise in the background on push where necessary.
Push functionality is performed by Script data sources' Push methods in the BEP. Any script may be used to utilise these push methods, but Script Jobs (either on a schedule or run manually in BrightBuilder) and Web services are typically used to invoke pushing to devices.
There are two types of push functionality which may be implemented in the BrightXpress Mobility suite:
Pushing may be performed across all platforms by pushing records directly to an IP address. Devices must be online for push to succeed. If the push could not be performed, an error will occur, with the server requiring to queue retries.
On iOS and Android platforms where devices are not configured to have static IP addresses, push functionality may be implemented using cloud services, specifically Google Cloud Messaging. This sets messages to be stored and pushed to devices. If the device is offline,any messages queued to be received will be retrieved when GetMessage() is performed.
A detailed breakdown of these two methods are detailed below.
Devices on all platforms may utilise this type of push, which will push records directly to a static IP address on a set push port opened on the device via script. This is handled by the Push object in scripts, which may be imported by the following statement:
importClass (Packages.au.com.brightsoft.integrator.Push) ;
The IP address may be retrieved from the device using the GetIpAddress() method, or on the server side by using getUserRemoteHostAddress(). Push port is configured in BrightForms' settings, and may be retrieved by the GetPushListenerPortNumber() method in BrightForms.
These parameters are used to instantiate the Push() object in the script.
Records in tables may be pushed directly to devices, using the sendData() method of a Push object instance. On receiving the push, BrightForms will read and write this record data directly to its tables. As tables are pushed to directly with this mechanism, the script is required to create record sets, whose definition of FieldInfo must match BrightForms' table definitions, else the client will not be able to consume the record.
An example of pushing records to a device (including import statements) is as follows:
// Import statements
importClass (java.util.Calendar) ; // To create and return Java Date values
importClass (java.util.Vector) ; // To create and manipulate Java Vector objects
importClass (java.lang.Integer) ; // To create and return Integer values
importClass (Packages.au.com.brightsoft.integrator.Record) ;
importClass (Packages.au.com.brightsoft.integrator.RecordSet) ;
importClass (Packages.au.com.brightsoft.integrator.FieldInfo) ;
importClass (Packages.au.com.brightsoft.integrator.Util) ;
importClass (Packages.au.com.brightsoft.integrator.Push) ;
In an expression, the following lines may be used to initiate the push:
// Record will be pushed to localhost port 8090
var ipAddress = "localhost";
var port = 8090;
try
{
var pusher = new Push(ipAddress, port) ;
var vect = new Vector();
// Create new record set for TEST_DATA table
rs = new RecordSet("TEST_DATA");
// Construct field data for record set
vfi = new Vector();
vfi.add(new FieldInfo("FIELD1", FieldInfo.INTEGER, true, 0, false));
vfi.add(new FieldInfo("FIELD2", FieldInfo.BOOLEAN, false, 0, true));
vfi.add(new FieldInfo("FIELD3", FieldInfo.STRING, false, 255, true));
vfi.add(new FieldInfo("FIELD4", FieldInfo.DOUBLE, false, 0, true));
vfi.add(new FieldInfo("FIELD5", FieldInfo.DATETIME, false, 0, true));
rs.setFieldInfo(vfi);
// Create and populate record
rand = Math.random() * 100;
bool = rand % 2;
str = "PUSHED RECORD";
date = Calendar.getInstance().getTime();
r = new Record();
r.add(new Integer(888));
r.add(bool);
r.add(str);
r.add(rand);
r.add(date);
rs.addRecord(r);
// Create a set of RecordSet to push - data may be across multiple tables
vect.add(rs);
// Push the set after they are constructed
ScriptSession.logInfo("Push Script - Pushing to " + ipAddress);
pusher.sendData(vect);
}
catch(error)
{
ScriptSession.logError("Error pushing record to " + ipAddress + ": " + error) ;
}
Records will be added on to the device if they do not exist in the table, otherwise they will be updated. As records are not managed by the sync engine, explicit culling methods should be designed for these records (such as deletion on logout if the records are older than n days, deleting processed pushed records etc).
On successful push, the On Push expression will execute, and any controls which are assigned queries to the tables which have been pushed will automatically refresh. Pushing record tables in this manner will be outside of the sync engine, and it is not advised to have tables which have records which are both pushed and synchronised (using sync rules) from the server.
BrightForms may determine what table is being pushed by the GetPushedTableName method.
Alternatively, a named sync rule in the BSP project may be specified by the script, which will then queue the rule up to be executed via BrightForms by sync engine in the background.
This is performed calling the forceRemoteSync() method, which will send a push notification to the device, and activate the rules for background sync. It is advised to use this method when there are a large number of records to be sent, or the table uses the sync engine, but also needs to retrieve records on the fly with push infrastructure.
An example using this method is as follows:
// Record will be pushed to localhost port 8090
var ipAddress = "localhost";
var port = 8090;
try
{
var pusher = new Push(ipAddress, port) ;
// We want devices to sync "syncGetRecords"
var syncRule = "syncGetRecords";
// Push the set after they are constructed
ScriptSession.logInfo("Push Script - Forcing " + ipAddress + " to sync " + syncRule);
pusher.forceRemoteSync(syncRule);
}
catch(error)
{
ScriptSession.logError("Error running sync rule on " + ipAddress + ": " + error) ;
}
Like with pushing records directly to the device, if the forceRemoteSync() method fails, an error will appear on the server.
As with other background sync rules, when the sync rule executes, the On Background Sync expression will run for each form. This will also refresh controls which utilise queries on the table in any opened forms.
BrightServer supports downstream pushing to devices with dynamic IP addresses via Google Cloud Messaging (GCM) Services. This feature is available on Android as of BrightForms version 9 onwards, provided that Google Play Services is supported and installed on the device, and from BrightForms 9.1.2 on iOS. Unlike direct pushing above, pushing to cloud services do not need any ports or additional setting to be forwarded when running.
As with pushing to static IP addresses, this is handled by script method calls on BrightServer.

The push from the server sends messages to devices and is handled by the sendTextMessageToUser() and sendTextMessageToDevice() methods in the script. In addition to these methods, notifications may also be pushed to devices with the sendNotificationToUser() and sendNotificationToDevice() methods. Pushing to a device uses a specific token, which may be retrieved in a user initiated script via the GetGCMTokenForUser() method.
This token is similar to a device ID, and is recorded on the server per user when BrightForms synchronises to BrightServer with a project having the 'Enable Push Listener' property set to 'true'. Therefore, in order for pushes via GCM to occur, the application must have synchronised to the server with a push-enabled application. As this token will be recorded for every BrightServer instance for each user, it is important to disable any unused user accounts on previously used BrightServer instances if the device is migrated to another BrightServer instance. The status of the user may then be checked before the push, using the Script User object. Furthermore, a push sent to a disabled user will throw an exception in the script. This is to ensure that pushes from multiple servers do not occur for the device.
Note:
If Google Play Services are not on the device, tokens cannot not
be generated, and a WARNING message will appear in BrightForms'
log as follows:
BFApplication.registerForGoogleCloudMessaging : Google Play services are not available: code=1
The example below demonstrates a GCM push message to a user account:
try
{
var user = SystemConfiguration.createUserObject("exampleUser");
if (user.isActive())
{
var gcmObj = ScriptSession.createGCMServiceObject();
gcmObj.sendTextMessageToUser ("exampleUser", "Test GCM push", "");
}
}
catch(error)
{
ScriptSession.logError(error);
}
The above example will push the text 'Test GCM push' to the device which 'exampleUser' is using. It will only do this if the user is active in the system. If the user is not specified, or does not have a device, the sending will fail with error logged. This also applies if a device token supplied to the sendTextMessageToDevice() method is invalid.
The messages sent are not collapsed, as there is no collapse key specified. Therefore it will be sent to the device as separate pushes with any other messages stored on the GCM server.
In addition to the code above, the following code may be added before/after the sendTextMessageToUser method:
gcmObj.sendNotificationToUser ("exampleUser", "Test Title", "Test GCM notification", "");
This will send a notification to the user with title "Test Title", and body as "Test GCM notification".
For more information on these methods, please refer to Script Methods Reference > Helper Objects > GCMService.
Messages on the GCM server will be stored, then pushed to the user or device. If the user/device is online, for each message sent to the device, On Push expressions of any opened forms will run. If the user/device is offline, the message will be stored on the server for later forwarding.
The push to a device may be processed by the Synchroniser.HasPushMessage() method, which will return 'true' if a GCM message exists to be read. Consuming messages on devices is handled by the GetPushMessage() method, which will retrieve the message in text format for parsing by the BrightForms application.
One way this may be used is to send messages to devices with sync rules to run. The push expression may then retrieve this sync rule and run it to synchronise in the background. The device should also perform the acknowledgement that it has received its records at this stage, if required.
For example, the next block of code will check if there are any messages - if so, it will check the start of the message for the 'Sync' marker, and if that exists, a background sync will be initiated for the rule specified:
IF(Synchroniser.HasPushMessage())
{
IF(String.IndexOf(local.vMsg, "Sync:", 0) <> -1)
{
local.vIndex = String.IndexOf(local.vMsg, ":", 0) + 1;
local.vLength = String.Length(local.vMsg);
local.vRule = String.Mid(local.vMsg, local.vIndex, local.vLength);
local.vLine = local.vLine & "Running rule: " & local.vRule & CHAR_NEWLINE;
Synchroniser.EnableSyncRule(local.vRule, true);
Synchroniser.MakeBackgroundSyncRule(local.vRule, true);
Synchroniser.SynchroniseInBackground();
}
}
As messages are consumed by GetPushMessage(), it is advised to put this is in only one push event expression for the whole BSP project. Messages which may have been sent to the device while offline may be retrieved by these methods as follows:
WHILE (Synchroniser.HasPushMessage())
{
local.vMsg = Synchroniser.GetPushMessage();
// Code to further process message here
}
This should be called before the push listener is initialised, to process offline records accordingly.
Using GCM services, there are a few restrictions to this form of push, as follows:
The text in the message payload is limited to 4KB.
GCM will store 100 messages to be forwarded, without any order guaranteed. If this limit is reached, messages will be discarded.
A 'collapse key' may be specified when executing the push. This will replace any previously pushed message with the same collapse key on the server with the current message. Per device, 4 keys may exist on the server. If this number is exceeded, there are no guarantees to which messages will be kept.
For more information on GCM message options, please refer to:
https://firebase.google.com/docs/cloud-messaging/concept-options