inverge_websocket 1.1.0
inverge_websocket: ^1.1.0 copied to clipboard
Flutter SDK for the Inverge WebSocket service: room-based realtime over Socket.IO with an app-wide provider, context.socket, and auto room re-join.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:inverge_websocket/inverge_websocket.dart';
const _baseUrl = 'https://websocket.inverge.net';
const _apiKey = 'your_api_key';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// Configure the NATIVE emitter once (Android/iOS). persist:true stores the
// credentials in native storage so a background service — e.g. an Android
// foreground LocationService — can restore and emit without the Flutter engine.
// Wrapped in a try: it's a MissingPluginException on non-mobile platforms.
try {
await WebSocketNative.configure(baseUrl: _baseUrl, apiKey: _apiKey);
} catch (_) {}
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
// The Dart socket client, provided app-wide and reachable via context.socket.
return WebSocketInitializer(
config: const WebSocketConfig(
baseUrl: _baseUrl,
apiKey: _apiKey,
enableLogging: true,
),
child: MaterialApp(
title: 'inverge_websocket example',
theme: ThemeData(colorSchemeSeed: Colors.teal, useMaterial3: true),
home: const OrderPage(orderId: 8821),
),
);
}
}
class OrderPage extends StatefulWidget {
const OrderPage({super.key, required this.orderId});
final int orderId;
@override
State<OrderPage> createState() => _OrderPageState();
}
class _OrderPageState extends State<OrderPage> {
final List<String> _events = [];
String? _nativeStatus;
late final String _room = Room.scoped('order', widget.orderId);
@override
void initState() {
super.initState();
// Socket client: join the order's room and listen for its events.
final socket = context.socket;
socket.joinRoom(_room);
socket.on('location', _onLocation);
}
void _onLocation(dynamic data) {
setState(() => _events.insert(0, data.toString()));
}
// NATIVE emit path — the same call an Android/iOS background service makes.
Future<void> _nativeEmit() async {
setState(() => _nativeStatus = 'emitting…');
try {
final res = await WebSocketNative.emit(
_room,
'location',
payload: {'lat': 33.31, 'lng': 44.36, 'ts': DateTime.now().millisecondsSinceEpoch},
);
setState(() => _nativeStatus = 'native emit → ${res.statusCode} (${res.success ? 'ok' : res.error})');
} catch (e) {
setState(() => _nativeStatus = 'native emit failed: $e');
}
}
@override
void dispose() {
final socket = context.socket;
socket.off('location', _onLocation);
socket.leaveRoom(_room);
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Room $_room')),
body: Column(
children: [
StreamBuilder<ConnectionStatus>(
stream: context.socket.statusStream,
initialData: context.socket.status,
builder: (context, snapshot) => ListTile(
leading: Icon(
snapshot.data == ConnectionStatus.connected ? Icons.cloud_done : Icons.cloud_off,
),
title: Text('Socket: ${snapshot.data?.name}'),
subtitle: _nativeStatus == null ? null : Text(_nativeStatus!),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: FilledButton.icon(
onPressed: _nativeEmit,
icon: const Icon(Icons.send),
label: const Text('Native emit to this room'),
),
),
const Divider(),
Expanded(
child: ListView(
children: [for (final e in _events) ListTile(title: Text(e))],
),
),
],
),
);
}
}