WebSocket Reconnection in Flutter: Keep Your Real-Time App Alive
Teqani Blogs
Writer at Teqani
Real-time applications such as live chats and financial dashboards require continuous WebSocket connectivity. This article guides you through implementing automatic WebSocket reconnection in Flutter, ensuring a smooth user experience.
Setting Up the Flutter Project
First, add the necessary dependencies to your pubspec.yaml
file:
dependencies:
flutter:
sdk: flutter
web_socket_channel: ^2.3.0
rxdart: ^0.27.4
Creating a Reconnecting WebSocket Client
Encapsulate WebSocket logic into a reusable class:
import 'dart:async';
import 'package:web_socket_channel/web_socket_channel.dart';
import 'package:rxdart/rxdart.dart';
class ReconnectingWebSocket {
final String url;
WebSocketChannel? _channel;
Timer? _reconnectTimer;
bool _manuallyClosed = false;
int _retrySeconds = 1;
final BehaviorSubject<String> _messageStream = BehaviorSubject<String>();
Stream<String> get messages => _messageStream.stream;
ReconnectingWebSocket(this.url);
void connect() {
_manuallyClosed = false;
_channel = WebSocketChannel.connect(Uri.parse(url));
_channel!.stream.listen(
(message) {
_retrySeconds = 1; // reset on success
_messageStream.add(message);
},
onError: (error) {
print("Error: $error");
_scheduleReconnect();
},
onDone: () {
print("Connection closed");
_scheduleReconnect();
},
);
print('Connecting to $url...');
}
void _scheduleReconnect() {
if (_manuallyClosed) return;
_reconnectTimer?.cancel();
_reconnectTimer = Timer(Duration(seconds: _retrySeconds), () {
connect();
_retrySeconds = (_retrySeconds * 2).clamp(1, 64); // exponential backoff
});
print('Scheduled reconnect in $_retrySeconds seconds');
}
void send(String message) {
try {
_channel?.sink.add(message);
} catch (e) {
print("Send failed: $e");
}
}
void disconnect() {
_manuallyClosed = true;
_reconnectTimer?.cancel();
_channel?.sink.close();
_messageStream.close();
print("Disconnected manually");
}
}
Flutter UI for Testing
Create a simple UI to test the reconnection logic:
import 'package:flutter/material.dart';
import 'reconnecting_websocket.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final ReconnectingWebSocket socket = ReconnectingWebSocket('wss://echo.websocket.events');
@override
Widget build(BuildContext context) {
socket.connect();
return MaterialApp(
home: WebSocketTestPage(socket: socket),
);
}
}
class WebSocketTestPage extends StatefulWidget {
final ReconnectingWebSocket socket;
WebSocketTestPage({required this.socket});
@override
_WebSocketTestPageState createState() => _WebSocketTestPageState();
}
class _WebSocketTestPageState extends State<WebSocketTestPage> {
final TextEditingController _controller = TextEditingController();
void _send() {
if (_controller.text.isNotEmpty) {
widget.socket.send(_controller.text);
_controller.clear();
}
}
@override
void dispose() {
widget.socket.disconnect();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('WebSocket Reconnect Demo')),
body: Column(
children: [
Expanded(
child: StreamBuilder<String>(
stream: widget.socket.messages,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Center(child: Text('Message: ${snapshot.data}'));
}
return Center(child: Text('Waiting for messages...'));
},
),
),
Padding(
padding: EdgeInsets.all(12),
child: Row(
children: [
Expanded(child: TextField(controller: _controller)),
IconButton(icon: Icon(Icons.send), onPressed: _send),
],
),
)
],
),
);
}
}
Testing and Production Tips
- Use SSL (
wss://
) for production. - Integrate auth tokens before connection.
- Add ping/pong heartbeats for connection health.
- Create a connection status stream for better UX.
By implementing the ReconnectingWebSocket
client, you've enabled auto-reconnect with exponential backoff, managed streams with rxdart
, and achieved a clean separation of UI and connection logic. You can now build more robust, resilient Flutter apps.
All blogs are certified by our company and reviewed by our specialists
Issue Number: #beaaf720-278f-480a-81df-9736d7a52b0c