offline_sms 1.0.1
offline_sms: ^1.0.1 copied to clipboard
A Flutter package for peer-to-peer messaging via Bluetooth Low Energy (BLE) without internet connection.
Offline SMS #
A comprehensive Flutter package for peer-to-peer messaging via Bluetooth Low Energy (BLE) without requiring an internet connection. Perfect for offline communication between nearby devices.
Features #
- Device Discovery: Scan for nearby Bluetooth devices
- Secure Connections: Establish reliable BLE connections
- Real-time Messaging: Send and receive text messages instantly
- Cross-platform: Support for Android and iOS
- Permission Handling: Automatic Bluetooth permission management
- Connection Monitoring: Real-time connection state tracking
- Event Streaming: Stream-based architecture for UI integration
- Error Handling: Comprehensive error management and recovery
- Debug Logging: Detailed logging for development and troubleshooting
- Demo Mode: Web-based demonstration with device simulation
- Adaptive UI: Beautiful responsive design for mobile and web
- Message Sender Selection: Choose which device to send messages from (demo mode)
Use Cases #
- Offline Messaging: Send and receive text messages without internet connectivity
- Proximity Communication: Chat with devices in close physical proximity
- Emergency Communication: Reliable messaging when cellular networks are unavailable
- Local Networks: Create ad-hoc communication networks
- Privacy-Focused: Direct device-to-device communication without external servers
- Demo Mode: Web-based demonstration with simulated devices and messages
Installation #
Add this to your package's pubspec.yaml
file:
dependencies:
offline_sms: ^1.0.0
You can install packages from the command line:
flutter pub add offline_sms
Quick Start #
Basic Usage #
import 'package:offline_sms/offline_sms.dart';
void main() async {
// Create an OfflineSms instance
final offlineSms = OfflineSms();
// Initialize the Bluetooth system
final success = await offlineSms.initialize();
if (!success) {
print('Failed to initialize Bluetooth');
return;
}
// Listen to connection state changes
offlineSms.connectionStateStream.listen((state) {
print('Connection state: ${state.description}');
});
// Listen to discovered devices
offlineSms.discoveredDevicesStream.listen((devices) {
print('Found ${devices.length} devices');
for (final device in devices) {
print('- ${device.name} (RSSI: ${device.rssi})');
}
});
// Listen to incoming messages
offlineSms.messagesStream.listen((message) {
print('Received: ${message.content} from ${message.senderDeviceName}');
});
// Start scanning for devices
await offlineSms.startScanning();
// Connect to a device (assuming you have a device from discovery)
// await offlineSms.connectToDevice(device);
// Send a message
// await offlineSms.sendMessage('Hello, world!');
}
Complete Example #
import 'package:flutter/material.dart';
import 'package:offline_sms/offline_sms.dart';
class ChatScreen extends StatefulWidget {
@override
_ChatScreenState createState() => _ChatScreenState();
}
class _ChatScreenState extends State<ChatScreen> {
final OfflineSms _offlineSms = OfflineSms();
final List<OfflineMessage> _messages = [];
final List<OfflineDevice> _devices = [];
OfflineConnectionState _connectionState = OfflineConnectionState.unavailable;
OfflineDevice? _connectedDevice;
@override
void initState() {
super.initState();
_initializeOfflineSms();
}
Future<void> _initializeOfflineSms() async {
final success = await _offlineSms.initialize();
if (success) {
// Listen to state changes
_offlineSms.connectionStateStream.listen((state) {
setState(() => _connectionState = state);
});
// Listen to discovered devices
_offlineSms.discoveredDevicesStream.listen((devices) {
setState(() {
_devices.clear();
_devices.addAll(devices);
});
});
// Listen to messages
_offlineSms.messagesStream.listen((message) {
setState(() => _messages.add(message));
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('OfflineSMS - ${_connectionState.description}'),
actions: [
IconButton(
icon: Icon(_offlineSms.isScanning ? Icons.stop : Icons.search),
onPressed: _offlineSms.isScanning
? _offlineSms.stopScanning
: _offlineSms.startScanning,
),
],
),
body: Column(
children: [
// Device list
if (_devices.isNotEmpty)
Container(
height: 100,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: _devices.length,
itemBuilder: (context, index) {
final device = _devices[index];
return Card(
child: ListTile(
title: Text(device.name),
subtitle: Text('RSSI: ${device.rssi}'),
trailing: ElevatedButton(
onPressed: () => _connectToDevice(device),
child: Text('Connect'),
),
),
);
},
),
),
// Messages
Expanded(
child: ListView.builder(
itemCount: _messages.length,
itemBuilder: (context, index) {
final message = _messages[index];
return ListTile(
title: Text(message.content),
subtitle: Text(message.senderDeviceName),
trailing: Text(message.isFromMe ? 'Sent' : 'Received'),
);
},
),
),
],
),
);
}
Future<void> _connectToDevice(OfflineDevice device) async {
final success = await _offlineSms.connectToDevice(device);
if (success) {
setState(() => _connectedDevice = device);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Connected to ${device.name}')),
);
}
}
@override
void dispose() {
_offlineSms.dispose();
super.dispose();
}
}
Platform Support #
Platform | Support | Notes |
---|---|---|
Android | Full | Requires location permission for BLE scanning |
iOS | Full | Uses CoreBluetooth framework |
Web | Demo mode only | BLE not available in web browsers |
Desktop | Limited | Platform-specific BLE implementation required |
Configuration #
Android Permissions #
The necessary permissions are automatically included in the package. The Android manifest includes:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
iOS Permissions #
The necessary permissions are automatically included in the package. The Info.plist includes:
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app uses Bluetooth to communicate with nearby devices</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>This app uses Bluetooth to communicate with nearby devices</string>
API Reference #
OfflineSms Class #
The main class for Bluetooth chat functionality.
Properties
connectionStateStream
- Stream of connection state changesdiscoveredDevicesStream
- Stream of discovered devicesmessagesStream
- Stream of incoming and outgoing messagesconnectionState
- Current connection stateconnectedDevice
- Currently connected devicediscoveredDevices
- List of discovered devicesisScanning
- Whether currently scanningisAdvertising
- Whether currently advertising
Methods
initialize()
- Initialize the Bluetooth systemstartScanning()
- Start scanning for nearby devicesstopScanning()
- Stop scanning for devicesconnectToDevice(OfflineDevice device)
- Connect to a specific devicedisconnect()
- Disconnect from current devicesendMessage(String message)
- Send a message to connected devicestartAdvertising()
- Start advertising this devicestopAdvertising()
- Stop advertising this devicedispose()
- Clean up resources
OfflineMessage Class #
Represents a chat message.
Properties
id
- Unique message identifiercontent
- Message text contenttimestamp
- When the message was sent/receivedisFromMe
- Whether sent by current devicesenderDeviceId
- ID of the sending devicesenderDeviceName
- Name of the sending device
OfflineDevice Class #
Represents a discovered Bluetooth device.
Properties
id
- Unique device identifiername
- Device namerssi
- Signal strength indicatorisConnected
- Whether currently connectedisConnectable
- Whether device can be connected todiscoveredAt
- When device was discovered
OfflineConnectionState Enum #
Represents the current connection state.
Values
unavailable
- Bluetooth not availableidle
- Ready to scanscanning
- Currently scanningconnecting
- Attempting to connectconnected
- Successfully connecteddisconnected
- Disconnected from deviceerror
- Error occurred
Development #
Running the Example #
cd example
flutter run -d chrome # For web demo
flutter run -d android # For Android device
flutter run -d ios # For iOS device
Testing #
flutter test # Run all tests
flutter test test/offline_sms_test.dart # Run basic tests
flutter test test/offline_sms_integration_test.dart # Run integration tests
Code Analysis #
flutter analyze
License #
This project is licensed under the MIT License - see the LICENSE file for details.
Contributing #
Contributions are welcome! Please feel free to submit a Pull Request.
Technical Details #
Bluetooth Low Energy (BLE) #
- Range: 10-30 meters (depending on environment)
- Speed: ~1KB/second for message transfer
- Power: Low energy consumption, optimized for mobile devices
- Security: Built-in AES-128 encryption
- No Internet Required: Works completely offline
Message Format #
Messages are serialized as JSON and transmitted via BLE characteristics:
{
"id": "unique-message-id",
"content": "Message text",
"timestamp": "2024-01-01T12:00:00Z",
"isFromMe": true,
"senderDeviceId": "device-uuid",
"senderDeviceName": "Device Name"
}
Support #
If you encounter any problems or have suggestions, please file an issue on GitHub.