Question #105MediumFlutter Basics

What are the flutter mobile app standards ?

#flutter

Answer

Overview

Flutter mobile app standards refer to best practices for code quality, performance, security, accessibility, and user experience. Following these standards ensures maintainable, scalable, and production-ready apps.


1. Code Quality Standards

Project Structure

Feature-first structure (recommended for large apps):

text
lib/
  features/
    authentication/
      data/
      domain/
      presentation/
    home/
      data/
      domain/
      presentation/
  core/
    utils/
    constants/
    widgets/
  main.dart

Layer-first structure (simple apps):

text
lib/
  data/
  domain/
  presentation/
  main.dart

Naming Conventions

dart
// ✅ Classes: PascalCase
class UserRepository {}

// ✅ Files: snake_case
// user_repository.dart

// ✅ Variables/functions: camelCase
String userName = 'Alice';
void fetchUserData() {}

// ✅ Constants: lowerCamelCase or UPPER_SNAKE_CASE
const maxRetries = 3;
const MAX_RETRIES = 3;

// ✅ Private members: _prefix
class User {
  String _password;
}

Dart Analysis (Linting)

analysis_options.yaml:

yaml
include: package:flutter_lints/flutter.yaml

linter:
  rules:
    - prefer_const_constructors
    - prefer_const_literals_to_create_immutables
    - avoid_print
    - avoid_unnecessary_containers
    - sized_box_for_whitespace
    - use_key_in_widget_constructors
    - prefer_single_quotes
    - always_declare_return_types

2. Performance Standards

Widget Optimization

dart
// ✅ Use const constructors
const Text('Hello');
const SizedBox(height: 16);

// ✅ Avoid rebuilding entire tree
class MyWidget extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Column(
      children: [
        const HeaderWidget(), // Const — never rebuilds
        DynamicWidget(),      // Only this rebuilds
      ],
    );
  }
}

// ✅ Extract widgets for reuse
class _BuildItem extends StatelessWidget {
  final String text;
  const _BuildItem(this.text);

  
  Widget build(BuildContext context) {
    return Text(text);
  }
}

Image Optimization

dart
// ✅ Use cached_network_image
CachedNetworkImage(
  imageUrl: 'https://example.com/image.jpg
  placeholder: (context, url) => CircularProgressIndicator(),
  errorWidget: (context, url, error) => Icon(Icons.error),
)

// ✅ Specify image dimensions
Image.network(
  'https://example.com/image.jpg
  width: 300,
  height: 200,
  fit: BoxFit.cover,
)

// ❌ Avoid loading large images without caching
Image.network('https://example.com/10mb.jpg') // ❌

List Performance

dart
// ✅ Use ListView.builder for long lists
ListView.builder(
  itemCount: 1000,
  itemBuilder: (context, index) => ListTile(title: Text('Item $index')),
)

// ❌ Avoid ListView with all items
ListView(
  children: List.generate(1000, (i) => ListTile(...)), // ❌ Builds all at once
)

3. State Management Standards

Choose based on app complexity:

App SizeRecommendedAlternative
SmallProvider, RiverpodsetState
MediumBLoC, RiverpodGetX
LargeBLoC, RiverpodClean Architecture + BLoC

Example (BLoC):

dart
// ✅ Separate business logic from UI
class UserBloc extends Bloc<UserEvent, UserState> {
  UserBloc() : super(UserInitial()) {
    on<FetchUser>(_onFetchUser);
  }

  Future<void> _onFetchUser(FetchUser event, Emitter<UserState> emit) async {
    emit(UserLoading());
    try {
      final user = await userRepository.fetchUser(event.id);
      emit(UserLoaded(user));
    } catch (e) {
      emit(UserError(e.toString()));
    }
  }
}

4. Security Standards

API Keys

dart
// ❌ Never hardcode API keys
const apiKey = 'sk-1234567890'; // ❌

// ✅ Use environment variables
flutter run --dart-define=API_KEY=sk-1234567890

// Access in code
const apiKey = String.fromEnvironment('API_KEY');

Secure Storage

dart
// ✅ Use flutter_secure_storage for sensitive data
import 'package:flutter_secure_storage/flutter_secure_storage.dart';

final storage = FlutterSecureStorage();

await storage.write(key: 'auth_token', value: token);
final token = await storage.read(key: 'auth_token');

Network Security

dart
// ✅ Use HTTPS only
final response = await http.get(Uri.parse('https://api.example.com'));

// ❌ Avoid HTTP (insecure)
// http://api.example.com ❌

5. Accessibility Standards

dart
// ✅ Add semantic labels
Semantics(
  label: 'Close button',
  child: IconButton(
    icon: Icon(Icons.close),
    onPressed: () {},
  ),
)

// ✅ Use accessible colors (contrast ratio 4.5:1)
Text(
  'Readable Text',
  style: TextStyle(
    color: Colors.black,      // ✅ High contrast
    backgroundColor: Colors.white,
  ),
)

// ✅ Support screen readers
ExcludeSemantics(
  child: DecorativeImage(), // Decorative — skip for screen readers
)

6. Testing Standards

dart
// ✅ Unit tests for business logic
test('UserRepository fetches user', () async {
  final user = await userRepository.fetchUser('123');
  expect(user.name, 'Alice');
});

// ✅ Widget tests for UI
testWidgets('Login button triggers login', (tester) async {
  await tester.pumpWidget(LoginPage());
  await tester.tap(find.byType(ElevatedButton));
  await tester.pump();

  expect(find.text('Loading...'), findsOneWidget);
});

// ✅ Integration tests for flows
testWidgets('Complete login flow', (tester) async {
  await tester.pumpWidget(MyApp());
  await tester.enterText(find.byKey(Key('email')), 'test@example.com');
  await tester.enterText(find.byKey(Key('password')), 'password');
  await tester.tap(find.text('Login'));
  await tester.pumpAndSettle();

  expect(find.text('Welcome'), findsOneWidget);
});

Coverage target: 80%+ for critical code.


7. Error Handling Standards

dart
// ✅ Handle errors gracefully
try {
  final data = await fetchData();
} catch (e) {
  logger.error('Failed to fetch data', e);
  showSnackBar('Something went wrong. Please try again.');
}

// ✅ Use Result/Either pattern (functional error handling)
class Result<T> {
  final T? data;
  final String? error;

  Result.success(this.data) : error = null;
  Result.failure(this.error) : data = null;
}

Future<Result<User>> fetchUser(String id) async {
  try {
    final user = await api.getUser(id);
    return Result.success(user);
  } catch (e) {
    return Result.failure(e.toString());
  }
}

8. Documentation Standards

dart
/// Fetches user data from the API.
///
/// Returns a [User] object if successful.
/// Throws [NetworkException] if network fails.
///
/// Example:
/// ```dart
/// final user = await fetchUser('123');
/// print(user.name);
/// ```
Future<User> fetchUser(String id) async {
  final response = await http.get(Uri.parse('https://api.example.com/users/$id'));
  if (response.statusCode == 200) {
    return User.fromJson(jsonDecode(response.body));
  } else {
    throw NetworkException('Failed to fetch user');
  }
}

9. Dependency Management

yaml
# ✅ Pin major versions
dependencies:
  http: ^1.1.0        # 1.x.x (SemVer)
  provider: ^6.0.0

# ✅ Separate dev dependencies
dev_dependencies:
  flutter_test:
    sdk: flutter
  build_runner: ^2.4.0
  mockito: ^5.4.0

# ✅ Keep dependencies updated
# Run: flutter pub outdated

10. Build Standards

Flavors (Dev, Staging, Prod)

dart
// main_dev.dart
void main() {
  runApp(MyApp(environment: Environment.dev));
}

// main_prod.dart
void main() {
  runApp(MyApp(environment: Environment.prod));
}

Build commands:

bash
# Dev build
flutter build apk --flavor dev -t lib/main_dev.dart

# Production build
flutter build apk --flavor prod -t lib/main_prod.dart --release

11. UI/UX Standards

dart
// ✅ Follow Material Design or Cupertino guidelines
MaterialApp(
  theme: ThemeData(
    primarySwatch: Colors.blue,
    visualDensity: VisualDensity.adaptivePlatformDensity,
  ),
)

// ✅ Responsive design
LayoutBuilder(
  builder: (context, constraints) {
    if (constraints.maxWidth > 600) {
      return TabletLayout();
    } else {
      return MobileLayout();
    }
  },
)

// ✅ Handle loading states
if (isLoading) CircularProgressIndicator()
else if (hasError) ErrorWidget(error: error)
else ContentWidget(data: data)

12. Checklist for Production

  • No
    text
    print()
    statements (use logger)
  • No hardcoded API keys
  • Error handling in all async calls
  • Loading states for all API calls
  • Accessibility labels on interactive widgets
  • Images optimized and cached
  • Tests written (80%+ coverage)
  • Lint errors fixed (
    text
    flutter analyze
    )
  • Obfuscated code (
    text
    --obfuscate --split-debug-info
    )
  • ProGuard enabled (Android)
  • Bitcode enabled (iOS)

Summary

CategoryStandard
CodeFollow linter rules, naming conventions
PerformanceUse const, ListView.builder, image caching
StateBLoC/Riverpod for complex apps
SecuritySecure storage, no hardcoded keys
AccessibilitySemantic labels, contrast ratios
Testing80%+ coverage
Error HandlingTry-catch, user-friendly messages
DocumentationDartdoc comments for public APIs

Learn more: