share_intent_package 1.0.24
share_intent_package: ^1.0.24 copied to clipboard
Zero-configuration Flutter share intent plugin. Receive shared content from other apps with one-command setup. Fully automated iOS ShareExtension + Android intent filters.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:share_intent_package/share_intent_package.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Bidirectional Share Test',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Bidirectional Share Test'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
SharedData? _receivedData;
String _status = 'Ready to receive shared content';
@override
void initState() {
super.initState();
_initializeShareIntent();
}
void _initializeShareIntent() async {
try {
// Initialize the plugin
await ShareIntentPackage.instance.init();
// Listen for incoming share intents while app is running
ShareIntentPackage.instance.getMediaStream().listen((sharedData) {
setState(() {
_receivedData = sharedData;
_status =
'Received shared content: ${_getContentSummary(sharedData)}';
});
});
// Check for any initial share data (when app was opened via share)
final initialShare = await ShareIntentPackage.instance
.getInitialSharing();
if (initialShare != null && initialShare.hasContent) {
setState(() {
_receivedData = initialShare;
_status = 'Initial share: ${_getContentSummary(initialShare)}';
});
}
} catch (e) {
setState(() {
_status = 'Error initializing share: $e';
});
}
}
String _getContentSummary(SharedData data) {
List<String> parts = [];
if (data.isText) {
parts.add('Text');
}
if (data.filePaths.isNotEmpty) {
parts.add(
'${data.filePaths.length} file${data.filePaths.length != 1 ? 's' : ''}',
);
}
return parts.join(' + ');
}
String _getContentTypeIcon(SharedData data) {
if (data.isImage) return '🖼️';
if (data.isVideo) return '🎬';
if (data.isUrl) return '🔗';
if (data.isText) return '📝';
if (data.isMedia) return '📎';
return '📄';
}
void _clearReceivedContent() {
setState(() {
_receivedData = null;
_status = 'Content cleared - ready for new shares';
});
// Clear the shared data from the plugin
ShareIntentPackage.instance.reset();
}
void _shareText() async {
try {
await ShareIntentPackage.shareText(
'Hello from Bidirectional Share Test! This is outbound sharing.',
);
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Shared text successfully!')),
);
} catch (e) {
if (!mounted) return;
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Error sharing text: $e')));
}
}
void _shareFiles() async {
try {
// For demo purposes, we'll try to share any received files
if (_receivedData?.filePaths.isNotEmpty == true) {
await ShareIntentPackage.shareFiles(_receivedData!.filePaths);
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Shared files successfully!')),
);
} else {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('No files available to share')),
);
}
} catch (e) {
if (!mounted) return;
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Error sharing files: $e')));
}
}
void _shareContent() async {
try {
await ShareIntentPackage.shareContent(
text: 'Check out this content from Bidirectional Share Test!',
filePaths: _receivedData?.filePaths ?? [],
);
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Shared content successfully!')),
);
} catch (e) {
if (!mounted) return;
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Error sharing content: $e')));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
actions: [
IconButton(
icon: const Icon(Icons.clear_all),
onPressed: _clearReceivedContent,
tooltip: 'Clear received content',
),
],
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Status Card
Card(
color: Colors.blue.shade50,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
Icon(Icons.info, color: Colors.blue.shade700),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Status',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.blue.shade700,
),
),
const SizedBox(height: 4),
Text(_status),
],
),
),
],
),
),
),
const SizedBox(height: 20),
// Instructions Card
Card(
color: Colors.green.shade50,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(Icons.share, color: Colors.green.shade700),
const SizedBox(width: 12),
Text(
'How to Test',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.green.shade700,
),
),
],
),
const SizedBox(height: 12),
const Text(
'📥 RECEIVE (Inbound):\n'
'1. Open Photos, Files, or any app with sharing\n'
'2. Select content (photos, files, text, etc.)\n'
'3. Tap Share button\n'
'4. Look for "Bidirectional Share Test"\n'
'5. Tap it to share content to this app\n\n'
'📤 SHARE (Outbound):\n'
'1. Use buttons below to share content from this app\n'
'2. Choose destination app from system share sheet',
style: TextStyle(height: 1.4),
),
],
),
),
),
const SizedBox(height: 20),
// Outbound Sharing Section
Card(
color: Colors.orange.shade50,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(Icons.send, color: Colors.orange.shade700),
const SizedBox(width: 12),
Text(
'Share FROM This App',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.orange.shade700,
),
),
],
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: ElevatedButton.icon(
onPressed: _shareText,
icon: const Icon(Icons.text_fields),
label: const Text('Share Text'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.orange.shade100,
foregroundColor: Colors.orange.shade700,
),
),
),
const SizedBox(width: 12),
Expanded(
child: ElevatedButton.icon(
onPressed: _shareFiles,
icon: const Icon(Icons.attachment),
label: const Text('Share Files'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.orange.shade100,
foregroundColor: Colors.orange.shade700,
),
),
),
],
),
const SizedBox(height: 12),
SizedBox(
width: double.infinity,
child: ElevatedButton.icon(
onPressed: _shareContent,
icon: const Icon(Icons.share),
label: const Text('Share Text + Files'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.orange.shade200,
foregroundColor: Colors.orange.shade800,
),
),
),
],
),
),
),
const SizedBox(height: 20),
// Received Content Section
if (_receivedData != null && _receivedData!.hasContent) ...[
Text(
'Received Content',
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 12),
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
_getContentTypeIcon(_receivedData!),
style: const TextStyle(fontSize: 24),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Shared Content',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
Text(
_getContentSummary(_receivedData!),
style: TextStyle(color: Colors.grey.shade600),
),
],
),
),
],
),
const SizedBox(height: 16),
// MIME Type
if (_receivedData!.mimeType != null) ...[
_buildInfoRow('MIME Type', _receivedData!.mimeType!),
const SizedBox(height: 8),
],
// Text Content
if (_receivedData!.text != null) ...[
_buildInfoRow('Text Content', _receivedData!.text!),
const SizedBox(height: 8),
],
// Files
if (_receivedData!.filePaths.isNotEmpty) ...[
const Text(
'Files:',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.indigo,
),
),
const SizedBox(height: 8),
for (
int i = 0;
i < _receivedData!.filePaths.length;
i++
)
Padding(
padding: const EdgeInsets.only(
left: 16.0,
bottom: 4.0,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('${i + 1}. '),
Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
_receivedData!.filePaths[i]
.split('/')
.last,
style: const TextStyle(
fontWeight: FontWeight.w500,
),
),
Text(
_receivedData!.filePaths[i],
style: TextStyle(
fontSize: 12,
color: Colors.grey.shade600,
fontFamily: 'monospace',
),
),
],
),
),
],
),
),
],
// Content Type Indicators
const SizedBox(height: 16),
Wrap(
spacing: 8.0,
children: [
if (_receivedData!.isImage)
_buildTypeChip('Image', Icons.image, Colors.green),
if (_receivedData!.isVideo)
_buildTypeChip('Video', Icons.videocam, Colors.red),
if (_receivedData!.isUrl)
_buildTypeChip('URL', Icons.link, Colors.blue),
if (_receivedData!.isText && !_receivedData!.isUrl)
_buildTypeChip(
'Text',
Icons.text_fields,
Colors.purple,
),
if (_receivedData!.isMedia &&
!_receivedData!.isImage &&
!_receivedData!.isVideo)
_buildTypeChip(
'File',
Icons.attach_file,
Colors.orange,
),
],
),
],
),
),
),
const SizedBox(height: 20),
],
// No Content Message
if (_receivedData == null || !_receivedData!.hasContent) ...[
Card(
color: Colors.grey.shade50,
child: Container(
width: double.infinity,
padding: const EdgeInsets.all(32.0),
child: Column(
children: [
Icon(Icons.inbox, size: 64, color: Colors.grey.shade400),
const SizedBox(height: 16),
Text(
'No shared content yet',
style: TextStyle(
fontSize: 18,
color: Colors.grey.shade600,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 8),
Text(
'Share some content from another app to see it here',
style: TextStyle(color: Colors.grey.shade500),
textAlign: TextAlign.center,
),
],
),
),
),
],
],
),
),
);
}
Widget _buildInfoRow(String label, String value) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'$label:',
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.indigo,
),
),
const SizedBox(height: 4),
Container(
width: double.infinity,
padding: const EdgeInsets.all(12.0),
decoration: BoxDecoration(
color: Colors.grey.shade100,
borderRadius: BorderRadius.circular(8.0),
border: Border.all(color: Colors.grey.shade300),
),
child: Text(value, style: const TextStyle(fontFamily: 'monospace')),
),
],
);
}
Widget _buildTypeChip(String label, IconData icon, Color color) {
return Chip(
avatar: Icon(icon, size: 16, color: color),
label: Text(label),
backgroundColor: color.withValues(alpha: 0.1),
labelStyle: TextStyle(
color: Color.lerp(color, Colors.black, 0.3),
fontWeight: FontWeight.bold,
),
);
}
}