Building Real-Time Apps With Flutter And WebSocket
Mobile app development nowadays requires real-time data to offer rapid responses to users, whether it is a chat application that displays a person typing in real time or a distant application that plots data directly from a hardware sensor.
We try to fix these concerns with REST, but we run into a tricky problem: to get near-instant input, we must ping the server multiple times per minute, which can be tough to do architecturally and overload the server.
When utilizing solutions such as Firebase Realtime Database, you will notice that whenever a new record is added to the database, the Flutter application gets it as a Stream and displays the data to the user.
So how does Firebase accomplish this? In truth, frameworks like Firebase and others rely on a critical piece of technology called WebSockets.
In this post, we’ll look at how we can employ our own WebSockets to build apps that provide real-time data to our consumers.
What is WebSocket API?
The WebSocket API, according to Mozilla, is “a sophisticated technology that allows for the establishment of a two-way interactive communication session between the user’s browser and a server… You may send messages to a server and obtain event-driven answers without polling the service.”
WebSockets are made up of the following components:
- A server that broadcasts data
- A client in the application that is prepared to receive the new data stream
- A communication channel between the client and the server.
- Messages transmitted back and forth between the client and the server
Unlike REST, we do not wait for a response from the server after sending a message to it with WebSockets. We can send a single message and receive hundreds of responses from the server.
In some ways, it’s similar to subscribing to notifications; we subscribe to a certain topic, such as the USD-EUR exchange rate, and then we receive a new message from the server each time the USD-EUR exchange rate changes.
WebSockets’ real-time communication stream makes it the ideal solution for stock exchange apps, chat apps, IoT apps, and any other app that requires an incoming stream of data.
But how can we integrate Flutter? Let’s explore this in the below section!
Using WebSockets with Flutter in Apps
Thankfully, Dart, Flutter’s language, includes an out-of-the-box solution for dealing with WebSockets: The WebSocket class.
We can take use of WebSocket securely if we design apps for only one target (desktop, web, or mobile).
Nevertheless, if we choose to utilize our app on several platforms, we must keep in mind that the WebSocket class is dependent on dart:io and dart:html, which means we cannot build for both mobile and web at the same time.
Fortunately, the Dart team produced the web_socket_channel, an official library that encapsulates the dart:io and dart:html functionality and allows us to construct a multiplatform application with a single class.
We must take three easy actions to use the web_spclet_channel:
- Build a new WebSocketChannel client and connect to a channel using the connect method.
- With the stream getter, you may listen in on incoming messages.
- Send messages to the server using the sink getter.
Here are the steps for building real-time apps with Flutter and WebSockets.
Steps to build a real-time app using Flutter and WebSocket
Flutter is a powerful and popular framework for building mobile and web applications. Real-time apps require real-time data synchronization, which can be achieved using WebSocket, a protocol for real-time communication between a client and a server.
Here are the steps to build a real-time app with Flutter app development and WebSocket:
Create a new Flutter project:
To create a new project using Flutter, follow the command mentioned below:
1 |
flutter create my_realtime_app |
Add dependencies:
Add the web_socket_channel package to the pubspec.yaml file. This package provides a high-level API for working with WebSocket.
1 2 3 4 |
dependencies: flutter: sdk: flutter web_socket_channel: ^2.1.0 |
Create a WebSocket connection:
To create a WebSocket connection, use the WebSocketChannel.connect method, which returns a WebSocketChannel object. You can create the connection in the initState method of your widget:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
class MyRealtimeApp extends StatefulWidget { @override _MyRealtimeAppState createState() => _MyRealtimeAppState(); } class _MyRealtimeAppState extends State<MyRealtimeApp> { WebSocketChannel channel; @override void initState() { super.initState(); channel = WebSocketChannel.connect(Uri.parse('ws://localhost:8080')); } @override Widget build(BuildContext context) { // ... } @override void dispose() { channel.sink.close(); super.dispose(); } } |
In this example, we create a WebSocket connection to ws://localhost:8080. You can replace this with the URL of your WebSocket server.
Send and receive messages:
Once you have a WebSocket connection, you can use the sink and stream properties of the WebSocketChannel object to send and receive messages.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
class _MyRealtimeAppState extends State<MyRealtimeApp> { WebSocketChannel channel; TextEditingController _controller = TextEditingController(); @override void initState() { super.initState(); channel = WebSocketChannel.connect(Uri.parse('ws://localhost:8080')); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Realtime App'), ), body: Column( children: <Widget>[ Form( child: TextFormField( controller: _controller, decoration: InputDecoration(labelText: 'Send a message'), ), ), StreamBuilder( stream: channel.stream, builder: (context, snapshot) { if (snapshot.hasData) { return Text(snapshot.data); } else { return Text('No data'); } }, ), ], ), floatingActionButton: FloatingActionButton( onPressed: _sendMessage, tooltip: 'Send message', child: Icon(Icons.send), ), ); } void _sendMessage() { if (_controller.text.isNotEmpty) { channel.sink.add(_controller.text); } } @override void dispose() { channel.sink.close(); super.dispose(); } } |
In this example, we create a simple UI with a text input and a text view to display the received messages. We use the StreamBuilder widget to listen to incoming messages and update the UI accordingly.
The _sendMessage method sends the message entered in the text input to the WebSocket server.
Run the app:
To run the app, use the following command:
1 |
flutter run |
This will launch the app on an emulator or a connected device.
After running a Flutter app using the command flutter run, the next step would be to test and interact with the app to verify that it is working as intended.
Test the app:
Here are some steps you can follow to test your app:
- Check the app on the emulator or device: Once the app is launched, check if it is working as expected on the emulator or device. Ensure that the UI is rendering correctly and that the app is responding to user inputs.
- Check the console output: The console output can provide valuable information about any errors or warnings that the app encounters while running. Make sure to check the console output for any issues that need to be addressed.
- Test edge cases: Test the app with edge cases to ensure that it can handle unexpected inputs or scenarios. For example, if the app requires network connectivity, test it with and without network connectivity to ensure that it can handle both cases.
- Verify real-time functionality: If the app includes real-time functionality using WebSocket, verify that the data is being synchronized correctly between the client and server.
- Test on multiple devices: Test the app on different devices and screen sizes to ensure that the UI is responsive and renders correctly on different devices.
- Test performance: Use Flutter’s profiling tools to test the performance of the app and identify any bottlenecks or performance issues.
- Debug any issues: If any issues are identified during testing, use Flutter’s debugging tools to investigate and debug the issues.
Once you have tested and verified that the app is working as intended, the next step would be to deploy the app to the app stores or a hosting provider. And that’s it! You have created your very own application with Flutter and WebScoket.
Wrapping Up:
There may be occasions when we need to provide real-time data to a user, and as we’ve seen, WebSockets can simplify the process in Flutter app development services with just four simple steps:
- Making a customer
- Adding the client to a channel
- Messages are being sent to the server.
- Watching for new messages
This enables us to construct reactive apps in which our StreamBuilders widget changes based on the current state. Are we waiting for new information? Did we get an error or fresh information?
These inquiries can be converted into UI components, such as the animation that indicates someone is typing in a chat or altering the value of a graph on a page.
So here’s a question for you! Have you ever been required to show consumers real-time data in your applications? If so, what method did you employ? Firebase? WebSockets? dedicated Server-side gRPC Stream?
We eagerly await your response!