Introduction
Integrating media capture capabilities is a common requirement in modern mobile apps. In Flutter, you can leverage the camera and image_picker packages to build custom photo and video workflows. This intermediate tutorial demonstrates how to use the Flutter camera image picker ecosystem—combining the camera plugin for live capture and image_picker for gallery selection—to streamline your app’s media features.
Setup and Permissions
Before writing code, add dependencies to your pubspec.yaml:
dependencies:
camera: ^0.10.0
image_picker: ^0.8.7
path_provider
On Android, request camera and storage permissions in android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
On iOS, edit Info.plist:
Run flutter pub get and rebuild.
Capturing Media with Camera
The camera plugin provides a CameraController to interface with device cameras. Initialize a controller, display a preview, and capture images or videos.
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
class CameraCaptureWidget extends StatefulWidget {
final CameraDescription camera;
const CameraCaptureWidget(this.camera, {Key? key}) : super(key: key);
@override
_CameraCaptureWidgetState createState() => _CameraCaptureWidgetState();
}
class _CameraCaptureWidgetState extends State<CameraCaptureWidget> {
late CameraController _controller;
late Future<void> _initFuture;
@override
void initState() {
super.initState();
_controller = CameraController(widget.camera, ResolutionPreset.high);
_initFuture = _controller.initialize();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
Future<void> _takePhoto() async {
final XFile file = await _controller.takePicture();
print('Photo saved to ${file.path}');
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: _initFuture,
builder: (_, snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return const Center(child: CircularProgressIndicator());
}
return Stack(
children: [
CameraPreview(_controller),
Align(
alignment: Alignment.bottomCenter,
child: FloatingActionButton(
onPressed: _takePhoto,
child: const Icon(Icons.camera_alt),
),
),
],
);
},
);
}
}Obtain available cameras in main.dart with availableCameras() and pass one to this widget.
Selecting Media with Image Picker
While the camera plugin handles live capture, image_picker simplifies gallery selection. It supports both photos and videos from the device’s library.
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
class GalleryPickerWidget extends StatefulWidget {
@override
_GalleryPickerWidgetState createState() => _GalleryPickerWidgetState();
}
class _GalleryPickerWidgetState extends State<GalleryPickerWidget> {
final ImagePicker _picker = ImagePicker();
XFile? _mediaFile;
Future<void> _pickMedia(ImageSource source, {bool isVideo = false}) async {
XFile? file = isVideo
? await _picker.pickVideo(source: source)
: await _picker.pickImage(source: source);
if (file != null) {
setState(() => _mediaFile = file);
print('Picked file: ${file.path}');
}
}
@override
Widget build(BuildContext context) {
return Column(
children: [
if (_mediaFile != null)
isVideo(_mediaFile!)
? Text('Video path: ${_mediaFile!.path}')
: Image.file(File(_mediaFile!.path)),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () => _pickMedia(ImageSource.gallery),
child: const Text('Pick Image'),
),
const SizedBox(width: 8),
ElevatedButton(
onPressed: () => _pickMedia(ImageSource.camera, isVideo: true),
child: const Text('Record Video'),
),
],
),
],
);
}
bool isVideo(XFile file) => file.path.endsWith('.mp4');
}This snippet showcases camera image picker Flutter integration, enabling both gallery browsing and on-the-fly recording.
Managing Streams and State
If your app requires real-time camera frames—for example, for custom filters or machine learning—you can listen to the controller’s imageStream:
_controller.startImageStream((CameraImage image) {
});Remember to stop the stream with _controller.stopImageStream() when done. Use state management solutions (Provider, Riverpod, Bloc) to share media URIs and update UI reactively.
Vibe Studio

Vibe Studio, powered by Steve’s advanced AI agents, is a revolutionary no-code, conversational platform that empowers users to quickly and efficiently create full-stack Flutter applications integrated seamlessly with Firebase backend services. Ideal for solo founders, startups, and agile engineering teams, Vibe Studio allows users to visually manage and deploy Flutter apps, greatly accelerating the development process. The intuitive conversational interface simplifies complex development tasks, making app creation accessible even for non-coders.
Conclusion
Combining the Flutter camera and image_picker packages gives you full control over media capture and selection. You can craft seamless experiences: from live camera feeds and custom frame processing to picking images and videos within a unified workflow. Always manage permissions and resource cleanup diligently to avoid memory leaks or crashes.