20 āļāļģāļāļēāļĄāļŠāļąāļĄāļ āļēāļĐāļāđāļāļēāļ Flutter āļāļĩāđāļāļāļāđāļāļĒāļāļĩāđāļŠāļļāļāļŠāļģāļŦāļĢāļąāļāļāļąāļāļāļąāļāļāļēāđāļāļāļĄāļ·āļāļāļ·āļ
āđāļāļĢāļĩāļĒāļĄāļāļąāļ§āļŠāļąāļĄāļ āļēāļĐāļāđāļāļēāļ Flutter āļāđāļ§āļĒāļāļģāļāļēāļĄ 20 āļāđāļāļāļĩāđāļāļđāļāļāļēāļĄāļāđāļāļĒāļāļĩāđāļŠāļļāļ āļāļĢāļāļāļāļĨāļļāļĄ Widget, State Management, Dart, āļŠāļāļēāļāļąāļāļĒāļāļĢāļĢāļĄ āđāļĨāļ°āđāļāļ§āļāļēāļāļāļāļīāļāļąāļāļīāļāļĩāđāļāļĩāļāļĩāđāļŠāļļāļ āļāļĢāđāļāļĄāļāļģāļāļāļīāļāļēāļĒāļāļĒāđāļēāļāļĨāļ°āđāļāļĩāļĒāļāđāļĨāļ°āļāļąāļ§āļāļĒāđāļēāļāđāļāđāļ

āļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļāđāļāļēāļ Flutter āļāļ°āļāļĢāļ°āđāļĄāļīāļāļāļ§āļēāļĄāđāļāļĩāđāļĒāļ§āļāļēāļāđāļ Framework, āļ āļēāļĐāļē Dart āđāļĨāļ°āļĢāļđāļāđāļāļāļŠāļāļēāļāļąāļāļĒāļāļĢāļĢāļĄāđāļāļāļĄāļ·āļāļāļ·āļ āļāļāļāļ§āļēāļĄāļāļĩāđāļĢāļ§āļāļĢāļ§āļĄ 20 āļāļģāļāļēāļĄāļāļĩāđāļāļđāļāļāļēāļĄāļāđāļāļĒāļāļĩāđāļŠāļļāļ āļāļąāđāļāđāļāđāļāļ·āđāļāļāļēāļāđāļāļāļāļāļķāļāđāļāļ§āļāļīāļāļāļąāđāļāļŠāļđāļ āļāļĢāđāļāļĄāļāļģāļāļāļāļāļĒāđāļēāļāļĨāļ°āđāļāļĩāļĒāļāđāļĨāļ°āļāļąāļ§āļāļĒāđāļēāļāđāļāđāļāļāļĩāđāđāļāđāļāļēāļāđāļāđāļāļĢāļīāļ
āļāļđāđāļŠāļąāļĄāļ āļēāļĐāļāđāļāļ°āđāļŦāđāļāļ°āđāļāļāļŠāļđāļāļāļąāļāļāļđāđāļŠāļĄāļąāļāļĢāļāļĩāđāļŠāļēāļĄāļēāļĢāļāļāļāļīāļāļēāļĒ "āđāļŦāļāļļāļāļĨ" āļāļ§āļāļāļđāđāļāļąāļ "āļ§āļīāļāļĩāļāļēāļĢ" āđāļāđ āļŠāļģāļŦāļĢāļąāļāđāļāđāļĨāļ°āđāļāļ§āļāļīāļ āļāļēāļĢāđāļāđāļēāđāļāļāļĢāļāļĩāļāļēāļĢāđāļāđāļāļēāļāđāļĨāļ°āļāđāļāđāļĨāļāđāļāļĨāļĩāđāļĒāļāļāļēāļāđāļāļāļāļīāļāļāļ°āđāļāđāļāļāļąāļ§āļāļąāļāļŠāļīāļāļāļĩāđāļŠāļģāļāļąāļ
āļāļģāļāļēāļĄāļāļ·āđāļāļāļēāļ Flutter āđāļĨāļ° Dart
1. StatelessWidget āđāļĨāļ° StatefulWidget āđāļāļāļāđāļēāļāļāļąāļāļāļĒāđāļēāļāđāļĢ?
StatelessWidget āđāļāđāļ Widget āļāļĩāđāđāļĄāđāļŠāļēāļĄāļēāļĢāļāđāļāļĨāļĩāđāļĒāļāđāļāļĨāļāđāļāđ (immutable) āļāļķāđāļāļĢāļđāļāļĨāļąāļāļĐāļāđāļāļķāđāļāļāļĒāļđāđāļāļąāļāļāđāļēāđāļĢāļīāđāļĄāļāđāļāļāļĩāđāļāļģāļŦāļāļāđāļāđāļēāļāļąāđāļ āđāļĄāļ·āđāļāļŠāļĢāđāļēāļāđāļĨāđāļ§āļāļ°āđāļĄāđāļĄāļĩāļāļēāļĢāđāļāļĨāļĩāđāļĒāļāđāļāļĨāļāđāļ āđ āļŠāđāļ§āļ StatefulWidget āļāļ°āđāļāđāļ State āļāļĩāđāļŠāļēāļĄāļēāļĢāļāđāļāļĨāļĩāđāļĒāļāđāļāļĨāļāđāļāđāļāļēāļĄāđāļ§āļĨāļē āđāļĨāļ°āļāļģāđāļŦāđ Widget āļāļđāļ Rebuild āđāļŦāļĄāđ
// StatelessWidget: static display, no change after construction
class WelcomeMessage extends StatelessWidget {
// Final parameter - never changes
final String username;
const WelcomeMessage({super.key, required this.username});
Widget build(BuildContext context) {
// Build called once (unless parent rebuilds)
return Text('Welcome, $username');
}
}// StatefulWidget: mutable state, can rebuild itself
class LikeButton extends StatefulWidget {
const LikeButton({super.key});
State<LikeButton> createState() => _LikeButtonState();
}
class _LikeButtonState extends State<LikeButton> {
// Mutable local state
int _likeCount = 0;
void _incrementLike() {
// setState triggers rebuild with new state
setState(() {
_likeCount++;
});
}
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: _incrementLike,
child: Text('Likes: $_likeCount'),
);
}
}āļŦāļĨāļąāļāļāļēāļĢāļāļ·āļ āđāļŦāđāđāļāđ StatelessWidget āđāļāđāļāļāđāļēāđāļĢāļīāđāļĄāļāđāļ āđāļĨāļ°āđāļāđ StatefulWidget āđāļāļāļēāļ°āđāļĄāļ·āđāļāļāļģāđāļāđāļāļāđāļāļāļāļąāļāļāļēāļĢ State āļ āļēāļĒāđāļ Widget āđāļāđāļēāļāļąāđāļ
2. Widget Tree āđāļ Flutter āļāļģāļāļēāļāļāļĒāđāļēāļāđāļĢ?
Flutter āļāļąāļāļĢāļ°āđāļāļĩāļĒāļ Interface āđāļāļĒāđāļāđāļāđāļāđāļ 3 Tree āļāļĩāđāđāļāļ·āđāļāļĄāđāļĒāļāļāļąāļ āđāļāđāđāļāđ Widget Tree (āļāļēāļĢāļāļĢāļ°āļāļēāļĻāđāļāļ immutable), Element Tree (Lifecycle āđāļĨāļ° Binding) āđāļĨāļ° Render Tree (Layout āđāļĨāļ° Painting)
// Declarative structure - widgets describe the UI
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
// Each widget creates an Element in the Element Tree
return MaterialApp(
home: Scaffold(
// Scaffold creates multiple RenderObjects
body: Center(
// Center modifies its child's layout
child: Column(
children: [
// Each Text has its own RenderParagraph
Text('First'),
Text('Second'),
],
),
),
),
);
}
}āđāļĄāļ·āđāļāļĄāļĩāļāļēāļĢāđāļĢāļĩāļĒāļ setState Flutter āļāļ°āđāļāļĢāļĩāļĒāļāđāļāļĩāļĒāļ Widget Tree āđāļāđāļēāđāļĨāļ°āđāļŦāļĄāđāđāļāļ·āđāļ Rebuild āđāļāļāļēāļ° Element āļāļĩāđāļĄāļĩāļāļēāļĢāđāļāļĨāļĩāđāļĒāļāđāļāļĨāļ āļāļĢāļ°āļāļ§āļāļāļēāļĢ Differentiation āļāļĩāđāļāļēāļĻāļąāļĒ Key āđāļĨāļ°āļāļĢāļ°āđāļ āļāļāļāļ Widget
3. Const Constructor āļāļ·āļāļāļ°āđāļĢ āđāļĨāļ°āļāļģāđāļĄāļāđāļāļāđāļāđ?
Const Constructor āļŠāļĢāđāļēāļ Widget āđāļāļāļąāđāļāļāļāļ Compile Time āđāļāļāļāļĩāđāļāļ°āđāļāđāļ Runtime āļāļģāđāļŦāđ Flutter āļŠāļēāļĄāļēāļĢāļāļāļģ Instance āđāļāļīāļĄāļāļĨāļąāļāļĄāļēāđāļāđāļāđāļģāđāļāđ āļāļķāđāļāļāđāļ§āļĒāđāļāļīāđāļĄāļāļĢāļ°āļŠāļīāļāļāļīāļ āļēāļāđāļāļĒāļŦāļĨāļĩāļāđāļĨāļĩāđāļĒāļāļāļēāļĢ Rebuild āļāļĩāđāđāļĄāđāļāļģāđāļāđāļ
class OptimizedScreen extends StatelessWidget {
const OptimizedScreen({super.key});
Widget build(BuildContext context) {
return Column(
children: [
// â
const: same instance reused on each build
const Icon(Icons.star, size: 48),
const SizedBox(height: 16),
const Text('Static title'),
// â Non-const: new instance on each build
Icon(Icons.star, color: Theme.of(context).primaryColor),
],
);
}
}
// Custom widget with const constructor
class StaticCard extends StatelessWidget {
final String title;
// All fields must be final for const
const StaticCard({super.key, required this.title});
Widget build(BuildContext context) {
return Card(child: Text(title));
}
}Flutter Analyzer āļāļ°āđāļāđāļāđāļāļ·āļāļāđāļĄāļ·āđāļāļĄāļĩāđāļāļāļēāļŠāđāļāđ const āđāļāđāđāļĄāđāđāļāđāđāļāđāļāđāļēāļ lint rule prefer_const_constructors
4. āļāļāļīāļāļēāļĒāļāļĢāļ°āđāļ āļāļāđāļēāļ āđ āļāļāļ Key āđāļ Flutter
Key āļāļģāļŦāļāđāļēāļāļĩāđāļĢāļąāļāļĐāļē State āļāļāļ Widget āđāļĄāļ·āđāļāļĄāļĩāļāļēāļĢāļāļąāļāđāļĢāļĩāļĒāļāđāļŦāļĄāđ āļŦāļēāļāđāļĄāđāļĄāļĩ Key Flutter āļāļ°āļāļēāļĻāļąāļĒāļāļģāđāļŦāļāđāļāđāļ Tree āļāļķāđāļāļāļēāļāļāļģāđāļŦāđāđāļāļīāļ Bug āđāļĄāļ·āđāļāļĄāļĩāļāļēāļĢāđāļāļĨāļĩāđāļĒāļāļĨāļģāļāļąāļāļāļāļāļĢāļēāļĒāļāļēāļĢ
class TodoList extends StatelessWidget {
final List<Todo> todos;
const TodoList({super.key, required this.todos});
Widget build(BuildContext context) {
return ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
final todo = todos[index];
// â
ValueKey: preserves state if order changes
return TodoTile(
key: ValueKey(todo.id),
todo: todo,
);
},
);
}
}
// Different key types for different contexts
class KeyExamples extends StatelessWidget {
Widget build(BuildContext context) {
return Column(
children: [
// ValueKey: based on a unique value
Container(key: ValueKey('unique-id')),
// ObjectKey: based on object identity
Container(key: ObjectKey(myObject)),
// UniqueKey: new key on each build
Container(key: UniqueKey()),
// GlobalKey: access state from outside
Form(key: _formKey),
],
);
}
}GlobalKey āļĒāļąāļāļāđāļ§āļĒāđāļŦāđāļŠāļēāļĄāļēāļĢāļāđāļāđāļēāļāļķāļ State āļāļāļ Widget āļāļēāļāļ āļēāļĒāļāļāļāđāļāđ āđāļāđāļāļ§āļĢāđāļāđāļāļĒāđāļēāļāļĢāļ°āļĄāļąāļāļĢāļ°āļ§āļąāļ
āļāļģāļāļēāļĄāđāļāļĩāđāļĒāļ§āļāļąāļ Dart
5. final āđāļĨāļ° const āđāļ Dart āļāđāļēāļāļāļąāļāļāļĒāđāļēāļāđāļĢ?
final āļāļģāļŦāļāļāļāļąāļ§āđāļāļĢāļāļĩāđāļŠāļēāļĄāļēāļĢāļāļāļģāļŦāļāļāļāđāļēāđāļāđāđāļāļĩāļĒāļāļāļĢāļąāđāļāđāļāļĩāļĒāļ§ āđāļāļĒāļāļĢāļ°āđāļĄāļīāļāļāđāļēāđāļāļāļāļ° Runtime āļŠāđāļ§āļ const āļŠāļĢāđāļēāļāļāđāļēāļāļāļāļĩāđāđāļāļāļąāđāļāļāļāļ Compile Time āļāļķāđāļāđāļāđāļ Immutable āđāļĨāļ°āļāļđāļāļāļĢāļ°āđāļĄāļīāļāļāđāļēāļāđāļāļāļāļēāļĢāļĢāļąāļ
class DateExample {
// final: value assigned at runtime
final DateTime createdAt = DateTime.now();
// const: value known at compile time
static const int maxItems = 100;
static const String appName = 'MyApp';
// â Error: DateTime.now() not const (runtime value)
// static const DateTime timestamp = DateTime.now();
}
void demonstrateDifference() {
// final: each call can have different value
final timestamp1 = DateTime.now();
final timestamp2 = DateTime.now();
print(timestamp1 == timestamp2); // false (different)
// const: same instance reused
const list1 = [1, 2, 3];
const list2 = [1, 2, 3];
print(identical(list1, list2)); // true (same instance)
}āđāļ Flutter āļāļ§āļĢāđāļāđ const āļŠāļģāļŦāļĢāļąāļ Widget āļāļĩāđāđāļāđāļ Static āđāļĨāļ°āđāļāđ final āļŠāļģāļŦāļĢāļąāļāļāđāļēāļāļĩāđāļāđāļāļāļāļģāļāļ§āļ
6. Future āđāļĨāļ° async/await āļāļģāļāļēāļāļāļĒāđāļēāļāđāļĢ?
Future āđāļāļāļāđāļēāļāļĩāđāļāļ°āļāļĢāđāļāļĄāđāļāđāļāļēāļāđāļāļ āļēāļĒāļŦāļĨāļąāļ āļŠāđāļ§āļ async/await āļāļģāđāļŦāđāđāļ§āļĒāļēāļāļĢāļāđāļāđāļēāļāļāđāļēāļĒāļāļķāđāļāđāļāļāļēāļĢāļāļąāļāļāļēāļĢāļāļąāļ Asynchronous Operation āđāļāļĒāđāļĄāđāļāđāļāļāļāđāļāļ Callback
class UserRepository {
final ApiClient _client;
UserRepository(this._client);
// Future: promise of a future value
Future<User> fetchUser(String id) async {
try {
// await suspends execution until resolution
final response = await _client.get('/users/$id');
return User.fromJson(response);
} catch (e) {
// Errors propagate normally with async/await
throw UserNotFoundException(id);
}
}
// Parallel execution with Future.wait
Future<List<User>> fetchUsers(List<String> ids) async {
// All requests start simultaneously
final futures = ids.map((id) => fetchUser(id));
// Wait for all to complete
return Future.wait(futures);
}
// Sequential processing
Future<void> processSequentially(List<String> ids) async {
for (final id in ids) {
// Each request waits for the previous one
await fetchUser(id);
}
}
}āđāļāđ Future.wait āļŠāļģāļŦāļĢāļąāļāļāļēāļĢāļāļĢāļ°āļĄāļ§āļĨāļāļĨāđāļāļāļāļāļēāļ āđāļĨāļ°āđāļāđ async loop āļŠāļģāļŦāļĢāļąāļāļāļēāļĢāļāļĢāļ°āļĄāļ§āļĨāļāļĨāļāļēāļĄāļĨāļģāļāļąāļ
FutureBuilder āđāļŦāļĄāļēāļ°āļŠāļģāļŦāļĢāļąāļāļāļĢāļāļĩāļāļĩāđāđāļĄāđāļāļąāļāļāđāļāļ āđāļāđ Riverpod (AsyncValue) āđāļŦāđāļāļ§āļēāļĄāļŠāļēāļĄāļēāļĢāļāđāļāļāļēāļĢāļāļąāļāļāļēāļĢ Cache, Error Handling āđāļĨāļ° Refresh āļāļĩāđāļāļĩāļāļ§āđāļēāļŠāļģāļŦāļĢāļąāļāđāļāļāļāļĨāļīāđāļāļāļąāļāļāļĩāđāļĄāļĩāļāļ§āļēāļĄāļāļąāļāļāđāļāļāļŠāļđāļ
7. āļāļāļīāļāļēāļĒāđāļĢāļ·āđāļāļ Stream āđāļĨāļ°āļāļēāļĢāđāļāđāļāļēāļ
Stream āđāļāļāļĨāļģāļāļąāļāļāđāļēāđāļāļ Asynchronous āļāļķāđāļāđāļŦāļĄāļēāļ°āļŠāļģāļŦāļĢāļąāļ Event āđāļāļ Real-time āđāļāđāļ WebSocket, āļāđāļāļĄāļđāļĨāđāļāđāļāđāļāļāļĢāđ āļŦāļĢāļ·āļāļāļēāļĢāđāļāđāļāļāļāļāļāļāļāļđāđāđāļāđ
class MessageService {
// StreamController manages creation and broadcasting
final _messageController = StreamController<Message>.broadcast();
// Expose only the Stream (not the Sink)
Stream<Message> get messages => _messageController.stream;
void addMessage(Message message) {
_messageController.sink.add(message);
}
void dispose() {
_messageController.close();
}
}
// Usage with StreamBuilder
class MessageList extends StatelessWidget {
final MessageService service;
const MessageList({super.key, required this.service});
Widget build(BuildContext context) {
return StreamBuilder<Message>(
stream: service.messages,
builder: (context, snapshot) {
// Handle all possible states
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
}
if (!snapshot.hasData) {
return const Text('No messages');
}
return MessageCard(message: snapshot.data!);
},
);
}
}Stream āđāļāļ .broadcast() āļāļāļļāļāļēāļāđāļŦāđāļĄāļĩ Listener āļŦāļĨāļēāļĒāļāļąāļ§ āļāđāļēāļāļāļēāļ Single-subscription Stream āļāļĩāđāļĢāļąāļ Listener āđāļāđāđāļāļĩāļĒāļāļāļąāļ§āđāļāļĩāļĒāļ§
āļāļĢāđāļāļĄāļāļĩāđāļāļ°āļāļīāļāļīāļāļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļāđ Flutter āđāļĨāđāļ§āļŦāļĢāļ·āļāļĒāļąāļāļāļĢāļąāļ?
āļāļķāļāļāļāļāđāļ§āļĒāļāļąāļ§āļāļģāļĨāļāļāđāļāļāđāļāđāļāļāļ, flashcards āđāļĨāļ°āđāļāļāļāļāļŠāļāļāđāļāļāļāļīāļāļāļĢāļąāļ
āļāļģāļāļēāļĄāđāļāļĩāđāļĒāļ§āļāļąāļāļŠāļāļēāļāļąāļāļĒāļāļĢāļĢāļĄāđāļĨāļ° State Management
8. āđāļāļĢāļĩāļĒāļāđāļāļĩāļĒāļ State Management: Provider, Riverpod āđāļĨāļ° Bloc
āđāļāđāļĨāļ°āđāļāļĨāļđāļāļąāļāļāļāļāđāļāļāļĒāđāļāļ§āļēāļĄāļāđāļāļāļāļēāļĢāļāļĩāđāđāļāļāļāđāļēāļāļāļąāļ Provider āđāļāđāļāļāļ§āļēāļĄāđāļĢāļĩāļĒāļāļāđāļēāļĒāđāļĨāļ°āļĢāļāļāļĢāļąāļ Native Integration āļŠāđāļ§āļ Riverpod āļĄāļēāļāļĢāđāļāļĄ Type Safety āđāļĨāļ°āļāļ§āļēāļĄāļŠāļēāļĄāļēāļĢāļāđāļāļāļēāļĢāļāļāļŠāļāļ āļāļāļ°āļāļĩāđ Bloc āļāļąāļāļāļąāļāđāļāđāļŠāļāļēāļāļąāļāļĒāļāļĢāļĢāļĄāđāļāļ Event-driven āļāļĒāđāļēāļāđāļāđāļĄāļāļ§āļ
// Riverpod: declarative and type-safe approach
final userProvider = FutureProvider.autoDispose<User>((ref) async {
final repository = ref.watch(userRepositoryProvider);
return repository.fetchCurrentUser();
});
class UserProfile extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
// AsyncValue handles loading/error/data
final userAsync = ref.watch(userProvider);
return userAsync.when(
loading: () => const CircularProgressIndicator(),
error: (error, stack) => Text('Error: $error'),
data: (user) => Text(user.displayName),
);
}
}// Bloc: explicit events/states separation
abstract class AuthEvent {}
class LoginRequested extends AuthEvent {
final String email;
final String password;
LoginRequested(this.email, this.password);
}
abstract class AuthState {}
class AuthInitial extends AuthState {}
class AuthLoading extends AuthState {}
class AuthSuccess extends AuthState {
final User user;
AuthSuccess(this.user);
}
class AuthFailure extends AuthState {
final String error;
AuthFailure(this.error);
}
class AuthBloc extends Bloc<AuthEvent, AuthState> {
AuthBloc() : super(AuthInitial()) {
on<LoginRequested>(_onLoginRequested);
}
Future<void> _onLoginRequested(
LoginRequested event,
Emitter<AuthState> emit,
) async {
emit(AuthLoading());
try {
final user = await _repository.login(event.email, event.password);
emit(AuthSuccess(user));
} catch (e) {
emit(AuthFailure(e.toString()));
}
}
}Riverpod āđāļāđāļāļāļąāļ§āđāļĨāļ·āļāļāļāļĩāđāđāļāļ°āļāļģāļŠāļģāļŦāļĢāļąāļāđāļāļĢāđāļāļāļāđāđāļŦāļĄāđ āđāļāļ·āđāļāļāļāļēāļ API āļāļĩāđāļāļąāļāļŠāļĄāļąāļĒāđāļĨāļ°āļāļ§āļēāļĄāļāđāļēāļĒāđāļāļāļēāļĢāļāļāļŠāļāļ
9. Clean Architecture āđāļ Flutter āļāļ·āļāļāļ°āđāļĢ?
Clean Architecture āđāļāđāļāđāļāđāļāļāļāļāđāļāđāļ Layer āļāļĩāđāđāļāđāļāļāļīāļŠāļĢāļ°āļāļēāļāļāļąāļ āđāļāđāđāļāđ Domain (Business Logic), Data (āđāļŦāļĨāđāļāļāđāļāļĄāļđāļĨ) āđāļĨāļ° Presentation (UI) āļāļēāļĢāđāļāđāļāđāļĒāļāļāļĩāđāļāđāļ§āļĒāđāļŦāđāļāļēāļĢāļāļāļŠāļāļāđāļĨāļ°āļāļēāļĢāļāļđāđāļĨāļĢāļąāļāļĐāļēāļāļģāđāļāđāļāđāļēāļĒāļāļķāđāļ
// Entity: pure business object, no framework dependency
class User {
final String id;
final String email;
final String name;
const User({
required this.id,
required this.email,
required this.name,
});
}
// domain/repositories/user_repository.dart
// Interface: abstract contract, implementation in Data
abstract class UserRepository {
Future<User> getUser(String id);
Future<void> updateUser(User user);
}
// domain/usecases/get_user_usecase.dart
// Use case: isolated business logic
class GetUserUseCase {
final UserRepository _repository;
GetUserUseCase(this._repository);
Future<User> call(String userId) {
return _repository.getUser(userId);
}
}// Concrete implementation with data sources
class UserRepositoryImpl implements UserRepository {
final UserRemoteDataSource _remoteDataSource;
final UserLocalDataSource _localDataSource;
UserRepositoryImpl(this._remoteDataSource, this._localDataSource);
Future<User> getUser(String id) async {
try {
// Try local cache first
final cachedUser = await _localDataSource.getUser(id);
if (cachedUser != null) return cachedUser;
} catch (_) {}
// Fallback to API
final user = await _remoteDataSource.fetchUser(id);
await _localDataSource.cacheUser(user);
return user;
}
}Domain Layer āđāļĄāđāļāļķāđāļāļāļē Layer āļāļ·āđāļ, Data Layer āļāļķāđāļāļāļē Domain āđāļĨāļ° Presentation Layer āļāļķāđāļāļāļēāļāļąāđāļāļŠāļāļ
10. āļāļēāļĢāļāļģ Dependency Injection āļāļģāļāļĒāđāļēāļāđāļĢ?
Dependency Injection āđāļĒāļ Component āļāļāļāļāļēāļāļāļąāļāđāļāļĒāļāļēāļĢāļŠāđāļ Dependency āļāļēāļāļ āļēāļĒāļāļāļ Riverpod āļāļģāđāļĢāļ·āđāļāļāļāļĩāđāđāļāđāļāļĒāđāļēāļāļĒāļāļāđāļĒāļĩāđāļĒāļĄāļāđāļēāļāļĢāļ°āļāļ Provider
// Provider definitions (dependencies)
final apiClientProvider = Provider<ApiClient>((ref) {
return ApiClient(baseUrl: Environment.apiUrl);
});
final userRepositoryProvider = Provider<UserRepository>((ref) {
// Automatically injects ApiClient
final client = ref.watch(apiClientProvider);
return UserRepositoryImpl(client);
});
final getUserUseCaseProvider = Provider<GetUserUseCase>((ref) {
final repository = ref.watch(userRepositoryProvider);
return GetUserUseCase(repository);
});
// Usage in a widget
class UserScreen extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
final getUserUseCase = ref.watch(getUserUseCaseProvider);
// Use the use case...
}
}
// Tests: easy dependency override
void main() {
testWidgets('displays user', (tester) async {
await tester.pumpWidget(
ProviderScope(
overrides: [
// Replace with mock for tests
userRepositoryProvider.overrideWithValue(MockUserRepository()),
],
child: const MyApp(),
),
);
});
}āļāđāļāđāļāđāđāļāļĢāļĩāļĒāļāļŦāļĨāļąāļāļāļ·āļ āļāļēāļĢāļāļāļŠāļāļāļŠāļēāļĄāļēāļĢāļāđāļāļāļāļĩāđ Dependency āđāļ āđ āļāđāļ§āļĒ Mock āđāļāđāļāļĒāđāļēāļāļāđāļēāļĒāļāļēāļĒ
āļāļģāļāļēāļĄāđāļāļĩāđāļĒāļ§āļāļąāļāļāļĢāļ°āļŠāļīāļāļāļīāļ āļēāļ
11. āļāļēāļĢāđāļāļīāđāļĄāļāļĢāļ°āļŠāļīāļāļāļīāļ āļēāļāļāļēāļĢ Rebuild āļāļģāļāļĒāđāļēāļāđāļĢ?
āļāļēāļĢāļĨāļāļāļģāļāļ§āļ Rebuild āļāļĩāđāđāļĄāđāļāļģāđāļāđāļāļāđāļ§āļĒāđāļāļīāđāļĄāļāļĢāļ°āļŠāļīāļāļāļīāļ āļēāļāļāļāļāđāļāļāđāļāđāļāļĒāđāļēāļāļĄāļēāļ āđāļāļāļāļīāļāļŦāļĨāļąāļāļāļĢāļ°āļāļāļāļāđāļ§āļĒ const Widget, āļāļēāļĢāđāļāđāļ Widget āđāļŦāđāđāļĨāđāļāļĨāļ āđāļĨāļ° Riverpod Selector
// â Bad: everything rebuilds on each change
class BadExample extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
final user = ref.watch(userProvider);
return Column(
children: [
Text(user.name),
Text(user.email),
const ExpensiveWidget(), // Rebuilds unnecessarily
],
);
}
}
// â
Good: selector to rebuild only if name changes
class GoodExample extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
// select: rebuilds only if name changes
final name = ref.watch(userProvider.select((u) => u.name));
return Text(name);
}
}
// â
Good: splitting into smaller widgets
class OptimizedScreen extends StatelessWidget {
Widget build(BuildContext context) {
return Column(
children: [
const Header(), // Static, never rebuilds
const UserNameWidget(), // Rebuilds if name changes
const UserEmailWidget(), // Rebuilds if email changes
const Footer(), // Static
],
);
}
}āđāļāđ DevTools Performance āđāļāļ·āđāļāļāļĢāļ§āļāļāļąāļ Rebuild āļāļĩāđāļĄāļēāļāđāļāļīāļāđāļ
12. āļāļēāļĢāđāļāļīāđāļĄāļāļĢāļ°āļŠāļīāļāļāļīāļ āļēāļāļĢāļēāļĒāļāļēāļĢāļĒāļēāļ§ āđ āļāļģāļāļĒāđāļēāļāđāļĢ?
āļĢāļēāļĒāļāļēāļĢāļāļĩāđāļĄāļĩāļāļģāļāļ§āļāļĄāļēāļāļāđāļāļāđāļāđ Lazy Loading āļāđāļ§āļĒ ListView.builder āļāļ§āļĢāļŦāļĨāļĩāļāđāļĨāļĩāđāļĒāļāļāļēāļĢāđāļāđ ListView āļāļĩāđāļĄāļĩ Children āđāļāļĒāļāļĢāļāđāļĄāļ·āđāļāļĄāļĩāļĢāļēāļĒāļāļēāļĢāļĄāļēāļāļāļ§āđāļē 20 āļĢāļēāļĒāļāļēāļĢ
class OptimizedList extends StatelessWidget {
final List<Item> items;
const OptimizedList({super.key, required this.items});
Widget build(BuildContext context) {
// â
ListView.builder: builds on demand
return ListView.builder(
// Fixed height improves scrolling
itemExtent: 72,
itemCount: items.length,
itemBuilder: (context, index) {
return ItemTile(
// Key to preserve state during scroll
key: ValueKey(items[index].id),
item: items[index],
);
},
);
}
}
// List widget with infinite loading
class InfiniteList extends ConsumerStatefulWidget {
ConsumerState<InfiniteList> createState() => _InfiniteListState();
}
class _InfiniteListState extends ConsumerState<InfiniteList> {
final _scrollController = ScrollController();
void initState() {
super.initState();
_scrollController.addListener(_onScroll);
}
void _onScroll() {
// Load more data near the end
if (_scrollController.position.pixels >=
_scrollController.position.maxScrollExtent - 200) {
ref.read(itemsProvider.notifier).loadMore();
}
}
Widget build(BuildContext context) {
final items = ref.watch(itemsProvider);
return ListView.builder(
controller: _scrollController,
itemCount: items.length,
itemBuilder: (context, index) => ItemTile(item: items[index]),
);
}
}āļŠāļģāļŦāļĢāļąāļāļĢāļēāļĒāļāļēāļĢāļāļĩāđāļĒāļēāļ§āļĄāļēāļ (1,000 āļĢāļēāļĒāļāļēāļĢāļāļķāđāļāđāļ) āļāļ§āļĢāļāļīāļāļēāļĢāļāļēāđāļāđ ListView.separated āļŦāļĢāļ·āļ Package āđāļāļāļēāļ°āļāļēāļ āđāļāđāļ scrollable_positioned_list
āļŠāļģāļŦāļĢāļąāļāļĢāļēāļĒāļāļēāļĢāļāļĩāđāļĄāļĩāļĢāļđāļāļ āļēāļ āļāļ§āļĢāđāļāđ cached_network_image āđāļāļ·āđāļāļŦāļĨāļĩāļāđāļĨāļĩāđāļĒāļāļāļēāļĢāđāļŦāļĨāļāļāđāļģ āļĢāļđāļāļ āļēāļāļāļĩāđāđāļĄāđāđāļāđāđāļāļāļāļ°āļāļģāđāļŦāđāđāļāļīāļāļāļēāļāļēāļĢāļāļĢāļ°āļāļļāļāļāļāļ°āđāļĨāļ·āđāļāļāļŦāļāđāļēāļāļ
13. āļāļāļīāļāļēāļĒāļāļēāļĢāļāļģāļāļēāļāļāļāļ Impeller Rendering Engine
Impeller āđāļāđāļēāļĄāļēāđāļāļāļāļĩāđ Skia āđāļāļāļēāļāļ° Rendering Engine āđāļĢāļīāđāļĄāļāđāļ (Flutter 3.16+) āđāļāļĒāļāļģāļāļēāļĢ Precompile Shader āđāļāļ·āđāļāļāļģāļāļąāļāļāļēāļāļēāļĢ "Jank" āđāļāļāļēāļĢāđāļŠāļāļāļāļĨāļāļĢāļąāđāļāđāļĢāļ
// Complex animations benefit from Impeller
class SmoothAnimation extends StatefulWidget {
State<SmoothAnimation> createState() => _SmoothAnimationState();
}
class _SmoothAnimationState extends State<SmoothAnimation>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
)..repeat();
}
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, child) {
// Impeller: no runtime shader compilation
return Transform.rotate(
angle: _controller.value * 2 * 3.14159,
child: child,
);
},
child: const FlutterLogo(size: 100),
);
}
}Impeller āļāļđāļāđāļāļīāļāđāļāđāļāļēāļāđāļāļĒāļāđāļēāđāļĢāļīāđāļĄāļāđāļāļāļ iOS āļŠāļģāļŦāļĢāļąāļ Android āļŠāļēāļĄāļēāļĢāļāļāļĢāļ§āļāļŠāļāļāļāļ§āļēāļĄāđāļāđāļēāļāļąāļāđāļāđāļāđāļ§āļĒāļāļģāļŠāļąāđāļ flutter run --enable-impeller
āļāļģāļāļēāļĄāđāļāļĩāđāļĒāļ§āļāļąāļāļāļēāļĢāļāļģāļāļēāļāđāļĨāļ°āļāļāļĢāđāļĄ
14. āļāļēāļĢāļāļąāļāļāļēāļĢ Navigation āļāđāļ§āļĒ Deep Linking āļāļģāļāļĒāđāļēāļāđāļĢ?
Deep Linking āļāđāļ§āļĒāđāļŦāđāļŠāļēāļĄāļēāļĢāļāđāļāļīāļāđāļāļāđāļāļĒāļąāļāļŦāļāđāļēāļāļāļāļĩāđāļāļģāļŦāļāļāļāđāļēāļ URL āđāļāđāđāļāļĒāļāļĢāļ GoRouter āļĢāļāļāļĢāļąāļāļāļąāļāļāđāļāļąāļāļāļĩāđāđāļāļ Native
final router = GoRouter(
routes: [
GoRoute(
path: '/products/:productId',
builder: (context, state) {
// Extract URL parameter
final productId = state.pathParameters['productId']!;
return ProductScreen(productId: productId);
},
),
GoRoute(
path: '/search',
builder: (context, state) {
// Query parameters (?query=flutter)
final query = state.uri.queryParameters['query'] ?? '';
return SearchScreen(initialQuery: query);
},
),
],
);
// Programmatic navigation
void navigateToProduct(BuildContext context, String id) {
// go: replaces navigation stack
context.go('/products/$id');
// push: adds to stack (allows back)
context.push('/products/$id');
// pushNamed with extra for complex data
context.pushNamed(
'productDetail',
pathParameters: {'productId': id},
extra: ProductData(id: id),
);
}āļāļģāđāļāđāļāļāđāļāļāļāļąāđāļāļāđāļēāđāļāļĨāđ Native (AndroidManifest.xml, Info.plist) āđāļāļ·āđāļāđāļāļīāļāđāļāđāļāļēāļ Deep Linking āđāļāļĢāļ°āļāļąāļāļĢāļ°āļāļāļāļāļīāļāļąāļāļīāļāļēāļĢ
15. āļāļēāļĢ Validate āļāļāļĢāđāļĄāļāļĒāđāļēāļāļĄāļĩāļāļĢāļ°āļŠāļīāļāļāļīāļ āļēāļāļāļģāļāļĒāđāļēāļāđāļĢ?
āļāļēāļĢ Validate āļĢāļ§āļĄ Form, TextFormField āđāļĨāļ° Custom Validator āđāļāđāļēāļāđāļ§āļĒāļāļąāļ Package āļāļĒāđāļēāļ formz āļāđāļ§āļĒāđāļāļīāđāļĄāđāļāļĢāļāļŠāļĢāđāļēāļāļāļĩāđāļāļąāļāđāļāļāļāļĨāđāļēāļĒāļāļąāļ Zod
class RegistrationForm extends StatefulWidget {
State<RegistrationForm> createState() => _RegistrationFormState();
}
class _RegistrationFormState extends State<RegistrationForm> {
final _formKey = GlobalKey<FormState>();
final _emailController = TextEditingController();
final _passwordController = TextEditingController();
final _confirmController = TextEditingController();
Widget build(BuildContext context) {
return Form(
key: _formKey,
// Real-time validation
autovalidateMode: AutovalidateMode.onUserInteraction,
child: Column(
children: [
TextFormField(
controller: _emailController,
decoration: const InputDecoration(labelText: 'Email'),
keyboardType: TextInputType.emailAddress,
validator: _validateEmail,
),
TextFormField(
controller: _passwordController,
decoration: const InputDecoration(labelText: 'Password'),
obscureText: true,
validator: _validatePassword,
),
TextFormField(
controller: _confirmController,
decoration: const InputDecoration(labelText: 'Confirm'),
obscureText: true,
validator: _validateConfirmPassword,
),
ElevatedButton(
onPressed: _submit,
child: const Text('Create account'),
),
],
),
);
}
String? _validateEmail(String? value) {
if (value == null || value.isEmpty) {
return 'Email required';
}
final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
if (!emailRegex.hasMatch(value)) {
return 'Invalid email format';
}
return null;
}
String? _validatePassword(String? value) {
if (value == null || value.length < 8) {
return 'Minimum 8 characters';
}
if (!value.contains(RegExp(r'[A-Z]'))) {
return 'At least one uppercase letter required';
}
if (!value.contains(RegExp(r'[0-9]'))) {
return 'At least one number required';
}
return null;
}
String? _validateConfirmPassword(String? value) {
if (value != _passwordController.text) {
return 'Passwords do not match';
}
return null;
}
void _submit() {
if (_formKey.currentState!.validate()) {
// Form is valid, proceed
}
}
}āđāļŦāļĄāļ AutovalidateMode.onUserInteraction āđāļŦāđ UX āļāļĩāđāļāļĩāļāļĩāđāļŠāļļāļ āđāļāļĢāļēāļ°āđāļŠāļāļ Error āļŦāļĨāļąāļāļāļēāļāļāļđāđāđāļāđāđāļāđāļāļāļāļāļąāļāļāļīāļĨāļāđāđāļĨāđāļ§āđāļāđāļēāļāļąāđāļ
āļāļģāļāļēāļĄāđāļāļĩāđāļĒāļ§āļāļąāļāļāļēāļĢāļāļāļŠāļāļ
16. āļāļēāļĢāļāļāļŠāļāļ Widget āđāļ Flutter āļāļģāļāļĒāđāļēāļāđāļĢ?
Widget Test āļāđāļ§āļĒāļāļĢāļ§āļāļŠāļāļ UI āđāļāļĒāđāļĄāđāļāđāļāļāļāļķāđāļāļāļēāļāļļāļāļāļĢāļāđāļāļĢāļīāļ Package flutter_test āļĄāļĩāđāļāļĢāļ·āđāļāļāļĄāļ·āļāļāļĩāđāļāļģāđāļāđāļāļāļąāđāļāļŦāļĄāļ
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
void main() {
testWidgets('displays welcome message', (tester) async {
// Arrange: build the widget
await tester.pumpWidget(
const ProviderScope(
child: MaterialApp(
home: WelcomeScreen(username: 'Alice'),
),
),
);
// Assert: verify content
expect(find.text('Welcome, Alice'), findsOneWidget);
});
testWidgets('button increments counter', (tester) async {
await tester.pumpWidget(
const MaterialApp(home: CounterScreen()),
);
// Initial state
expect(find.text('0'), findsOneWidget);
// Act: tap the button
await tester.tap(find.byType(ElevatedButton));
await tester.pump(); // Rebuild after setState
// Assert: counter incremented
expect(find.text('1'), findsOneWidget);
});
testWidgets('form validates email', (tester) async {
await tester.pumpWidget(
const MaterialApp(home: LoginForm()),
);
// Enter invalid email
await tester.enterText(
find.byKey(const Key('email-field')),
'invalid-email',
);
await tester.tap(find.byType(ElevatedButton));
await tester.pump();
// Verify error message
expect(find.text('Invalid email format'), findsOneWidget);
});
}pump() āđāļĨāļ·āđāļāļāđāļāļŦāļāļķāđāļāđāļāļĢāļĄ āļŠāđāļ§āļ pumpAndSettle() āļĢāļāļāļāļāļ§āđāļē Animation āļāļąāđāļāļŦāļĄāļāļāļ°āđāļŠāļĢāđāļāļŠāļĄāļāļđāļĢāļāđ
17. āļāļēāļĢāļāļāļŠāļāļ Riverpod Provider āļāļģāļāļĒāđāļēāļāđāļĢ?
Riverpod āļāđāļ§āļĒāđāļŦāđāļāļēāļĢāļāļāļŠāļāļāļāļģāđāļāđāļāđāļēāļĒāļāđāļēāļ ProviderContainer āđāļĨāļ°āļĢāļ°āļāļ Override
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
// Repository mock
class MockUserRepository extends Mock implements UserRepository {}
void main() {
late MockUserRepository mockRepository;
late ProviderContainer container;
setUp(() {
mockRepository = MockUserRepository();
container = ProviderContainer(
overrides: [
userRepositoryProvider.overrideWithValue(mockRepository),
],
);
});
tearDown(() {
container.dispose();
});
test('loads user from repository', () async {
// Arrange
final expectedUser = User(id: '1', name: 'Test');
when(() => mockRepository.getUser('1'))
.thenAnswer((_) async => expectedUser);
// Act
final user = await container.read(userProvider('1').future);
// Assert
expect(user, expectedUser);
verify(() => mockRepository.getUser('1')).called(1);
});
test('handles repository error', () async {
when(() => mockRepository.getUser(any()))
.thenThrow(Exception('Network error'));
expect(
() => container.read(userProvider('1').future),
throwsException,
);
});
}āļāļēāļĢāļāļāļŠāļāļ Provider āļāļģāļāļēāļāđāļāđāļĢāļ§āļāđāļĢāđāļ§āđāļāļĢāļēāļ°āđāļĄāđāļāļģāđāļāđāļāļāđāļāļ Render UI
āļāļģāļāļēāļĄāđāļāļĩāđāļĒāļ§āļāļąāļāļāļēāļĢ Deploy
18. āļāļēāļĢāļāļąāļāļāļēāļĢ Environment (dev, staging, prod) āļāļģāļāļĒāđāļēāļāđāļĢ?
Environment āļāļģāļŦāļāļāļāđāļēāļāđāļēāļāđāļāļĨāđ .env āļŦāļĢāļ·āļ Compile-time Constant āļāđāļ§āļĒ --dart-define
enum Environment { dev, staging, prod }
class AppConfig {
final Environment environment;
final String apiUrl;
final bool enableAnalytics;
const AppConfig._({
required this.environment,
required this.apiUrl,
required this.enableAnalytics,
});
// Predefined configurations
static const dev = AppConfig._(
environment: Environment.dev,
apiUrl: 'https://api-dev.example.com',
enableAnalytics: false,
);
static const staging = AppConfig._(
environment: Environment.staging,
apiUrl: 'https://api-staging.example.com',
enableAnalytics: true,
);
static const prod = AppConfig._(
environment: Environment.prod,
apiUrl: 'https://api.example.com',
enableAnalytics: true,
);
// Read from --dart-define
static AppConfig fromEnvironment() {
const env = String.fromEnvironment('ENV', defaultValue: 'dev');
switch (env) {
case 'prod':
return prod;
case 'staging':
return staging;
default:
return dev;
}
}
}# terminal
# Launch with specific environment
flutter run --dart-define=ENV=staging
# Production build
flutter build apk --dart-define=ENV=prod --release19. āļāļēāļĢāļāļģ Flavoring āļŠāļģāļŦāļĢāļąāļāđāļāļāļŦāļĨāļēāļĒāđāļ§āļāļĢāđāļāļąāļāļāļģāļāļĒāđāļēāļāđāļĢ?
Flavoring āļŠāļĢāđāļēāļāđāļāļāļŦāļĨāļēāļĒāđāļ§āļāļĢāđāļāļąāļ (client1, client2) āļāļĩāđāļĄāļĩāļāļēāļĢāļāļąāđāļāļāđāļēāđāļāļāļāđāļēāļāļāļąāļ (āđāļāļāļāļ, āļāļ·āđāļ, API)
import 'package:flutter/material.dart';
import 'config/flavor_config.dart';
import 'app.dart';
void main() {
FlavorConfig(
flavor: Flavor.client1,
name: 'App Client 1',
apiUrl: 'https://api.client1.com',
primaryColor: Colors.blue,
);
runApp(const App());
}
// config/flavor_config.dart
enum Flavor { client1, client2, internal }
class FlavorConfig {
final Flavor flavor;
final String name;
final String apiUrl;
final Color primaryColor;
// Singleton for global access
static FlavorConfig? _instance;
static FlavorConfig get instance => _instance!;
FlavorConfig({
required this.flavor,
required this.name,
required this.apiUrl,
required this.primaryColor,
}) {
_instance = this;
}
bool get isProduction => flavor != Flavor.internal;
}āļāļģāđāļāđāļāļāđāļāļāļāļąāđāļāļāđāļēāđāļāļĨāđ Native āļāļąāđāļ Android (build.gradle) āđāļĨāļ° iOS (xcconfig) āļŠāļģāļŦāļĢāļąāļāđāļāđāļĨāļ° Flavor
20. āđāļāļ§āļāļēāļāļāļāļīāļāļąāļāļīāļāđāļēāļāļāļ§āļēāļĄāļāļĨāļāļāļ āļąāļĒāļāļāļ Flutter āļĄāļĩāļāļ°āđāļĢāļāđāļēāļ?
āļāļ§āļēāļĄāļāļĨāļāļāļ āļąāļĒāļāļĢāļāļāļāļĨāļļāļĄāļāļēāļĢāļāļąāļāđāļāđāļāļāđāļāļĄāļđāļĨāļāļĩāđāļĨāļ°āđāļāļĩāļĒāļāļāđāļāļ, āļāļēāļĢ Validate Input āđāļĨāļ°āļāļēāļĢāļāđāļāļāļāļąāļ Reverse Engineering
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
class SecureStorage {
// Encrypted storage for sensitive data
final _storage = const FlutterSecureStorage(
aOptions: AndroidOptions(encryptedSharedPreferences: true),
iOptions: IOSOptions(accessibility: KeychainAccessibility.first_unlock),
);
Future<void> saveToken(String token) async {
await _storage.write(key: 'auth_token', value: token);
}
Future<String?> getToken() async {
return _storage.read(key: 'auth_token');
}
Future<void> deleteToken() async {
await _storage.delete(key: 'auth_token');
}
}
// Input validation
class InputValidator {
// Injection prevention
static String sanitize(String input) {
return input
.replaceAll(RegExp(r'[<>"\']'), '')
.trim();
}
// Length validation
static bool isValidLength(String input, int min, int max) {
return input.length >= min && input.length <= max;
}
}
// SSL pinning protection
class SecureApiClient {
Dio createSecureClient() {
final dio = Dio();
// Add certificate pinning
(dio.httpClientAdapter as IOHttpClientAdapter).createHttpClient = () {
final client = HttpClient();
client.badCertificateCallback = (cert, host, port) {
// Verify certificate fingerprint
return _isValidCertificate(cert);
};
return client;
};
return dio;
}
}āđāļĄāđāļāļ§āļĢāđāļāđāļ Secret āđāļ§āđāđāļāđāļāđāļāđāļāļĒāđāļāđāļāļāļēāļ āđāļāđ flutter_secure_storage āļŠāļģāļŦāļĢāļąāļ Token āđāļĨāļ°āđāļāđ --obfuscate āļŠāļģāļŦāļĢāļąāļ Production Build
āļŠāļĢāļļāļ
āļāļģāļāļēāļĄ 20 āļāđāļāđāļŦāļĨāđāļēāļāļĩāđāļāļĢāļāļāļāļĨāļļāļĄāļāļļāļāđāļāđāļĄāļļāļĄāļāļĩāđāļŠāļģāļāļąāļāļāļāļāļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļāđāļāļēāļ Flutter āļāļąāđāļāđāļāđāļāļ·āđāļāļāļēāļāļāļāļ Framework, āļāļ§āļēāļĄāđāļāļĩāđāļĒāļ§āļāļēāļāļāđāļēāļ Dart, āļĢāļđāļāđāļāļāļŠāļāļēāļāļąāļāļĒāļāļĢāļĢāļĄ āđāļāļāļāļāļķāļāđāļāļ§āļāļēāļāļāļāļīāļāļąāļāļīāļŠāļģāļŦāļĢāļąāļ Production āļāļ§āļēāļĄāļŠāļģāđāļĢāđāļāđāļāļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļāđāļāļĒāļđāđāļāļĩāđāļāļ§āļēāļĄāđāļāđāļēāđāļāđāļāļīāļāļĨāļķāļāļāļāļāļāļĨāđāļāđāļāļ·āđāļāļāļŦāļĨāļąāļ āđāļĄāđāđāļāđāđāļāđāđāļ§āļĒāļēāļāļĢāļāđ
āļĢāļēāļĒāļāļēāļĢāļāļĢāļ§āļāļŠāļāļāļāđāļāļāļŠāļąāļĄāļ āļēāļĐāļāđ
- â āđāļāđāļēāđāļāļāļ§āļēāļĄāđāļāļāļāđāļēāļāļĢāļ°āļŦāļ§āđāļēāļ StatelessWidget āļāļąāļ StatefulWidget āđāļĨāļ°āļāļĢāļāļĩāļāļēāļĢāđāļāđāļāļēāļ
- â āđāļāđāļēāđāļ Widget Tree āđāļĨāļ°āļāļēāļĢāđāļāļīāđāļĄāļāļĢāļ°āļŠāļīāļāļāļīāļ āļēāļāļāļēāļĢ Rebuild
- â āļāļķāļāļāļ async/await, Future āđāļĨāļ° Stream āļāđāļ§āļĒāđāļāļāļāļķāļāļŦāļąāļāļāļĢāļīāļ
- â āļŠāļĢāđāļēāļāđāļāļĢāđāļāļāļāđāļāđāļ§āļĒ Riverpod āļŠāļģāļŦāļĢāļąāļ State Management
- â āļĢāļđāđāļāļąāļ GoRouter āđāļĨāļ° Deep Linking
- â āđāļāļĩāļĒāļ Unit Test āđāļĨāļ° Widget Test
- â āđāļāđāļēāđāļāļāļēāļĢāļāļąāđāļāļāđāļē Multi-environment
āđāļĢāļīāđāļĄāļāļķāļāļāđāļāļĄāđāļĨāļĒ!
āļāļāļŠāļāļāļāļ§āļēāļĄāļĢāļđāđāļāļāļāļāļļāļāļāđāļ§āļĒāļāļąāļ§āļāļģāļĨāļāļāļŠāļąāļĄāļ āļēāļĐāļāđāđāļĨāļ°āđāļāļāļāļāļŠāļāļāđāļāļāļāļīāļāļāļĢāļąāļ
āļāļēāļĢāļāļķāļāļāļāļāļĒāđāļēāļāļŠāļĄāđāļģāđāļŠāļĄāļāđāļāđāļāļĢāđāļāļāļāđāļŠāđāļ§āļāļāļąāļ§āļĒāļąāļāļāļāđāļāđāļāļ§āļīāļāļĩāļāļĩāđāļāļĩāļāļĩāđāļŠāļļāļāđāļāļāļēāļĢāđāļŠāļĢāļīāļĄāļŠāļĢāđāļēāļāļāļ§āļēāļĄāļĢāļđāđāđāļŦāļĨāđāļēāļāļĩāđ āđāļāđāļĨāļ°āļāļģāļāļēāļĄāļāļĩāđāļāļĨāđāļēāļ§āļĄāļēāļāļ§āļĢāđāļāđāļĢāļąāļāļāļēāļĢāļĻāļķāļāļĐāļēāđāļāļīāđāļĄāđāļāļīāļĄāđāļāđāļāļīāļāļĨāļķāļāļāđāļ§āļĒāđāļāđāļāļāļĢāļīāļāđāļāļ·āđāļāđāļŦāđāđāļāđāļēāđāļāļĢāļēāļĒāļĨāļ°āđāļāļĩāļĒāļāļāļĨāļĩāļāļĒāđāļāļĒāļāļāļ Flutter Framework āļāļĒāđāļēāļāļāđāļāļāđāļāđ
āđāļāđāļ
āđāļāļĢāđ
āļāļāļāļ§āļēāļĄāļāļĩāđāđāļāļĩāđāļĒāļ§āļāđāļāļ

Flutter: āļŠāļĢāđāļēāļāđāļāļāļāļĨāļīāđāļāļāļąāļāļāđāļēāļĄāđāļāļĨāļāļāļāļĢāđāļĄāļāļąāļ§āđāļĢāļ
āļāļđāđāļĄāļ·āļāļāļāļąāļāļŠāļĄāļāļđāļĢāļāđāļŠāļģāļŦāļĢāļąāļāļāļēāļĢāļŠāļĢāđāļēāļāđāļāļāļāļĨāļīāđāļāļāļąāļāļĄāļ·āļāļāļ·āļāļāđāļēāļĄāđāļāļĨāļāļāļāļĢāđāļĄāļāđāļ§āļĒ Flutter āđāļĨāļ° Dart āļāļĢāļāļāļāļĨāļļāļĄ Widget āļāļēāļĢāļāļąāļāļāļēāļĢāļŠāļāļēāļāļ° āļāļēāļĢāļāļģāļāļēāļ āđāļĨāļ°āđāļāļ§āļāļēāļāļāļāļīāļāļąāļāļīāļāļĩāđāļāļĩāļŠāļģāļŦāļĢāļąāļāļāļđāđāđāļĢāļīāđāļĄāļāđāļ

Flutter āđāļĨāļ° Firebase āđāļāļāļĩ 2026: āļāļēāļĢāļĒāļ·āļāļĒāļąāļāļāļąāļ§āļāļ, Firestore āđāļĨāļ°āļāļģāļāļēāļĄāļŠāļąāļĄāļ āļēāļĐāļāđ
āđāļāļēāļ°āļĨāļķāļ Flutter Firebase: āļāļēāļĢāļĒāļ·āļāļĒāļąāļāļāļąāļ§āļāļāļāđāļ§āļĒ firebase_auth, CRUD āļāļāļ Firestore āđāļĨāļ°āļŠāļāļĢāļĩāļĄāđāļāļāđāļĢāļĩāļĒāļĨāđāļāļĄāđ, āļāļāļāļ§āļēāļĄāļāļĨāļāļāļ āļąāļĒ āđāļĨāļ°āļāļģāļāļēāļĄāļŠāļąāļĄāļ āļēāļĐāļāđāļāļĩāđāļāļāļāđāļāļĒāļāļĢāđāļāļĄāļāļąāļ§āļāļĒāđāļēāļāđāļāđāļ

āļāļēāļĢāļāļāļŠāļāļ Flutter āļāļĒāđāļēāļāļāļĢāļāļāđāļ§āļ: Widget Test, Integration Test āđāļĨāļ°āļāļĨāļĒāļļāļāļāđāļŠāļąāļĄāļ āļēāļĐāļāđāļāļēāļāļŠāļēāļĒāđāļāļāļāļīāļ 2026
āļāļđāđāļĄāļ·āļāļāļēāļĢāļāļāļŠāļāļ Flutter āļāļāļąāļāļŠāļĄāļāļđāļĢāļāđ: widget test, integration test, golden test āđāļĨāļ° mocking āļāđāļ§āļĒ Mocktail āļāļĢāđāļāļĄāļāļąāļ§āļāļĒāđāļēāļāđāļāđāļāļāļĢāļīāļāđāļĨāļ°āđāļāļ§āļāļēāļāļāļĩāđāļāļāļāđāļāļĒāđāļāļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļāđāļāļēāļāļŠāļēāļĒāđāļāļāļāļīāļ 2026