Create AI-Powered Flutter Apps
A complete, step-by-step guide to building real AI applications from scratch using Flutter, Dart, and modern ML APIs.
1. Prerequisites & Environment Setup
Before building AI apps, you need a properly configured Flutter development environment. Follow every step below — skipping any command can cause hard-to-debug issues later.
Install Flutter SDK
On macOS (Apple Silicon), clone or download the Flutter SDK:
# Clone the stable branch
git clone https://github.com/flutter/flutter.git -b stable ~/flutter
# Add Flutter to your PATH (zsh — macOS default)
echo 'export PATH="$HOME/flutter/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
# Verify installation
flutter --version
# Expected output: Flutter 3.x.x • channel stable
Install Dart
Dart ships with Flutter, but you can also install it standalone for server-side work:
brew install dart
# Verify
dart --version
# Dart SDK version: 3.x.x
Install Android Studio
Required for Android emulators and SDK tools:
brew install --cask android-studio
# Launch Android Studio and follow the setup wizard
# Install: Android SDK, SDK Platform-Tools, Android Emulator
Install VS Code
brew install --cask visual-studio-code
# Install Flutter and Dart extensions
code --install-extension Dart-Code.flutter
code --install-extension Dart-Code.dart-code
Run flutter doctor
This command checks your entire setup and tells you exactly what's missing:
flutter doctor -v
Expected output will look something like this:
| Component | Status | Action Needed |
|---|---|---|
| Flutter SDK | ✓ | None |
| Android Toolchain | ✓ | Accept licenses with flutter doctor --android-licenses |
| Xcode (iOS) | ✓ | Install Xcode from Mac App Store |
| Chrome (Web) | ✓ | Install Google Chrome |
| Android Studio | ✓ | Install from brew or website |
| VS Code | ✓ | Install Flutter extension |
Set Up Emulators / Simulators
# List available Android emulators
flutter emulators
# Create a new Android emulator
flutter emulators --create --name pixel_7
# Launch the emulator
flutter emulators --launch pixel_7
# For iOS (macOS only)
open -a Simulator
# List connected devices
flutter devices
flutter doctor --android-licenses and accept every license. Missing licenses cause build failures with no clear error message.
2. Creating Your First AI App (Step by Step)
Let's walk through every single command from an empty directory to a running AI app on your device.
Step 1: Create the Project
flutter create my_ai_app
cd my_ai_app
Step 2: Project Structure
After creation, your project looks like this:
| Path | Purpose |
|---|---|
lib/main.dart | Your app's entry point — all Dart code lives here |
lib/ | Source code directory (add more .dart files here) |
pubspec.yaml | Dependencies, assets, and project metadata |
android/ | Android-specific native code and configs |
ios/ | iOS-specific native code and configs |
test/ | Unit and widget tests |
build/ | Generated build output (never edit manually) |
assets/ | Images, models, fonts (create this folder) |
Step 3: Add Your First AI Package
flutter pub add google_generative_ai
Step 4: Write the Code
import 'package:flutter/material.dart';
import 'package:google_generative_ai/google_generative_ai.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My AI App',
home: const HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
String _response = 'Tap the button to ask AI anything.';
bool _loading = false;
Future<void> _askAI() async {
setState(() => _loading = true);
final model = GenerativeModel(
model: 'gemini-1.5-flash',
apiKey: 'YOUR_API_KEY',
);
final response = await model.generateContent([
Content.text('Say hello in exactly 5 words.'),
]);
setState(() {
_response = response.text ?? 'No response.';
_loading = false;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('My AI App')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(_response, textAlign: TextAlign.center),
const SizedBox(height: 20),
ElevatedButton(
onPressed: _loading ? null : _askAI,
child: Text(_loading ? 'Thinking...' : 'Ask AI'),
),
],
),
),
);
}
}
Step 5: Run the App
# List connected devices
flutter devices
# Run on a specific device
flutter run -d macOS
flutter run -d chrome
flutter run -d <device-id>
# Hot reload is automatic — edit lib/main.dart and save
r) injects code changes without losing state. Hot Restart (press R) rebuilds the entire widget tree from scratch. Use reload for UI tweaks, restart for logic changes.
3. AI Chat App with Gemini API
Build a full conversational AI chat app with streaming responses using Google's Gemini API.
Create the Project
flutter create ai_chat_app
cd ai_chat_app
flutter pub add google_generative_ai
Dependencies
dependencies:
flutter:
sdk: flutter
google_generative_ai: ^0.4.3
Gemini Service Class
import 'dart:async';
import 'package:google_generative_ai/google_generative_ai.dart';
class GeminiChatService {
late GenerativeModel _model;
late ChatSession _chat;
final List<Content> _history = [];
GeminiChatService({required String apiKey}) {
_model = GenerativeModel(
model: 'gemini-1.5-flash',
apiKey: apiKey,
systemInstruction: Content.system(
'You are a friendly AI assistant. Reply concisely.',
),
);
_chat = _model.startChat(history: _history);
}
Future<String> sendMessage(String message) async {
final response = await _chat.sendMessage(Content.text(message));
return response.text ?? 'No response.';
}
Stream<String> sendMessageStream(String message) async* {
await for (final chunk in _chat.sendMessageStream(Content.text(message))) {
if (chunk.text != null) {
yield chunk.text!;
}
}
}
void resetChat() {
_history.clear();
_chat = _model.startChat(history: _history);
}
}
Chat UI with Streaming
import 'dart:async';
import 'package:flutter/material.dart';
import '../services/gemini_service.dart';
class ChatScreen extends StatefulWidget {
const ChatScreen({super.key});
@override
State<ChatScreen> createState() => _ChatScreenState();
}
class _ChatScreenState extends State<ChatScreen> {
late GeminiChatService _gemini;
final List<Map<String, String>> _messages = [];
final _controller = TextEditingController();
final _scrollController = ScrollController();
bool _isTyping = false;
@override
void initState() {
super.initState();
_gemini = GeminiChatService(apiKey: 'YOUR_API_KEY');
}
Future<void> _sendMessage() async {
final text = _controller.text.trim();
if (text.isEmpty) return;
setState(() {
_messages.add({'role': 'user', 'text': text});
_controller.clear();
_isTyping = true;
});
// Add empty assistant message for streaming
setState(() => _messages.add({'role': 'assistant', 'text': ''}));
await for (final chunk in _gemini.sendMessageStream(text)) {
setState(() {
_messages.last['text'] = (_messages.last['text'] ?? '') + chunk;
});
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
duration: const Duration(milliseconds: 100),
curve: Curves.easeOut,
);
}
setState(() => _isTyping = false);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('AI Chat')),
body: Column(
children: [
Expanded(
child: ListView.builder(
controller: _scrollController,
padding: const EdgeInsets.all(16),
itemCount: _messages.length,
itemBuilder: (context, index) {
final msg = _messages[index];
final isUser = msg['role'] == 'user';
return Align(
alignment: isUser
? Alignment.centerRight
: Alignment.centerLeft,
child: Container(
margin: const EdgeInsets.only(bottom: 8),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: isUser
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(12),
),
child: Text(msg['text'] ?? ''),
),
);
},
),
),
if (_isTyping)
const Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: LinearProgressIndicator(),
),
SafeArea(
child: Padding(
padding: const EdgeInsets.all(8),
child: Row(
children: [
Expanded(
child: TextField(
controller: _controller,
onSubmitted: (_) => _sendMessage(),
decoration: const InputDecoration(
hintText: 'Type a message...',
border: OutlineInputBorder(),
),
),
),
const SizedBox(width: 8),
IconButton(
onPressed: _isTyping ? null : _sendMessage,
icon: const Icon(Icons.send),
),
],
),
),
),
],
),
);
}
}
--dart-define=API_KEY=xxx at build time or route requests through a backend proxy.
4. Image Classification App with TFLite
Run TensorFlow Lite models on-device to classify images in real time — no internet required.
Create the Project
flutter create image_classifier
cd image_classifier
flutter pub add tflite_flutter image_picker image
Add Model Assets
Download a MobileNet or EfficientNet .tflite model and its labels file, then:
mkdir -p assets/model
cp ~/Downloads/mobilenet_v1.tflite assets/model/
cp ~/Downloads/labels.txt assets/model/
flutter:
assets:
- assets/model/mobilenet_v1.tflite
- assets/model/labels.txt
dependencies:
tflite_flutter: ^0.10.4
image_picker: ^1.0.7
image: ^4.1.3
Classifier Service
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:tflite_flutter/tflite_flutter.dart';
import 'package:image/image.dart' as img;
class ClassifierService {
late Interpreter _interpreter;
List<String> _labels = [];
static const int inputSize = 224;
Future<void> loadModel() async {
_interpreter = await Interpreter.fromAsset(
'assets/model/mobilenet_v1.tflite',
);
final labelData = await rootBundle.loadString('assets/model/labels.txt');
_labels = labelData.split('\n').where((l) => l.isNotEmpty).toList();
}
Future<Map<String, double>> classify(File imageFile) async {
final bytes = await imageFile.readAsBytes();
final image = img.decodeImage(bytes)!;
final resized = img.copyResize(image, width: inputSize, height: inputSize);
var input = List.generate(inputSize, (y) =>
List.generate(inputSize, (x) => [
resized.getPixel(x, y).r / 255.0,
resized.getPixel(x, y).g / 255.0,
resized.getPixel(x, y).b / 255.0,
]),
);
var output = List.filled(_labels.length, 0.0).reshape([1, _labels.length]);
_interpreter.run([input], output);
final results = <String, double>{};
for (var i = 0; i < _labels.length; i++) {
results[_labels[i]] = output[0][i];
}
return results;
}
List<MapEntry<String, double>> getTopResults(
Map<String, double> results, {int top = 5}
) {
final sorted = results.entries.toList()
..sort((a, b) => b.value.compareTo(a.value));
return sorted.take(top).toList();
}
void dispose() => _interpreter.close();
}
Camera Integration UI
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import '../services/classifier_service.dart';
class ClassifierScreen extends StatefulWidget {
const ClassifierScreen({super.key});
@override
State<ClassifierScreen> createState() => _ClassifierScreenState();
}
class _ClassifierScreenState extends State<ClassifierScreen> {
final _classifier = ClassifierService();
final _picker = ImagePicker();
File? _image;
List<MapEntry<String, double>> _results = [];
bool _loading = false;
@override
void initState() {
super.initState();
_classifier.loadModel();
}
Future<void> _classify(ImageSource source) async {
final picked = await _picker.pickImage(source: source);
if (picked == null) return;
setState(() {
_image = File(picked.path);
_loading = true;
});
final allResults = await _classifier.classify(_image!);
setState(() {
_results = _classifier.getTopResults(allResults);
_loading = false;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Image Classifier')),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton.icon(
onPressed: () => _classify(ImageSource.camera),
icon: const Icon(Icons.camera_alt),
label: const Text('Camera'),
),
ElevatedButton.icon(
onPressed: () => _classify(ImageSource.gallery),
icon: const Icon(Icons.photo_library),
label: const Text('Gallery'),
),
],
),
const SizedBox(height: 16),
if (_image != null)
ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.file(_image!, height: 200, fit: BoxFit.cover),
),
const SizedBox(height: 16),
if (_loading) const CircularProgressIndicator(),
if (!_loading && _results.isNotEmpty)
Expanded(
child: ListView.builder(
itemCount: _results.length,
itemBuilder: (context, index) {
final entry = _results[index];
return ListTile(
title: Text(entry.key),
trailing: Text(
'${(entry.value * 100).toStringAsFixed(1)}%',
),
leading: LinearProgressIndicator(
value: entry.value,
backgroundColor: Colors.grey[300],
),
);
},
),
),
],
),
),
);
}
@override
void dispose() {
_classifier.dispose();
super.dispose();
}
}
5. Text Recognition (OCR) App
Extract text from photos, documents, and handwritten notes using Google ML Kit.
Create the Project
flutter create ocr_app
cd ocr_app
flutter pub add google_mlkit_text_recognition image_picker
ML Kit Text Recognition Setup
dependencies:
flutter:
sdk: flutter
google_mlkit_text_recognition: ^0.13.0
image_picker: ^1.0.7
Android Permissions
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera" android:required="false"/>
<application ...>
</application>
</manifest>
iOS Permissions
<key>NSCameraUsageDescription</key>
<string>Camera access is needed to scan text from documents.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Photo library access is needed to pick images for text recognition.</string>
Camera/Gallery Image Picking & OCR
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:google_mlkit_text_recognition/google_mlkit_text_recognition.dart';
class OcrScreen extends StatefulWidget {
const OcrScreen({super.key});
@override
State<OcrScreen> createState() => _OcrScreenState();
}
class _OcrScreenState extends State<OcrScreen> {
final _textRecognizer = TextRecognizer(script: TextRecognitionScript.latin);
final _picker = ImagePicker();
String _extractedText = 'No text extracted yet.';
bool _isProcessing = false;
Future<void> _pickAndRecognize(ImageSource source) async {
final picked = await _picker.pickImage(source: source);
if (picked == null) return;
setState(() {
_isProcessing = true;
_extractedText = '';
});
final inputImage = InputImage.fromFilePath(picked.path);
final recognized = await _textRecognizer.processImage(inputImage);
setState(() {
_extractedText = recognized.text.isEmpty
? 'No text found in image.'
: recognized.text;
_isProcessing = false;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('OCR Scanner')),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton.icon(
onPressed: () => _pickAndRecognize(ImageSource.camera),
icon: const Icon(Icons.camera_alt),
label: const Text('Camera'),
),
ElevatedButton.icon(
onPressed: () => _pickAndRecognize(ImageSource.gallery),
icon: const Icon(Icons.photo_library),
label: const Text('Gallery'),
),
],
),
const SizedBox(height: 20),
if (_isProcessing) const CircularProgressIndicator(),
if (!_isProcessing)
Expanded(
child: SelectableText(
_extractedText,
style: const TextStyle(fontSize: 16),
),
),
],
),
),
);
}
@override
void dispose() {
_textRecognizer.close();
super.dispose();
}
}
TextRecognizer instances with TextRecognitionScript.chinese, TextRecognitionScript.japanese, or TextRecognitionScript.korean.
6. Voice Assistant App with Speech-to-Text
Build an app that listens to voice input, converts it to text, and sends it to an AI for a response.
Create the Project
flutter create voice_assistant
cd voice_assistant
flutter pub add speech_to_text google_generative_ai
Dependencies
dependencies:
flutter:
sdk: flutter
speech_to_text: ^6.6.0
google_generative_ai: ^0.4.3
Microphone Permission Setup
Add microphone permission to both platforms:
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<key>NSMicrophoneUsageDescription</key>
<string>Microphone access is needed for voice input.</string>
Speech-to-Text + AI Service
import 'dart:async';
import 'package:speech_to_text/speech_to_text.dart';
import 'package:google_generative_ai/google_generative_ai.dart';
class SpeechAiService {
final _speech = SpeechToText();
late GenerativeModel _model;
bool _isListening = false;
SpeechAiService({required String apiKey}) {
_model = GenerativeModel(model: 'gemini-1.5-flash', apiKey: apiKey);
}
Future<bool> initialize() async {
return await _speech.initialize(
onError: (error) => print('Speech error: $error'),
onStatus: (status) => print('Speech status: $status'),
);
}
void startListening({required Function(String) onResult}) {
if (_isListening) return;
_isListening = true;
_speech.listen(
onResult: (result) {
if (result.recognizedWords.isNotEmpty) {
onResult(result.recognizedWords);
}
},
listenFor: const Duration(seconds: 30),
pauseFor: const Duration(seconds: 3),
);
}
void stopListening() {
_speech.stop();
_isListening = false;
}
Future<String> getAiResponse(String userInput) async {
final response = await _model.generateContent([
Content.text('Answer concisely: $userInput'),
]);
return response.text ?? 'Sorry, no response.';
}
bool get isListening => _isListening;
}
Voice Assistant UI
import 'package:flutter/material.dart';
import '../services/speech_ai_service.dart';
class VoiceScreen extends StatefulWidget {
const VoiceScreen({super.key});
@override
State<VoiceScreen> createState() => _VoiceScreenState();
}
class _VoiceScreenState extends State<VoiceScreen> {
late SpeechAiService _service;
String _transcript = '';
String _aiResponse = '';
bool _isProcessing = false;
@override
void initState() {
super.initState();
_service = SpeechAiService(apiKey: 'YOUR_API_KEY');
_service.initialize();
}
Future<void> _toggleListening() async {
if (_service.isListening) {
_service.stopListening();
return;
}
_service.startListening(onResult: (text) async {
setState(() => _transcript = text);
if (!_service.isListening && text.isNotEmpty) {
setState(() => _isProcessing = true);
final response = await _service.getAiResponse(text);
setState(() {
_aiResponse = response;
_isProcessing = false;
});
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Voice Assistant')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
onTap: _toggleListening,
child: CircleAvatar(
radius: 50,
backgroundColor: _service.isListening
? Colors.red
: Theme.of(context).colorScheme.primary,
child: Icon(
_service.isListening ? Icons.mic_off : Icons.mic,
size: 40,
color: Colors.white,
),
),
),
const SizedBox(height: 24),
Text(_transcript, style: const TextStyle(fontSize: 18)),
const SizedBox(height: 16),
if (_isProcessing) const CircularProgressIndicator(),
if (!_isProcessing && _aiResponse.isNotEmpty)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 32),
child: Text(_aiResponse, style: const TextStyle(fontSize: 16)),
),
],
),
),
);
}
}
UIBackgroundModes key with audio value to your Info.plist. Without it, iOS will stop recording when the app goes to background.
7. Barcode & QR Scanner App
Scan QR codes, EAN-13, Code 128, and 20+ barcode formats with real-time camera preview.
Create the Project
flutter create barcode_scanner
cd barcode_scanner
flutter pub add google_mlkit_barcode_scanning camera
Dependencies
dependencies:
flutter:
sdk: flutter
google_mlkit_barcode_scanning: ^0.13.0
camera: ^0.10.5+9
Permissions
<uses-permission android:name="android.permission.CAMERA"/>
<key>NSCameraUsageDescription</key>
<string>Camera access is needed to scan barcodes and QR codes.</string>
Barcode Scanner Service
import 'dart:io';
import 'package:google_mlkit_barcode_scanning/google_mlkit_barcode_scanning.dart';
class BarcodeService {
final _scanner = BarcodeScanner(
formats: [
BarcodeFormat.qrCode,
BarcodeFormat.ean13,
BarcodeFormat.ean8,
BarcodeFormat.code128,
],
);
Future<List<Barcode>> scanFromImage(File imageFile) async {
final inputImage = InputImage.fromFile(imageFile);
return await _scanner.processImage(inputImage);
}
void dispose() => _scanner.close();
}
Real-Time Camera Scanning
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:camera/camera.dart';
import 'package:google_mlkit_barcode_scanning/google_mlkit_barcode_scanning.dart';
class ScannerScreen extends StatefulWidget {
const ScannerScreen({super.key});
@override
State<ScannerScreen> createState() => _ScannerScreenState();
}
class _ScannerScreenState extends State<ScannerScreen> {
late CameraController _cameraController;
final _barcodeScanner = BarcodeScanner();
bool _isScanning = false;
String _result = 'Point camera at a barcode';
@override
void initState() {
super.initState();
_initCamera();
}
Future<void> _initCamera() async {
final cameras = await availableCameras();
_cameraController = CameraController(
cameras.first,
ResolutionPreset.medium,
enableAudio: false,
);
await _cameraController.initialize();
_cameraController.startImageStream(_processImage);
setState(() {});
}
void _processImage(CameraImage image) async {
if (_isScanning) return;
_isScanning = true;
// Convert camera image to InputImage and scan
final inputImage = InputImage.fromCameraImage(image);
if (inputImage == null) {
_isScanning = false;
return;
}
final barcodes = await _barcodeScanner.processImage(inputImage);
if (barcodes.isNotEmpty) {
final barcode = barcodes.first;
setState(() {
_result = '${barcode.type.name}: ${barcode.rawValue}';
});
_cameraController.stopImageStream();
}
_isScanning = false;
}
@override
Widget build(BuildContext context) {
if (!_cameraController.value.isInitialized) {
return const Center(child: CircularProgressIndicator());
}
return Scaffold(
appBar: AppBar(title: const Text('Barcode Scanner')),
body: Column(
children: [
Expanded(
child: CameraPreview(_cameraController),
),
Container(
padding: const EdgeInsets.all(16),
color: Colors.black87,
width: double.infinity,
child: Text(
_result,
style: const TextStyle(color: Colors.white, fontSize: 18),
textAlign: TextAlign.center,
),
),
],
),
);
}
@override
void dispose() {
_cameraController.dispose();
_barcodeScanner.close();
super.dispose();
}
}
BarcodeScanner constructor for better performance.
8. Deploying Your AI App
Once your app is ready, you need to build release binaries and submit them to app stores.
Build Android APK
# Build a release APK (arm64-v8a)
flutter build apk --release
# Build a split APK (smaller per-device downloads)
flutter build apk --split-per-abi
# Build an app bundle (recommended for Play Store)
flutter build appbundle --release
The APK output is at build/app/outputs/flutter-apk/app-release.apk.
Build iOS IPA
# Build for iOS release
flutter build ios --release
# Then archive in Xcode for distribution
open ios/Runner.xcworkspace
Play Store Submission
- Create a developer account at play.google.com/console
- Create a new app and fill in store listing details
- Upload the
.aabfile frombuild/app/outputs/bundle/release/ - Set pricing, content rating, and target audience
- Add screenshots for phone and tablet
- Submit for review (typically 1-3 days)
App Store Submission
- Enroll in the Apple Developer Program ($99/year)
- Archive your app in Xcode (Product → Archive)
- Distribute to App Store Connect
- Fill in metadata, screenshots, and privacy policy URL
- Submit for App Review (typically 1-7 days)
Performance Optimization
| Technique | Impact | Command / Tool |
|---|---|---|
| Tree shaking | Reduces APK size 30-50% | flutter build apk --tree-shake-icons |
| Split APKs | Smaller per-device downloads | flutter build apk --split-per-abi |
| Profile mode | Identify slow frames | flutter run --profile |
| DevTools | Memory leaks, widget rebuilds | flutter pub global activate devtools |
| Deferred loading | Faster initial startup | Use deferred imports in Dart |
| Model quantization | Smaller ML models, faster inference | TensorFlow Lite converter |
--dart-define-from-file=secrets.json to inject keys at build time without committing them to source control.
9. Complete Command Reference
Every Flutter command used in this guide, organized for quick reference.
Project Commands
| Command | Description |
|---|---|
flutter create my_app | Create a new Flutter project |
flutter pub add package_name | Add a dependency |
flutter pub get | Fetch all dependencies |
flutter pub outdated | Show packages with newer versions |
flutter pub upgrade | Upgrade dependencies to latest compatible |
flutter clean | Remove build artifacts |
flutter pub cache clean | Clear the pub cache |
Build & Run Commands
| Command | Description |
|---|---|
flutter run | Run the app on connected device |
flutter run -d chrome | Run on Chrome (web) |
flutter run --release | Run in release mode |
flutter run --profile | Run in profile mode (performance testing) |
flutter build apk --release | Build release APK |
flutter build appbundle --release | Build release AAB for Play Store |
flutter build ios --release | Build release iOS |
flutter build web | Build for web deployment |
Debugging Commands
| Command | Description |
|---|---|
flutter doctor | Check development environment |
flutter doctor -v | Detailed environment check |
flutter devices | List connected devices |
flutter emulators | List available emulators |
flutter emulators --launch name | Launch an emulator |
flutter analyze | Run static analysis for errors |
flutter test | Run unit and widget tests |
flutter logs | View device logs in real time |
flutter inspect | Open DevTools inspector |
Common Troubleshooting
| Problem | Solution |
|---|---|
Flutter SDK not found | Add flutter/bin to your PATH and restart terminal |
No connected devices | Run flutter devices and check USB debugging / simulator |
Android license not accepted | Run flutter doctor --android-licenses and accept all |
Pod install failed (iOS) | Run cd ios && pod install --repo-update |
Gradle build failed | Run flutter clean && flutter pub get && flutter run |
Package version conflict | Check flutter pub outdated and update pubspec.yaml |
Hot reload not working | Ensure lib/main.dart has no compile errors; try hot restart (R) |
ML Kit build error | Check minSdkVersion is at least 21 in android/app/build.gradle |
Package Version Compatibility
Use these tested package versions together for maximum compatibility:
| Package | Min Flutter | Tested Version |
|---|---|---|
google_generative_ai | 3.16 | ^0.4.3 |
google_mlkit_text_recognition | 3.0 | ^0.13.0 |
google_mlkit_barcode_scanning | 3.0 | ^0.13.0 |
tflite_flutter | 3.0 | ^0.10.4 |
speech_to_text | 3.0 | ^6.6.0 |
image_picker | 3.0 | ^1.0.7 |
camera | 3.0 | ^0.10.5+9 |