flutter_sms_reader 0.0.1
flutter_sms_reader: ^0.0.1 copied to clipboard
Flutter plugin to read SMS inbox, conversations, and messages on Android with typed models.
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter_sms_reader/flutter_sms_reader.dart';
import 'package:permission_handler/permission_handler.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'SMS Reader Example',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'SMS Reader Example'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<SmsMessage> _smsMessages = [];
List<SmsConversation> _conversations = [];
bool _isLoading = false;
String _statusMessage = '';
@override
void initState() {
super.initState();
}
Future<void> _requestPermissions() async {
final status = await Permission.sms.request();
if (status.isGranted) {
setState(() {
_statusMessage = 'SMS permission granted';
});
} else {
setState(() {
_statusMessage = 'SMS permission denied';
});
}
}
Future<void> _getAllSMS() async {
setState(() {
_isLoading = true;
_statusMessage = '';
});
try {
final messages = await FlutterSmsReader.getAllSms();
setState(() {
_smsMessages = messages;
_statusMessage = 'Loaded ${messages.length} SMS messages';
});
} catch (e) {
log(e.toString());
setState(() {
_statusMessage = 'Error loading SMS: $e';
});
} finally {
setState(() {
_isLoading = false;
});
}
}
Future<void> _getConversations() async {
setState(() {
_isLoading = true;
_statusMessage = '';
});
try {
final conversations = await FlutterSmsReader.getConversations(limit: 20);
setState(() {
_conversations = conversations;
_statusMessage = 'Loaded ${conversations.length} conversations';
});
} catch (e) {
setState(() {
_statusMessage = 'Error loading conversations: $e';
});
} finally {
setState(() {
_isLoading = false;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 8),
if (_statusMessage.isNotEmpty)
Text(
_statusMessage,
style: TextStyle(
color: _statusMessage.contains('Error')
? Colors.red
: Colors.green,
),
),
],
),
),
),
const SizedBox(height: 16),
Wrap(
spacing: 8,
runSpacing: 8,
children: [
ElevatedButton(
onPressed: _requestPermissions,
child: const Text('Request Permissions'),
),
ElevatedButton(
onPressed: _isLoading ? null : _getAllSMS,
child: const Text('Get All SMS'),
),
ElevatedButton(
onPressed: _isLoading ? null : _getConversations,
child: const Text('Get Conversations'),
),
],
),
const SizedBox(height: 16),
if (_isLoading)
const Center(child: CircularProgressIndicator())
else
Expanded(
child: DefaultTabController(
length: 2,
child: Column(
children: [
const TabBar(
tabs: [
Tab(text: 'SMS Messages'),
Tab(text: 'Conversations'),
],
),
Expanded(
child: TabBarView(
children: [
_buildSMSList(),
_buildConversationsList(),
],
),
),
],
),
),
),
],
),
),
);
}
Widget _buildSMSList() {
if (_smsMessages.isEmpty) {
return const Center(
child: Text('No SMS messages loaded. Tap "Get All SMS" to load.'),
);
}
return ListView.builder(
itemCount: _smsMessages.length,
itemBuilder: (context, index) {
final sms = _smsMessages[index];
return Card(
margin: const EdgeInsets.symmetric(vertical: 4),
child: ListTile(
title: Text(sms.address),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(sms.body),
const SizedBox(height: 4),
Text(
'Date: ${_formatDate(sms.date)}',
style: const TextStyle(fontSize: 12, color: Colors.grey),
),
],
),
trailing: Icon(
sms.read ? Icons.mark_email_read : Icons.mark_email_unread,
color: sms.read ? Colors.green : Colors.orange,
),
onTap: () => _showSMSDetails(context, sms),
),
);
},
);
}
Widget _buildConversationsList() {
if (_conversations.isEmpty) {
return const Center(
child: Text(
'No conversations loaded. Tap "Get Conversations" to load.',
),
);
}
return ListView.builder(
itemCount: _conversations.length,
itemBuilder: (context, index) {
final conversation = _conversations[index];
return Card(
margin: const EdgeInsets.symmetric(vertical: 4),
child: ListTile(
title: Text(conversation.address),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(conversation.snippet),
const SizedBox(height: 4),
Text(
'Date: ${_formatDate(conversation.date)}',
style: const TextStyle(fontSize: 12, color: Colors.grey),
),
],
),
trailing: const Icon(Icons.chat),
onTap: () => _showConversationMessages(context, conversation),
),
);
},
);
}
String _formatDate(DateTime date) {
return '${date.day}/${date.month}/${date.year} ${date.hour}:${date.minute.toString().padLeft(2, '0')}';
}
void _showSMSDetails(BuildContext context, SmsMessage sms) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('SMS from ${sms.address}'),
content: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text('Body: ${sms.body}'),
const SizedBox(height: 8),
Text('Date: ${_formatDate(sms.date)}'),
Text('Date Sent: ${_formatDate(sms.dateSent)}'),
Text('Type: ${sms.type.description}'),
Text('Read: ${sms.read ? "Yes" : "No"}'),
Text('ID: ${sms.id}'),
],
),
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('Close'),
),
],
),
);
}
void _showConversationMessages(
BuildContext context,
SmsConversation conversation,
) async {
try {
final messages = await FlutterSmsReader.getConversationMessages(
conversation.threadId,
);
if (!context.mounted) return;
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Messages with ${conversation.address}'),
content: SizedBox(
width: double.maxFinite,
height: 400,
child: ListView.builder(
itemCount: messages.length,
itemBuilder: (context, index) {
final message = messages[index];
return Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(message.body),
const SizedBox(height: 4),
Text(
_formatDate(message.date),
style: const TextStyle(
fontSize: 12,
color: Colors.grey,
),
),
],
),
),
);
},
),
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('Close'),
),
],
),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error loading conversation messages: $e')),
);
}
}
}