Modules
These are the modules that smf create offers. Each one is a Dart package on pub.dev, but you never add them to an app yourself: smf create puts what they generate into the app.
Module (-m) | Package | Kind | Role it provides | Adds to the app |
|---|---|---|---|---|
flutter_core | smf_flutter_core | scaffold | App entry | The Flutter project, main(), start-up and root widget, in every app, and the screen that an app starts on when no route starts it |
go_router | smf_go_router | infrastructure | Router | The router of the features' routes, with go_router |
bottom_tabs | smf_bottom_tabs | layout | Layout | Tabs at the bottom for the destinations of the features, in a bar that it draws in the colors of the theme |
home | smf_home_flutter | feature | none | A start screen at /home, which welcomes the developer of the app and lists the next steps |
onboarding | smf_onboarding | feature | Onboarding screen | The onboarding at /onboarding, which the app shows on its first launch until the user finishes it, with the steps that other modules add |
settings | smf_settings | feature | Settings screen | A settings screen at /settings, with the settings of the modules in one group, a row for each |
sign_in | smf_sign_in | feature | none | The screens of sign-in, sign-up and password reset for an email address and a password, with a button for each other way to sign in of the app, and the screen of the account with its row on the settings screen, with BLoC or with Riverpod |
paywall | smf_paywall | feature | none | The paywall at /paywall, which sells premium access with the plans of the current offer, the screen of the subscription at /paywall/subscription, its row on the settings screen and its step in the onboarding, with BLoC or with Riverpod |
bloc | smf_bloc | infrastructure | State management | flutter_bloc |
riverpod | smf_riverpod | infrastructure | State management | flutter_riverpod and its ProviderScope |
material_theme | smf_material_theme | infrastructure | Theme | A light and a dark Material 3 theme with a palette, text styles and a bundled font, in lib/core/theme/app_theme.dart |
launcher_icons | smf_launcher_icons | infrastructure | App icon | An opaque icon on iOS and an adaptive icon with a themed variant on Android, made with flutter_launcher_icons from two images in assets/branding/ |
native_splash | smf_native_splash | infrastructure | Splash screen | The screen that the system shows while the app starts, for the light and the dark mode, made with flutter_native_splash from two images in assets/branding/ |
gen_l10n | smf_gen_l10n | infrastructure | Localization | The texts of the app in ARB files, one for each language, with gen-l10n of Flutter |
get_it | smf_get_it | infrastructure | Dependency injection | Registration of the app's services in get_it |
event_bus | smf_event_bus | infrastructure | Events | A CommunicationService on the event_bus package |
shared_preferences | smf_shared_preferences | infrastructure | Preferences | AppPreferences on the shared_preferences package, for the settings that the app remembers |
dart_define | smf_dart_define | infrastructure | Values in .env | AppEnv, which gives the app the values of .env with --dart-define-from-file |
local_notifications | smf_local_notifications | infrastructure | Notifications | Notifications now and at about a time to come, the permission to show them and the taps on them, with flutter_local_notifications |
firebase_core | smf_firebase_core | infrastructure | none | Firebase for each flavor: options, initialization, the script tool/configure_firebase.dart, setup of the machine |
firebase_crashlytics | smf_firebase_crashlytics | infrastructure | Crash reporting | A CrashReporter on Firebase Crashlytics |
firebase_analytics | smf_firebase_analytics | infrastructure | Analytics | An AnalyticsService on Firebase Analytics, and screen views |
firebase_messaging | smf_firebase_messaging | infrastructure | Push messages | Push messages with Firebase Cloud Messaging: the address of the device for the backend, the messages and the taps on them |
firebase_auth | smf_firebase_auth | infrastructure | Authentication | Sign-in with Firebase Authentication: an email address and a password, an anonymous user, or a way to sign in of Google or Apple, and a script that enables the sign-in methods in the Firebase project |
google_sign_in | smf_google_sign_in | infrastructure | none | Google sign-in on Android and iOS: googleCredential(), the icon of its button with the "G" of Google, and a way to sign in for the auth role |
apple_sign_in | smf_apple_sign_in | infrastructure | none | Sign in with Apple on iOS: appleCredential(), the icon of its button, a way to sign in for the auth role, and the entitlement of the capability in ios/Runner/Runner.entitlements |
dio | smf_dio | infrastructure | REST API | The requests of appRest over a Dio |
revenuecat | smf_revenuecat | infrastructure | Purchases | Premium access with RevenueCat: the plans of the default offering, a purchase, a restore, and the access of the user before the first frame |
github_actions | smf_github_actions | infrastructure | CI | .github/workflows/ci.yml: the checks on each push, and a release APK for an environment on request |
The kind of a module decides the rules it follows. A feature keeps its files in lib/features/<id>/ and declares routes, a layout provides the main navigation, and infrastructure sets up a service or a library without screens of its own. A feature can provide a role too, as settings does, and it can keep its state with the state manager of the app, as sign_in and paywall do in a variant for each. See the module model.
Roles and their files
A role generates the part of the app that other code counts on, whichever module provides it. These files belong to the roles rather than to a module:
| Role | Files | What they declare |
|---|---|---|
| App entry | AGENTS.md, CLAUDE.md, lib/core/app/status_bar_icons.dart, test/core/app/status_bar_icons_test.dart, and the sections of the flavors and the steps by hand in README.md | The guide for coding agents that work on the app; StatusBarIcons, which asks for the icons of the status bar that suit the theme, and its widget test |
| Onboarding screen | lib/core/onboarding/onboarding_steps.dart | OnboardingStep and appOnboardingSteps, the steps that the modules add to the onboarding |
| Router | lib/core/router/app_router.dart, lib/core/router/navigation.dart | AppRouter, appRouter, the location classes and context.nav. In an app with guards, also routeGuards, redirectOf(), flowIsOver(), guardChanges and GuardedNavigation |
| Layout | lib/core/layout/destination.dart | Destination, the label and icon of an item of the main navigation, and appDestinations, the destinations of the app |
| Theme | lib/core/theme/theme_mode.dart, and lib/core/theme/theme_mode_setting.dart in an app with a settings screen | appThemeMode, the theme mode that the user selected, AppThemeModeScope and restoreAppThemeMode; ThemeModeSetting, the entry of the settings screen |
| Localization | lib/core/l10n/app_locale.dart, and lib/core/l10n/language_setting.dart in an app with a settings screen | appLocales, the languages of the app, appLocale, the language that the user chose, AppLocaleScope and restoreAppLocale; LanguageSetting, the entry of the settings screen |
| Dependency injection | lib/core/di/service_locator.dart | ServiceLocator, resolve<T>() |
| Events | lib/core/events/communication_service.dart | AppEvent, CommunicationService, createCommunicationService() |
| Preferences | lib/core/preferences/app_preferences.dart | AppPreferences, initPreferences(), createAppPreferences() |
| Analytics | lib/core/analytics/analytics_service.dart | AnalyticsService, createAnalyticsService() |
| Crash reporting | lib/core/crash_reporting/crash_reporter.dart | CrashReporter, createCrashReporter(), installCrashReporting() |
| Authentication | lib/core/auth/app_session.dart, lib/core/auth/auth_service.dart, lib/core/auth/guest_data.dart, lib/core/auth/sign_in_methods.dart | appSession, the session of the app, authMode and initAuth(); AuthService, the interface of a provider, AuthFailure and SignInCredential; takeGuestData(), which the developer of the app edits; SignInMethod and appSignInMethods, the ways to sign in of the app |
| Notifications | lib/core/notifications/app_notifications.dart, lib/core/notifications/notifications_service.dart, android/app/src/main/res/drawable/ic_notification.xml, android/app/src/main/res/raw/notifications_keep.xml, lib/core/notifications/notifications_setting.dart in an app with a settings screen, and lib/core/notifications/notifications_step.dart in an app with an onboarding | appNotifications, NotificationPermission and initNotifications(); NotificationsService, AppNotification and NotificationTap; the small icon of Android and the file that keeps it in a release build; NotificationsSetting, the entry of the settings screen; notificationsStepShows() and allowNotifications(), the functions of the step of the onboarding |
| Push messages | lib/core/push/app_push.dart, lib/core/push/push_service.dart | appPush and initPush(); PushService, the interface of a provider, and PushMessage |
| Purchases | lib/core/purchases/app_purchases.dart, lib/core/purchases/purchases_service.dart, and lib/core/purchases/restore_purchases_setting.dart in an app with a settings screen | appPurchases, the premium access of the user, and initPurchases(); PurchasesService, the interface of a provider, AppAccess, Plan and PurchasesFailure; RestorePurchasesSetting, the entry of the settings screen |
| Values in .env | .env, .env.example, a line of .gitignore, .vscode/launch.json and .run/<flavor>.run.xml | The values that you fill in, the same keys without values, the line that keeps .env out of git, and a run configuration for each flavor. Every provider generates AppEnv in lib/core/env/app_env.dart, with a getter for each key |
| REST API | lib/core/rest/app_rest.dart, lib/core/rest/rest_transport.dart, lib/core/rest/session_tokens.dart in an app with sign-in, test/core/rest/rest_test_server.dart, test/core/rest/app_rest_test.dart, and the permission android.permission.INTERNET | appRest, the REST client of the app, RestFailure, RestResponse and RestCancel; RestTransport, the interface of a provider; what gives the client the token of appSession; RestTestServer, a local server for the tests of the app; a real request through the provider |
| CI | tool/write_env.dart in an app with values in .env | The script that writes .env for a job. The commands of CI are in the README, and a provider writes them in the format of its host |
The state management role, the settings screen role, the app icon role and the splash role have no files of their own that code reads: screens use the state management libraries directly, the module that provides the settings screen generates the screen, and each module of the icon and the screen generates its two images in assets/branding/. Besides the files above, the files of the app entry come from flutter_core.
Routes, settings and texts of the modules
A module does not reach into another module. It gives a role what the role collects from every module: a route, a guard, a restorer of a setting, a row of the settings screen, a step of the onboarding, a text, a key of .env. In an app with every module above, the router, the preferences, the settings screen, the onboarding and the localization get these from the modules, and from four roles. The services of the modules and what follows the screens are on the pages of the modules.
| From | Routes and guards | Restorer of the preferences | Row of the settings screen | Texts, in English and in Ukrainian |
|---|---|---|---|---|
home | /home, a destination | The label of its tab, and the 14 texts of its screen | ||
onboarding | /onboarding, and the guard onboarding.firstRun | restoreOnboarding | The six texts of its screen | |
settings | /settings, a destination | The title of its screen, which is the label of its tab too | ||
sign_in | /sign_in with /sign_in/sign_up and /sign_in/reset_password below it, /sign_in/account, which asks for an account, and the guards sign_in.gate and sign_in.hasAccount | Account | The 49 texts of its screens | |
google_sign_in, apple_sign_in | The label of the button of each, Continue with Google and Continue with Apple | |||
paywall | /paywall, and /paywall/subscription, which asks for premium access, and the guard paywall.hasPremium | Subscription | The 65 texts of its screens, the three texts of its row, and the four texts of its step of the onboarding, Unlock premium | |
The theme role, with material_theme | restoreAppThemeMode | Theme | The four texts of its row | |
The localization role, with gen_l10n | restoreAppLocale | Language | The two texts of its row | |
The notifications role, with local_notifications | restoreNotifications | Notifications | The three texts of its row, and the four texts of its step of the onboarding, Turn on notifications | |
The purchases role, with revenuecat | Restore purchases | The four texts of its row |
So the settings screen of such an app has the rows Account and Subscription, and after them the rows Theme, Language, Notifications and Restore purchases, in the order of the modules that provide the four roles. The onboarding shows the step of the notifications and then the step of the paywall before its last page. The preferences restore four settings before the first frame, and the router asks four guards: the gate of the onboarding, then the gate of the sign-in, then the guard of the routes that need an account, and last the guard of the routes that need premium access. Such an app starts on /home, so flutter_core gives it no texts: only an app that no route starts has the two texts of its fallback start screen. revenuecat gives the role of the values in .env the three API keys of RevenueCat, paywall the addresses of its terms of use and its privacy policy, and the REST role the address of the API; see Values in .env. A module of your own gives the roles the same things; see Extending SMF.
Three modules also add files that are not code, and declare them in pubspec.yaml: home the image of its screen, in lib/features/home/assets/, google_sign_in the "G" of Google for its button, in lib/core/google_sign_in/assets/, and material_theme the font of its themes with its license, in assets/fonts/geist/.