The Lightstreamer Flutter Plugin enables any mobile (Android or iOS) or Web application to communicate bidirectionally with the Lightstreamer Server. The fully asynchronous API allows to subscribe to real-time data delivered directly by the server or routed via mobile push notifications, and to send any message to the server.
The library offers automatic recovery from connection failures, automatic selection of the best available transport, and full decoupling of subscription and connection operations.
The library also offers support for mobile push notifications (MPN). While real-time subscriptions deliver their updates via the client connection, MPN subscriptions deliver their updates via push notifications, even when the application is offline. They are handled by a special module of the Server, the MPN Module, that keeps them active at all times and continues pushing with no need for a client connection. However, push notifications are not real-time, they may be delayed by the service provider (Google Firebase or Apple APNs) and their delivery is not guaranteed.
In the dependencies:
section of your pubspec.yaml
, add the following line:
dependencies:
lightstreamer_flutter_client: 2.0.0
The lightstreamer_flutter_client
package comprises two libraries: lightstreamer_client.dart
for Android and iOS targets and lightstreamer_client_web.dart
for Web target.
These libraries are very similar, as they expose the same classes and methods. This means an application using the mobile library is almost source-code compatible with the same application using the web library. However, there are a few differences to keep in mind when writing apps that should work both on mobile and web devices.
-
Object lifespan When using the mobile library, references to the
LightstreamerClient
,Subscription
,MpnDevice
andMpnSubscription
instances must be maintained by the Flutter app for as long as these objects are in use. Failing to do so may result in the loss of events directed to these objects (e.g. listener notifications).// DO class MyClient { final client = LightstreamerClient("host", "adapter"); void connect() async { client.addListener(MyClientListener()); await client.connect(); } } // DO NOT class MyClient { void connect() async { var client = LightstreamerClient("host", "adapter"); client.addListener(MyClientListener()); await client.connect(); } }
The web library does not require such precautions.
-
Async Methods In the mobile library, most methods of the
LightstreamerClient
class (e.g.connect
,subscribe
, etc.) return aFuture
, whereas the corresponding methods of the web library returnvoid
or simple values.For example, in the web library, a client establishes a session as follows:
var client = LightstreamerClient("https://push.lightstreamer.com/", "DEMO"); client.connect();
The equivalent code for the mobile library is:
var client = LightstreamerClient("https://push.lightstreamer.com/", "DEMO"); await client.connect();
While the
await
command before the connection is optional in this case, it is recommended to include it to catch exceptions. -
Exception Types The web library throws exceptions such as
IllegalArgumentException
orIllegalStateException
, while the mobile library only throwsPlatformException
. -
Exception Timing The web library methods throw exceptions as soon as they detect an invalid condition, whereas the mobile library checks these conditions only during a few fundamental methods such as
connect
,subscribe
, etc. However, both libraries document the thrown exceptions when discussing the methods to which the exceptions logically belong. -
Precondition Failures on iOS Since the mobile library leverages the Lightstreamer iOS Client SDK to support the iOS target, and the iOS Client SDK uses Swift preconditions to validate method arguments, a failed precondition will abruptly stop the program execution when a Flutter app runs on an iOS device. However, in the same circumstances, both the web library and the Android library will throw an
IllegalArgumentException
.
import 'package:lightstreamer_flutter_client/lightstreamer_client.dart';
To connect to a Lightstreamer Server, a LightstreamerClient
object has to be created, configured, and instructed to connect to a specified endpoint.
A minimal version of the code that creates a LightstreamerClient and connects to the Lightstreamer Server at https://push.lightstreamer.com
will look like this:
var client = LightstreamerClient("https://push.lightstreamer.com/", "DEMO");
await client.connect();
For each subscription to be subscribed to a Lightstreamer Server a Subscription
instance is needed.
A simple Subscription containing three items and two fields to be subscribed in MERGE mode is easily created (see Lightstreamer General Concepts):
var items = [ "item1","item2","item3" ];
var fields = [ "stock_name","last_price" ];
var sub = Subscription("MERGE", items, fields);
sub.setDataAdapter("QUOTE_ADAPTER");
sub.setRequestedSnapshot("yes");
await client.subscribe(sub);
Before sending the subscription to the server, usually at least one SubscriptionListener
is attached to the Subscription instance in order to consume the real-time updates.
The following code shows the values of the fields stock_name and last_price each time a new update is received for the subscription:
sub.addListener(MySubscriptionListener());
class MySubscriptionListener extends SubscriptionListener {
void onItemUpdate(ItemUpdate update) {
print("UPDATE " + update.getValue("stock_name") + " " + update.getValue("last_price"));
}
}
Below is the complete Dart code:
import 'package:lightstreamer_flutter_client/lightstreamer_client.dart';
void main() async {
var client = LightstreamerClient("https://push.lightstreamer.com/", "DEMO");
await client.connect();
var items = [ "item1","item2","item3" ];
var fields = [ "stock_name","last_price" ];
var sub = Subscription("MERGE", items, fields);
sub.setDataAdapter("QUOTE_ADAPTER");
sub.setRequestedSnapshot("yes");
sub.addListener(MySubscriptionListener());
await client.subscribe(sub);
await Future.delayed(const Duration(seconds: 5));
}
class MySubscriptionListener extends SubscriptionListener {
void onItemUpdate(ItemUpdate update) {
print("UPDATE ${update.getValue("stock_name")} ${update.getValue("last_price")}");
}
}
The client can also send messages to the Server:
await client.sendMessage("Hello world");
The code below shows an implementation for a message listener:
await client.sendMessage("Hello world again", "sequence1", 5000, MyMessageListener(), true);
class MyMessageListener extends ClientMessageListener {
void onProcessed(String originalMessage, String response) {
print("PROCESSED $originalMessage");
}
}
A full running example app is included in the project under the example
folder.
To enable the internal client logger, create a LoggerProvider
and set it as the default provider of LightstreamerClient
.
var provider = ConsoleLoggerProvider(ConsoleLogLevel.DEBUG);
await LightstreamerClient.setLoggerProvider(provider);
The library offers support for Push Notifications on Apple platforms through Apple Push Notification Service (APNs) and Google platforms through Firebase Cloud Messaging (FCM). With Push Notifications, subscriptions deliver their updates through push notifications even when the application is offline.
-
Before you can add Firebase to your Android app, you need to create a Firebase project to connect to your Android app.
-
From the Firebase console, download the
google-services.json
configuration file and move it into the module (app-level) root directory of your app. -
In your root-level (project-level) Gradle file (
<project>/build.gradle
), add the Google services plugin as a dependency:plugins { id 'com.android.application' version '7.3.0' apply false // ... // Add the dependency for the Google services Gradle plugin id 'com.google.gms.google-services' version '4.4.2' apply false }
-
In your module (app-level) Gradle file (
<project>/<app-module>/build.gradle
), add the Google services plugin:plugins { id 'com.android.application' // Add the Google services Gradle plugin id 'com.google.gms.google-services' // ... }
-
In your module (app-level) Gradle file (
<project>/<app-module>/build.gradle
), add the dependencies for the Firebase messaging.dependencies { // ... // Import the Firebase BoM implementation(platform("com.google.firebase:firebase-bom:33.5.0")) // When using the BoM, you don't specify versions in Firebase library dependencies implementation 'com.google.firebase:firebase-messaging' }
-
Make sure that the
applicationId
field in the module (app-level) Gradle file (<project>/<app-module>/build.gradle
) has the same value as thepackage_name
field in thegoogle-services.json
file.
For further information, see the Firebase documentation.
-
In your Developer Account, enable the push notification service for the App ID assigned to your project.
-
In xcode, open the
xcworkspace
file from your Flutter project. -
In the Project navigator, click the
Runner
project and then select theRunner
target. -
Click Signing & Capabilities and add the Push Notification and Background Modes > Remote Notifications capabilities.
For further information, see the APNs documentation.
Before you can use MPN services, you need to configure the Lightstreamer MPN module (read carefully the section Mobile and Web Push Notifications
in the General Concepts guide).
Then you can create a MpnDevice
, which represents a specific app running on a specific mobile device.
var device = MpnDevice();
await client.registerForMpn(device);
To receive notifications, you need to subscribe to a MpnSubscription
: it contains subscription details and the listener needed to monitor its status.
var items = [ "item1","item2","item3" ];
var fields = [ "stock_name","last_price","time" ];
var sub = MpnSubscription("MERGE", items, fields);
var data = {
"stock_name": "\${stock_name}",
"last_price": "\${last_price}",
"time": "\${time}",
"item": "item1" };
var format = FirebaseMpnBuilder().setData(data).build();
sub.setNotificationFormat(format);
sub.setTriggerExpression("Double.parseDouble(\$[2])>45.0");
await client.subscribe(sub, true);
The notification format lets you specify how to format the notification message. It can contain a special syntax that lets you compose the message with the content of the subscription updates
(see the FirebaseMpnBuilder
and ApnsMpnBuilder
classes).
The optional trigger expression lets you specify when to send the notification message: it is a boolean expression, in Java language, that when evaluates to true triggers the sending of the notification. If not specified, a notification is sent each time the Data Adapter produces an update.
For more information, see the Mobile and Web Push Notifications
chapter in the General Concepts Guide.
-
Get the Lightstreamer Client Web SDK
-
Copy the file
lightstreamer-core.min.js
(or the filelightstreamer-mpn.min.js
if you need the Web Push Notifications, see below) in theweb
folder of your Flutter app -
Put the following line in the
<head>
section of the fileindex.html
just before every other<script>
element:<script src="lightstreamer-core.min.js" data-lightstreamer-ns="lightstreamer"></script>
(or the following line if you need the Web Push Notifications)
<script src="lightstreamer-mpn.min.js" data-lightstreamer-ns="lightstreamer"></script>
-
Add the following import to your app:
import 'package:lightstreamer_flutter_client/lightstreamer_client_web.dart';
To connect to a Lightstreamer Server, a LightstreamerClient
object has to be created, configured, and instructed to connect to a specified endpoint.
A minimal version of the code that creates a LightstreamerClient and connects to the Lightstreamer Server at https://push.lightstreamer.com
will look like this:
var client = LightstreamerClient("https://push.lightstreamer.com/", "DEMO");
client.connect();
For each subscription to be subscribed to a Lightstreamer Server a Subscription
instance is needed.
A simple Subscription containing three items and two fields to be subscribed in MERGE mode is easily created (see Lightstreamer General Concepts):
var items = [ "item1","item2","item3" ];
var fields = [ "stock_name","last_price" ];
var sub = Subscription("MERGE", items, fields);
sub.setDataAdapter("QUOTE_ADAPTER");
sub.setRequestedSnapshot("yes");
client.subscribe(sub);
Before sending the subscription to the server, usually at least one SubscriptionListener
is attached to the Subscription instance in order to consume the real-time updates.
The following code shows the values of the fields stock_name and last_price each time a new update is received for the subscription:
sub.addListener(MySubscriptionListener());
class MySubscriptionListener extends SubscriptionListener {
void onItemUpdate(ItemUpdate update) {
print("UPDATE " + update.getValue("stock_name") + " " + update.getValue("last_price"));
}
}
Below is the complete Dart code:
import 'package:lightstreamer_flutter_client/lightstreamer_client_web.dart';
void main() async {
var client = LightstreamerClient("https://push.lightstreamer.com/", "DEMO");
client.connect();
var items = [ "item1","item2","item3" ];
var fields = [ "stock_name","last_price" ];
var sub = Subscription("MERGE", items, fields);
sub.setDataAdapter("QUOTE_ADAPTER");
sub.setRequestedSnapshot("yes");
sub.addListener(MySubscriptionListener());
client.subscribe(sub);
await Future.delayed(const Duration(seconds: 5));
}
class MySubscriptionListener extends SubscriptionListener {
void onItemUpdate(ItemUpdate update) {
print("UPDATE ${update.getValue("stock_name")} ${update.getValue("last_price")}");
}
}
The client can also send messages to the Server:
client.sendMessage("Hello world");
The code below shows an implementation for a message listener:
client.sendMessage("Hello world again", "sequence1", 5000, MyMessageListener(), true);
class MyMessageListener extends ClientMessageListener {
void onProcessed(String originalMessage, String response) {
print("PROCESSED $originalMessage");
}
}
A full running example app is included in the project under the example
folder.
To enable the internal client logger, create a LoggerProvider
and set it as the default provider of LightstreamerClient
.
var provider = ConsoleLoggerProvider(ConsoleLogLevel.DEBUG);
LightstreamerClient.setLoggerProvider(provider);
The library offers support for Web Push Notifications on Apple platforms through Apple Push Notification Service (APNs) and Google platforms through Firebase Cloud Messaging (FCM). With Web Push, subscriptions deliver their updates through push notifications even when the application is offline.
Before you can use MPN services, you need to configure the Lightstreamer MPN module (read carefully the section Mobile and Web Push Notifications
in the General Concepts guide).
To receive notifications, you need to subscribe to a MpnSubscription
: it contains subscription details and the listener needed to monitor its status.
var items = [ "item1","item2","item3" ];
var fields = [ "stock_name","last_price","time" ];
var sub = MpnSubscription("MERGE", items, fields);
var data = {
"stock_name": "\${stock_name}",
"last_price": "\${last_price}",
"time": "\${time}",
"item": "item1" };
var format = FirebaseMpnBuilder().setData(data).build();
sub.setNotificationFormat(format);
sub.setTriggerExpression("Double.parseDouble(\$[2])>45.0");
client.subscribe(sub, true);
The notification format lets you specify how to format the notification message. It can contain a special syntax that lets you compose the message with the content of the subscription updates
(see the FirebaseMpnBuilder
and SafariMpnBuilder
classes).
The optional trigger expression lets you specify when to send the notification message: it is a boolean expression, in Java language, that when evaluates to true triggers the sending of the notification. If not specified, a notification is sent each time the Data Adapter produces an update.
For more information, see the Mobile and Web Push Notifications
chapter in the General Concepts Guide and the
the Firebase Cloud Messaging docs.
- Lightstreamer Flutter Plugin
- Lightstreamer Flutter Stock-List Demo
- Lightstreamer Flutter Project
- Flutter Mobile API Client Reference
- Flutter Web API Client Reference
- Lightstreamer Documentation
- The Plugin requires Lightstreamer Server 7.4.0 or later
- On Android devices, Android 8 (API 26) or later is required.
- On iOS devices, iOS 12.0 or later is required.