system_asset_picker
A modern Flutter plugin that leverages Android's native Photo Picker UI to select images and videos without requiring storage permissions. This plugin provides a clean, system-native experience that complies with Play Store guidelines while offering powerful media selection capabilities.
🎬 Demo

🌟 Features
- ✅ No Storage Permissions Required - Uses Android's built-in Photo Picker (Android 11+) and scoped storage
- 🎨 Native Photo Picker UI - Beautiful, system-native gallery interface
- 📸 Single & Multiple Image Selection - Pick one or many images with customizable limits
- 🎥 Video Selection with Size Limits - Pick videos with configurable size restrictions
- 🔄 Combined Media Selection - Select both images and videos together
- 📷 Camera Support - Direct camera access for capturing new photos/videos
- 🚀 Play Store Compliant - No broad storage permissions needed
- ⚡ Performant - Efficient handling of large media files
🎯 Why This Package?
Popular packages like image_picker, file_picker and some other packages have limitations:
- They often require
READ_MEDIA_IMAGESandREAD_MEDIA_VIDEOpermissions - Play Store may reject apps using these permissions without "broad usage" justification
- They don't provide the modern, native Photo Picker UI
- Limited control over video size restrictions
system_asset_picker solves all these issues while providing a superior user experience.
📋 Requirements
- Minimum SDK: Android API 21 (Android 5.0)
- Recommended: Android API 30+ (Android 11+) for full Photo Picker support
- Flutter: 2.5.0 or higher
🚀 Installation
Add this to your pubspec.yaml:
dependencies:
system_asset_picker: ^1.0.0
Then run:
flutter pub get
📱 Platform Setup
Android
Update your android/app/build.gradle:
android {
compileSdkVersion 34 // or higher
defaultConfig {
minSdkVersion 21
targetSdkVersion 34
}
}
No permissions required in AndroidManifest.xml! 🎉
The plugin automatically handles scoped storage and Photo Picker access.
💻 Usage
Import the Package
import 'package:system_asset_picker/system_asset_picker.dart';
Check Photo Picker Availability
bool isAvailable = await
SystemAssetPicker.isPhotoPickerAvailable
();if
(
isAvailable) {
print('Photo Picker is available on this device');
}
Pick a Single Image
// From gallery
XFile? image = await
SystemAssetPicker.pickImage
();
// From camera
XFile? image = await
SystemAssetPicker.pickImage
(
source: ImageSource.camera
);
if (image != null) {
print('Selected image: ${image.path}');
}
Pick Multiple Images
List<String> imagePaths = await
SystemAssetPicker.pickMultipleImages
(
maxItems: 10, // Maximum number of images
);
print('Selected ${imagePaths
.
length
}
images
'
);
Pick a Single Video
// From gallery
XFile? video = await
SystemAssetPicker.pickVideo
();
// From camera
XFile? video = await
SystemAssetPicker.pickVideo
(
source: ImageSource.camera
);
if (video != null) {
print('Selected video: ${video.path}');
}
Pick Multiple Videos with Size Limit
List<String> videoPaths = await
SystemAssetPicker.pickMultipleVideos
(
maxItems: 5, // Maximum number of videos
maxVideoSizeMB: 50, // Maximum size per video in MB
);
print('Selected ${videoPaths.length} videos');
Pick Images and Videos Together
List<String> mediaPaths = await
SystemAssetPicker.pickImagesAndVideos
(
maxItems: 10, // Maximum total items
maxVideoSizeMB: 100, // Maximum size per video in MB
);
// Process mixed media
for (String path in mediaPaths) {
if (path.toLowerCase().endsWith('.mp4') ||
path.toLowerCase().endsWith('.mov')) {
print('Video: $path');
} else {
print('Image: $path');
}
}
📖 Complete Example
import 'package:flutter/material.dart';
import 'package:system_asset_picker/system_asset_picker.dart';
import 'dart:io';
class MediaPickerScreen extends StatefulWidget {
@override
_MediaPickerScreenState createState() => _MediaPickerScreenState();
}
class _MediaPickerScreenState extends State<MediaPickerScreen> {
List<String> _selectedMedia = [];
Future<void> _pickMedia() async {
try {
final paths = await SystemAssetPicker.pickImagesAndVideos(
maxItems: 10,
maxVideoSizeMB: 50,
);
setState(() {
_selectedMedia = paths;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Selected ${paths.length} items')),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: $e')),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Media Picker')),
body: Column(
children: [
ElevatedButton(
onPressed: _pickMedia,
child: Text('Pick Images & Videos'),
),
Expanded(
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 4,
mainAxisSpacing: 4,
),
itemCount: _selectedMedia.length,
itemBuilder: (context, index) {
return Image.file(
File(_selectedMedia[index]),
fit: BoxFit.cover,
);
},
),
),
],
),
);
}
}
🎨 API Reference
SystemAssetPicker
| Method | Parameters | Return Type | Description |
|---|---|---|---|
pickImage() |
source (optional) |
Future<XFile?> |
Pick a single image from gallery or camera |
pickVideo() |
source (optional) |
Future<XFile?> |
Pick a single video from gallery or camera |
pickMultipleImages() |
maxItems (required) |
Future<List<String>> |
Pick multiple images with limit |
pickMultipleVideos() |
maxItems, maxVideoSizeMB |
Future<List<String>> |
Pick multiple videos with size limit |
pickImagesAndVideos() |
maxItems, maxVideoSizeMB |
Future<List<String>> |
Pick mixed media with limits |
isPhotoPickerAvailable() |
None | Future<bool> |
Check if Photo Picker is available |
Parameters
- maxItems: Maximum number of items that can be selected
- maxVideoSizeMB: Maximum size per video in megabytes (default: 100MB)
- source:
ImageSource.galleryorImageSource.camera(default: gallery)
🔒 Privacy & Permissions
This plugin is designed with privacy in mind:
- ✅ No
READ_EXTERNAL_STORAGEpermission needed - ✅ No
READ_MEDIA_IMAGESpermission needed - ✅ No
READ_MEDIA_VIDEOpermission needed - ✅ Uses Android's scoped storage and Photo Picker APIs
- ✅ Fully compliant with Google Play Store policies
The plugin only accesses files that the user explicitly selects through the system UI.
📊 Supported Android Versions
| Android Version | API Level | Photo Picker | Functionality |
|---|---|---|---|
| Android 13+ | 33+ | Native | Full native Photo Picker with all features |
| Android 11-12 | 30-32 | Fallback | Uses ACTION_GET_CONTENT with file type filters |
| Android 5-10 | 21-29 | Fallback | Basic file picker with MIME type filtering |
⚠️ Limitations
- Photo Picker UI is only available on Android 11+ (API 30+)
- On older Android versions, a basic file picker is used
- Videos exceeding the size limit will be filtered out with a toast notification
- Camera functionality requires camera hardware on the device
🐛 Troubleshooting
Photo Picker Not Showing
Problem: Photo Picker doesn't appear on device
Solution: Ensure your device is running Android 11+ (API 30+). Check availability:
bool available = await
SystemAssetPicker.isPhotoPickerAvailable
();
Video Size Limit Not Working
Problem: Large videos are not being filtered
Solution: Ensure you're passing maxVideoSizeMB parameter:
await
SystemAssetPicker.pickMultipleVideos
(
maxItems
:
5
,
maxVideoSizeMB
:
50
, // Add this parameter
);
Images Not Displaying
Problem: Selected images show error icon
Solution: Verify file paths are accessible and files exist:
for (String path in paths) {
final file = File(path);
if (await file.exists()) {
print('File exists: $path');
}
}
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
💬 Support
If you find this package helpful, please:
- ⭐ Star the repository
- 🐛 Report issues on GitHub
- 💡 Suggest new features
- 📢 Share with other developers
🔗 Links
👨💻 Author
Created and maintained by Your Name
Made with ❤️ for the Flutter community