flutter_core
| Package | Kind | Provides the role | Needs | Choose with |
|---|---|---|---|---|
smf_flutter_core | scaffold | App entry | nothing | added to every app |
flutter_core creates the Flutter app that every SMF app starts from: the Android and iOS projects, main(), the start-up sequence, the root widget, pubspec.yaml, and the screen that an app shows while it has no screen to start on. It provides the app entry role, and every app needs exactly one provider of that role, so smf create adds flutter_core to every app.
What it adds to the app
| File | What it holds |
|---|---|
lib/main.dart | main(): WidgetsFlutterBinding.ensureInitialized(), await bootstrap(), then runApp() with the root widget inside the wrappers of other modules. |
lib/bootstrap.dart | bootstrap(), where the other modules put their start-up code, phase by phase. It imports neither material nor cupertino. |
lib/app.dart | App, the root widget: a MaterialApp.router with the router's configuration when the app has a router, or else a MaterialApp that shows the fallback start screen. App creates it in its build, with the arguments that modules and roles give it, such as the theme. Its builder holds the widgets that other modules put around the content of every route. |
lib/core/app/fallback_start_screen.dart | FallbackStartScreen, the screen that an app without a screen to start on shows, and FallbackStartView, which the screen builds with its texts. |
test/core/app/fallback_start_screen_test.dart | A widget test of the fallback start screen. |
pubspec.yaml | The dependencies of all modules, with Dart ^3.12.0 and Flutter >=3.44.0, and flutter_lints for the lints. |
analysis_options.yaml | The lints of a new Flutter app, with build/** left out of the analysis. |
README.md | The name of the app, and the sections that other modules add. |
.gitignore, .metadata | The files of the same names that flutter create writes. |
android/, ios/ | The projects of flutter create of Flutter 3.44, with the identifiers of the app. |
The native projects are those that flutter create --platforms=android,ios writes with Flutter 3.44.2, with a few changes:
- The names and identifiers come from the app. The Android label and the iOS display name are the name of the app in title case. The Android namespace, application id and Kotlin package path, and the iOS bundle id, come from
--organd the app name. - The minimum iOS version is 15.0, the lowest that Xcode 27 builds for, unless a module needs a higher one. The Xcode project has no development team.
- The Android manifest,
Info.plistand the Gradle files have places where other modules add permissions, keys and plugins.
The app also gets AGENTS.md and CLAUDE.md, the guide for coding agents. They come from the app entry role, whichever module provides it, so an app with another provider of the role has them too. To the section "App entry" of the guide, the module adds the commands to run after a change, the rules of its root widget with the one MaterialApp of the app, and where the test of a file goes. See Working with a coding agent.
The fallback start screen
An app shows the fallback start screen while no route can start it: an app without a router, and an app with a router whose features mark no route to start on, where the screen is at /. It is a screen for you, the developer of the app. An app with a feature whose route can start it, such as home, never shows it.
The screen shows, in the middle:
- The app as a cell of the periodic table, with smaller cells around it.
smf createmakes the symbol and the number of the cell from the name of the app,Maand 5 formy_app: the first letters of its first two words, or the first two letters of a name of one word, and how many letters and digits the name has. - The name of the app.
- A hint: "No start screen yet. Add a feature with a route, or replace this screen."
- The path of the file of the screen,
lib/core/app/fallback_start_screen.dart. A tap copies it, and a snack bar says so.
| Colors and fonts | The screen takes its colors and its text styles from the theme of the app, so it follows the theme mode. The path and the number of the cell are in the monospaced font of the device. |
| Motion | The screen comes in with a short fade, once. On a device that asks for less motion, it is there at once. |
| Large text | The screen scrolls when it is too small for what it shows. The letters of the cell keep their size, since the cell is a picture, and the path grows to at most one and a half times its size. |
| Screen readers | A screen reader passes over the cell, and announces the name of the app as a header and the path as a button. |
Its texts and the languages of the app
The hint and the word that the snack bar says before the path, Copied, are texts of the module, in English and in Ukrainian. In an app with a module that provides the localization, such as gen_l10n, they are the texts flutterCoreFallbackHint and flutterCoreFallbackCopied of the app, and the screen shows them in the language of the app. Without one, they are in English.
Every app has this module. So every app with a module that provides the localization has these two texts, and is in English and in Ukrainian unless --locales says otherwise, also an app without a feature; see Languages.
FallbackStartScreen only reads the two texts and gives them to FallbackStartView, which shows the rest. In an app with gen_l10n:
class FallbackStartScreen extends StatelessWidget {
/// Creates the screen.
const FallbackStartScreen({super.key});
Widget build(BuildContext context) => FallbackStartView(
hint: context.l10n.flutterCoreFallbackHint,
copied: context.l10n.flutterCoreFallbackCopied,
);
}
So the widget test of the app shows the view with texts of its own, and needs neither the root of the app nor its texts:
/// Shows the view of the fallback start screen with texts of the test.
Future<void> _show(WidgetTester tester) => tester.pumpWidget(
const MaterialApp(
home: FallbackStartView(hint: 'A hint', copied: 'Copied'),
),
);
The test checks that the view names the app and the file, that a tap copies the path, and that the view fits a small phone with the largest text size.
When the app has a start screen
The file and its test are in every app, also in one that starts on the screen of a feature, where nothing in lib/ shows the screen. There you can leave them as they are, or remove both, together with the two texts in an app with gen_l10n.
In an app that shows the screen, add a feature with a route that can start the app, or replace the screen with one of your own. The widget test is a test of FallbackStartView, so change it with the view, or remove it with the view.
Start-up phases
bootstrap() runs the start-up code that modules and roles add, in four phases, in this order:
| Phase | What goes there |
|---|---|
| early | Code that must come before anything else |
| platform | Platform services, such as await Firebase.initializeApp(...), installCrashReporting() and await initPreferences() |
| DI | The services of the app: await registerDependencies(); |
| late | Code that needs those services |
main() runs the root widget inside the wrappers that modules add, such as the ProviderScope of Riverpod. App builds below them, so an argument of the root MaterialApp can read an inherited widget among the wrappers from the BuildContext of App, and the root rebuilds when that widget notifies. The theme mode reaches the root this way.
Choosing it
Every app has a provider of the app entry role. While flutter_core is the only module that provides it, you don't choose it: smf create adds it by itself.
Requirements
The app needs Flutter 3.44 or newer and Dart 3.12 or newer, and runs on iOS 15 or newer. For iOS builds with Xcode 27, see troubleshooting.