Files
flutter__agent-plugins/resources/flutter_skills.yaml
2026-03-12 13:34:49 -07:00

1444 lines
90 KiB
YAML

# Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
# This is the configuration file for the skill generator.
# To generate skills, use the following command (from the `tool` directory):
# dart run skills generate-skill --config ../resources/flutter_skills.yaml --output ../skills
- name: flutter-environment-setup-linux
description: Set up a Linux environment for Flutter development
instructions: |
Setting up a Linux environment for app development involves configuring your
system to run, build, and deploy applications. This often includes
installing necessary tools and prerequisites.
For Flutter app development on Linux, you need to configure your development
environment to build Flutter apps for the Linux desktop. If you haven't
already, you should first set up Flutter by following the "Get started with
Flutter" guide, and ensure it's up to date. To run and debug desktop Flutter
apps on Linux, you'll need to download and install prerequisite packages.
These prerequisites can include `curl`, `git`, `unzip`, `xz-utils`, `zip`,
and `libglu1-mesa`. On Debian-based distributions like Ubuntu, these
packages can be installed using `sudo apt-get update -y && sudo apt-get
upgrade -y` followed by `sudo apt-get install -y curl git unzip xz-utils zip
libglu1-mesa`. For the best experience, consider installing an editor or IDE
with Flutter support. If you are developing on a Chromebook, you need to
turn on Linux support and ensure it's up to date.
resources:
- https://docs.flutter.dev/platform-integration/linux/setup
- https://docs.flutter.dev/platform-integration/android/setup
- https://docs.flutter.dev/install
- https://docs.flutter.dev/deployment/linux
- https://docs.flutter.dev/platform-integration/linux
- https://docs.flutter.dev/install/manual
- https://docs.flutter.dev/install/custom
- https://docs.flutter.dev/platform-integration/linux/building
- https://docs.flutter.dev/learn/pathway/quick-install
- name: flutter-environment-setup-macos
description: Set up a macOS environment for Flutter development
instructions: |
To set up a macOS environment for Flutter development, you need to configure
your development environment to run, build, and deploy Flutter applications
for macOS devices. This involves setting up tooling, validating your setup,
and then you can start developing for macOS.
First, ensure Flutter is installed and up to date. If you haven't installed
Flutter yet, you should follow the "Get started with Flutter" guide.
For tooling, you will need Xcode. Xcode allows you to run Flutter apps on
macOS and compile and debug native Swift and Objective-C code. Install the
latest version of Xcode, or update it if you already have it.
After setting up the tooling, validate your setup by running the `flutter
doctor` command in your terminal. This command checks for any issues with
your macOS development setup. If there are errors or tasks under the Xcode
section, resolve them and run `flutter doctor -v` again to verify the
changes. You should also run `flutter devices` to ensure Flutter can find
and connect to your macOS device. If everything is set up correctly, you
should see at least one entry with "macos" as the platform. If you encounter
any setup issues, you can refer to the "Install and setup troubleshooting"
guide or reach out to the Flutter community channels.
Once your macOS desktop development for Flutter is set up, you can continue
your Flutter learning journey, test on macOS, or begin expanding integration
with macOS. You can also build and deploy to macOS, bind to native macOS
code, embed native macOS views, set up app flavors, and use Swift Package
Manager. Flutter supports building macOS apps. You can also host a native
macOS view and bind to native code.
resources:
- https://docs.flutter.dev/platform-integration/macos/setup
- https://docs.flutter.dev/install/add-to-path
- https://docs.flutter.dev/install/troubleshoot
- https://docs.flutter.dev/install
- https://docs.flutter.dev/install/quick
- https://docs.flutter.dev/platform-integration/ios/setup
- https://docs.flutter.dev/platform-integration/macos
- name: flutter-environment-setup-windows
description: Set up a Windows environment for Flutter development
instructions: |
To set up a Windows environment for app development, particularly with
Flutter, several steps are involved.
First, you need to install Flutter itself. If you haven't downloaded
Flutter, you should follow the "Get started with Flutter" guide. If Flutter
is already installed, ensure it's up to date. After downloading the Flutter
SDK, you must add its `bin` directory to your system's PATH environment
variable to use `flutter` and `dart` command-line tools in terminals and
IDEs. On Windows, this involves copying the absolute path to the Flutter
SDK's directory and navigating to the environment variables settings.
Next, you'll need to set up tooling. For Windows development with Flutter,
Visual Studio is required. Visual Studio allows you to run Flutter apps on
Windows and compile and debug native C and C++ code. It's important to note
that Visual Studio is a separate IDE from Visual Studio Code and is only
supported on Windows. If you haven't installed Visual Studio, follow
Microsoft's guide; otherwise, update it to the latest version.
You can also set up Flutter support in various IDEs and editors, such as VS
Code, Android Studio, IntelliJ, and Firebase Studio.
After installing Flutter and setting up tooling, you need to set up
development for at least one target platform. While web development is
recommended first as it requires no additional setup beyond a browser, you
can set up development for other platforms later. For Windows desktop
development, you specifically configure your environment to run, build, and
deploy Flutter apps for the Windows desktop platform.
If you are developing for Android on Windows, you'll need to configure your
development environment to run, build, and deploy Flutter apps for Android
devices. This includes setting up Android tooling and an Android device. For
physical Android devices, you need to enable Developer options and USB
debugging, and install the necessary USB driver for your device. You can
also enable wireless debugging. For emulated performance, you should enable
hardware acceleration by selecting an option that mentions "Hardware" in the
Graphics acceleration dropdown menu under "Emulated Performance" in
Additional settings. After configuring, you can verify your virtual device
and run the emulator.
To build a zip file for Windows, you'll find the Flutter executable (`.exe`)
in your project under `build\windows\runner\<build mode>\`. In addition to
the executable, you'll need all the `.dll` files from the same directory and
the `data` directory. The Visual C++ redistributables are also necessary,
and you can use methods from Microsoft's deployment example walkthroughs to
ensure end-users have them.
For certain functionalities, like generating certificates, you might need
OpenSSL. You can set an environment variable for OpenSSL and then use
commands to generate a private key, a certificate signing request (CSR)
file, a signed certificate (CRT) file, and a `.pfx` file. The `.pfx`
certificate needs to be installed on the local machine in the Certificate
store as "Trusted Root Certification Authorities" before installing the app.
After enabling desktop support, you should restart your IDE so it can detect
the new device. When creating a new project with desktop support, it will
automatically create iOS, Android, web, and desktop versions of your app. If
`flutter doctor` finds problems for platforms you don't intend to develop
for, you can ignore the warnings or disable the platform using `flutter
config` commands, such as `--no-enable-windows-desktop`.
resources:
- https://docs.flutter.dev/install
- https://docs.flutter.dev/install/add-to-path
- https://docs.flutter.dev/install/manual
- https://docs.flutter.dev/install/custom
- https://docs.flutter.dev/install/troubleshoot
- https://docs.flutter.dev/platform-integration/windows/building
- https://docs.flutter.dev/platform-integration/windows/setup
- https://docs.flutter.dev/tools/vs-code
- name: flutter-architecture
description: Build an app using the Flutter team's recommended app architecture
instructions: |
Architecture is a broad term that can refer to many topics depending on the
context. In the context of Flutter, architecture refers to how to structure,
organize, and design your Flutter app to scale as project requirements and
teams grow. It is an important part of building a maintainable, resilient,
and scalable Flutter app. This guide covers app architecture principles and
best practices for building Flutter apps.
Good app architecture provides several benefits to engineering teams and end
users. It makes it easier to modify, update, and fix issues over time
(maintainability). A well-thought-out application allows more people to
contribute to the same codebase concurrently with minimal code conflicts
(scalability).
Common architectural principles include separation of concerns, layered
architecture, single source of truth, unidirectional data flow, UI as a
function of (immutable) state, extensibility, and testability.
Flutter applications should be written in layers. Layered architecture is a
software design pattern that organizes an application into distinct layers,
each with specific roles and responsibilities. Typically, applications are
separated into 2 to 3 layers, depending on complexity. The three common
layers of app architecture are the UI layer, logic layer, and data layer.
* **UI layer** (also known as the 'presentation layer') displays data to
the user that is exposed by the business logic layer and handles user
interaction. In Flutter, this applies to widgets, which are the basic
building blocks of a Flutter user interface. You should
write reusable, lean widgets that hold as little logic as possible.
* **Logic layer** (commonly known as the 'domain layer') implements core
business logic and facilitates interaction between the data layer and UI
layer. This layer is optional and only needs to be implemented if your
application has complex business logic that happens on the client. Many
apps are only concerned with presenting data to a user and allowing the
user to change that data (colloquially known as CRUD apps).
* **Data layer** (known as the model in MVVM terminology) is the source of
truth for all application data. It handles business data and logic. As
the source of truth, it's the only place that application data should be
updated. It is responsible for consuming data from various external
APIs, exposing that data to the UI, handling events from the UI that
require data to be updated, and sending update requests to those
external APIs as needed. The data layer typically has two main
components: repositories and services.
* **Repositories** are the source of truth for your model data. They
contain logic related to that data, such as updating data in
response to user events or polling for data from services.
Repositories are responsible for synchronizing data when offline
capabilities are supported, managing retry logic, and caching data.
They transform raw data into domain models, which represent the data
the application needs, formatted for consumption by view model
classes.
* **Services** are stateless Dart classes that interact with APIs,
such as HTTP servers and platform plugins. Their only job is to wrap
an external API. Any data your application needs that isn't created
inside the application code itself should be fetched from within
service classes. There is generally one service class per data
source.
Within each layer, you should further separate your application by feature
or functionality. For example, your application's authentication logic
should be in a different class than the search logic.
The Flutter team's recommended app architecture includes common
architectural principles, MVVM and state management, dependency injection,
and common design patterns for writing robust Flutter applications.
resources:
- https://docs.flutter.dev/app-architecture
- https://docs.flutter.dev/app-architecture/concepts
- https://docs.flutter.dev/app-architecture/guide
- https://docs.flutter.dev/resources/architectural-overview
- https://docs.flutter.dev/app-architecture/recommendations
- https://docs.flutter.dev/app-architecture/design-patterns
- https://docs.flutter.dev/app-architecture/case-study
- https://docs.flutter.dev/app-architecture/case-study/data-layer
- https://docs.flutter.dev/app-architecture/design-patterns/key-value-data
- https://docs.flutter.dev/learn/pathway/how-flutter-works
- name: flutter-layout
description: How to build your app's layout using Flutter's layout widgets and constraint system
instructions: |
In Flutter, almost everything is a widget, including layout models. Widgets
are classes used to build user interfaces (UIs) and UI elements. Visible
elements like images, icons, and text are widgets, as are invisible elements
like rows, columns, and grids that arrange, constrain, and align visible
widgets. Layouts are created by composing simpler widgets to build more
complex ones.
Understanding constraints is crucial for Flutter layout, as layout generally
refers to the size and position of widgets on the screen. A widget's size
and position are constrained by its parent, meaning it cannot choose its own
size or placement. Instead, these are determined through a conversation
between the widget and its parent.
When building a Flutter layout, it's helpful to plan the layout beforehand
to speed up coding. This can involve using visual cues, an interface design
tool, or even a pencil and paper to determine where elements should be
placed on the screen before writing code. Key questions to ask when breaking
down a layout include identifying rows, columns, grids, overlapping
elements, tabs, and what needs alignment, padding, or borders. Identifying
larger elements, such as an image, rows, and text blocks, is also important.
Common layout patterns involve arranging widgets vertically or horizontally.
A `Row` widget arranges widgets horizontally, while a `Column` widget
arranges them vertically. Both `Row` and `Column` widgets take a list of
child widgets, and these children can themselves be other `Row`, `Column`,
or complex widgets. You can specify how `Row` or `Column` widgets align
their children, both vertically and horizontally, and how child widgets use
the available space. Nesting rows and columns inside each other is a common
practice. The `Container` widget is a versatile widget that allows
customization of its child, such as adding padding, margins, borders, or
background colors.
Flutter's layout mechanism aims to enable the development of apps from a
single codebase that look and feel great on any platform, accommodating
various screen sizes and input devices. This involves concepts of adaptive
and responsive design. Responsive design focuses on fitting the UI into the
available space by adjusting the placement of design elements, while
adaptive design ensures the UI is usable within that space.
resources:
- https://docs.flutter.dev/ui/layout
- https://docs.flutter.dev/ui/layout/tutorial
- https://docs.flutter.dev/get-started/fundamentals/layout
- https://docs.flutter.dev/ui/design/material
- https://docs.flutter.dev/learn/tutorial/layout
- https://docs.flutter.dev/ui/adaptive-responsive
- https://docs.flutter.dev/learn/tutorial/adaptive-layout
- https://docs.flutter.dev/ui/layout/constraints
- https://docs.flutter.dev/ui/widgets/layout
- https://docs.flutter.dev/learn/pathway/tutorial/layout
- name: flutter-theming
description: How to customize your app's theme using Flutter's theming system
instructions: |
Theming involves sharing colors and font styles throughout an app. You can
define app-wide themes and extend a theme to change a theme style for one
component. Each theme defines colors, type style, and other parameters
applicable for the type of Material component. Flutter applies styling in a
specific order: styles applied to the specific widget, themes that override
the immediate parent theme, and finally, the main theme for the entire app.
As of Flutter 3.16, Material 3 is Flutter's default theme.
Component theme normalization is a process where themes like `CardTheme`,
`DialogTheme`, and `TabBarTheme` have been refactored to conform to
Flutter's conventions for component themes in the Material library. This
normalization aims for a more consistent theming experience.
`CardThemeData`, `DialogThemeData`, and `TabBarThemeData` were added to
define overrides for the defaults of the component visual properties. In
`ThemeData`, the type of the `cardTheme` property has changed from
`CardTheme` to `CardThemeData`. During card theme normalization, the type of
`ThemeData.cardTheme` was changed to `Object?` to accept both `CardTheme`
and `CardThemeData` for a smooth transition.
New button widgets and themes have been introduced to align with the
Material Design spec and to make buttons more flexible and easier to
configure. The original `FlatButton`, `RaisedButton`, and `OutlineButton`
widgets have been replaced by `TextButton`, `ElevatedButton`, and
`OutlinedButton` respectively. Each new button class has its own theme:
`TextButtonTheme`, `ElevatedButtonTheme`, and `OutlinedButtonTheme`. The
original `ButtonTheme` class is no longer used. The appearance of these new
buttons is specified by a `ButtonStyle` object, which is a collection of
visual properties, many of which can depend on the button's state through
`MaterialStateProperty`. These new themes follow a "normalized" pattern
where theme properties and widget constructor parameters are null by
default, and non-null values override the component's default. The defaults
are based primarily on the overall `Theme`'s `colorScheme` and `textTheme`.
When considering theming for adaptive apps, it's important to consider
platform standards, idioms, and norms, as these inform user expectations.
Reflecting these standards can reduce cognitive load and build user trust.
It's beneficial to envision the ideal user experience for each platform and
consider how a user of that platform would expect to achieve a goal.
Assigning a platform advocate for each platform can provide constant,
informed feedback to ensure the app feels great on each platform. While
conforming to expected behaviors, an app doesn't need to use default
components or styling; many popular multiplatform apps have distinct UIs.
Consolidating styling and behavior across platforms can simplify development
and testing.
resources:
- https://docs.flutter.dev/cookbook/design/themes
- https://docs.flutter.dev/release/breaking-changes/component-theme-normalization
- https://docs.flutter.dev/release/breaking-changes/buttons
- https://docs.flutter.dev/release/breaking-changes/component-theme-normalization-updates
- https://docs.flutter.dev/release/breaking-changes/theme-data-accent-properties
- https://docs.flutter.dev/release/breaking-changes/material-theme-system-updates
- https://docs.flutter.dev/ui/design
- https://docs.flutter.dev/release/breaking-changes/appbar-theme-color
- https://docs.flutter.dev/ui/widgets/styling
- https://docs.flutter.dev/release/breaking-changes/material-3-migration
- https://docs.flutter.dev/cookbook/design/themes
- https://docs.flutter.dev/release/breaking-changes/component-theme-normalization
- https://docs.flutter.dev/release/breaking-changes/buttons
- https://docs.flutter.dev/release/breaking-changes/theme-data-accent-properties
- https://docs.flutter.dev/ui/design
- https://docs.flutter.dev/release/breaking-changes/component-theme-normalization-updates
- https://docs.flutter.dev/release/breaking-changes/material-theme-system-updates
- https://docs.flutter.dev/release/breaking-changes/material-3-migration
- https://docs.flutter.dev/release/breaking-changes/material-3-default
- https://docs.flutter.dev/release/breaking-changes/appbar-theme-color
- https://docs.flutter.dev/cookbook/design/themes
- https://docs.flutter.dev/ui/adaptive-responsive/idioms
- https://docs.flutter.dev/ui
- name: flutter-form
description: Build a form with validation
instructions: |
To build a form with validation, you need to create a `Form` widget with a
`GlobalKey`. This `GlobalKey` uniquely identifies the `Form` widget and
allows for validation later. It's recommended to create the form as a
`StatefulWidget` to store the `GlobalKey<FormState>()` once, as generating a
new `GlobalKey` each time the `build` method runs is resource-expensive. The
`Form` widget acts as a container for grouping and validating multiple form
fields. While a `GlobalKey` is the recommended way to access a form,
`Form.of()` can be used in more complex widget trees.
Next, add a `TextFormField` with validation logic. The `TextFormField`
widget renders a material design text field and can display validation
errors. Input validation is done by providing a `validator()` function to
the `TextFormField`. If the user's input is invalid, the `validator`
function should return a `String` containing an error message. If there are
no errors, the `validator` must return `null`. For example, a validator can
ensure the `TextFormField` isn't empty by returning a message like 'Please
enter some text' if the value is null or empty, otherwise returning null.
`TextFormField` is a convenience widget that pre-wraps a `TextField` in a
`FormField`. Each individual form field should be wrapped in a `FormField`
widget with the `Form` widget as a common ancestor.
Finally, create a button to validate and submit the form. When the user
attempts to submit the form, you check if the form is valid. To validate the
form, use the `_formKey` created earlier. The `_formKey.currentState`
accessor provides access to the `FormState`, which is automatically created
by Flutter when building a `Form`. The `FormState` class contains the
`validate()` method. When `validate()` is called, it runs the `validator()`
function for each text field in the form. If all validations pass,
`validate()` returns `true`. If any text field contains errors, `validate()`
rebuilds the form to display error messages and returns `false`. If the form
is valid, you can display a success message (e.g., a `SnackBar`). If it's
not valid, the error messages from the `TextFormField` validators will be
displayed. The `FormState` also allows you to save, reset, and validate each
`FormField` that descends from the `Form`.
resources:
- https://docs.flutter.dev/ai-best-practices/developer-experience
- https://docs.flutter.dev/app-architecture/recommendations
- https://docs.flutter.dev/cookbook/forms
- https://docs.flutter.dev/cookbook/forms/text-input
- https://docs.flutter.dev/cookbook/forms/validation
- https://docs.flutter.dev/flutter-for/react-native-devs
- https://docs.flutter.dev/flutter-for/xamarin-forms-devs
- https://docs.flutter.dev/get-started/fundamentals/user-input
- https://docs.flutter.dev/release/breaking-changes/form-field-autovalidation-api
- https://docs.flutter.dev/ui/adaptive-responsive/best-practices
- https://docs.flutter.dev/ui/interactivity/input
- name: flutter-routing-and-navigation
description: Move between or deep link to different screens or routes within a Flutter application
instructions: |
Routing and navigation involve moving between different screens or "routes"
within an application. In Flutter, screens and pages are referred to as
routes. This concept is similar to an Activity in Android or a
ViewController in iOS, but in Flutter, a route is simply a widget.
A key aspect of navigation is deep linking, which allows an app to open
directly to a specific location or "deep" inside the app when a URL is
received. For example, a deep link from an advertisement could open a
shopping app to a specific product page. Flutter supports deep linking on
iOS, Android, and the web. When running an app in a web browser, no
additional setup is required for deep linking. While named routes can be
used for deep linking, they are generally not recommended for most
applications. The `Router` widget can also be used for deep linking.
Common navigation tasks include navigating to a new screen and returning to
the previous one. This can be achieved using `Navigator.push()` to go to a
new route and `Navigator.pop()` to return to the previous route. Other
navigation functionalities include adding tabs to an app, sending data to a
new screen, returning data from a screen, and adding a drawer to a screen.
It's also possible to create nested navigation flows.
For more in-depth information on navigation and routing, resources like the
Flutter cookbook offer multiple navigation recipes that demonstrate how to
use the `Navigator`. The `Navigator` and `Router` API documentation provide
details on setting up declarative navigation without needing a routing
package. Additionally, the Material Design documentation offers insights
into designing app navigation, covering concepts like forward, upward, and
chronological navigation. An article on Medium describes how to use the
`Router` widget directly. The `Router` design document explains the
motivation and design of the `Router` API. A sample demonstrating how to use
`go_router` API for common navigation scenarios is also available.
resources:
- https://docs.flutter.dev/ui/navigation
- https://docs.flutter.dev/cookbook/navigation/navigation-basics
- https://docs.flutter.dev/cookbook/navigation/named-routes
- https://docs.flutter.dev/cookbook/effects/nested-nav
- https://docs.flutter.dev/cookbook/navigation/navigate-with-arguments
- https://docs.flutter.dev/ui/navigation/deep-linking
- https://docs.flutter.dev/learn/tutorial/navigation
- https://docs.flutter.dev/learn/pathway/tutorial/navigation
- https://docs.flutter.dev/cookbook/navigation
- https://docs.flutter.dev/cookbook/navigation/passing-data
- https://docs.flutter.dev/cookbook/navigation/navigate-with-arguments
- https://docs.flutter.dev/ui/navigation
- https://docs.flutter.dev/learn/pathway/tutorial/navigation
- https://docs.flutter.dev/cookbook/effects/nested-nav
- https://docs.flutter.dev/cookbook/navigation/navigate-with-arguments
- https://docs.flutter.dev/cookbook/navigation/named-routes
- https://docs.flutter.dev/cookbook/navigation/passing-data
- https://docs.flutter.dev/resources/glossary/index.html.md
- name: flutter-animation
description: Add animated effects to your Flutter app
instructions: |
Animation is a broad topic that encompasses various types and patterns,
often implemented using a system based on typed `Animation` objects.
Generally, animations are categorized as either tween-based or
physics-based. In a tween animation, the beginning and ending points, a
timeline, and a curve defining timing and speed are all defined, and the
framework calculates the transition. Physics-based animation, on the other
hand, models motion to resemble real-world behavior, such as how a tossed or
dropped ball would move.
Common animation patterns include animated lists or grids, shared element
transitions, and staggered animations. An animated list or grid involves
animating the addition or removal of elements. Shared element transitions,
also known as hero animations, occur when a user selects an element, and the
UI animates that element to a new page with more detail. Hero animations can
involve the element flying between routes while changing position and size,
or its shape transforming, for example, from circular to rectangular.
Staggered animations are broken into smaller motions, with some of the
motion delayed.
The animation system in Flutter is built upon typed `Animation` objects.
Widgets can either directly incorporate these animations by reading their
current value and listening to state changes, or they can use them as a
basis for more elaborate animations passed to other widgets. An `Animation`
object is an abstract class that understands its current value and state
(completed or dismissed). It knows nothing about what is onscreen,
rendering, or `build()` functions. A common type is `Animation<double>`,
which sequentially generates interpolated numbers between two values over a
duration, with output that can be linear, curved, or a step function.
Animations can also interpolate other types like `Animation<Color>` or
`Animation<Size>`. The current value of an `Animation` object is always
available in its `.value` member. When an animation's value changes, it
notifies all listeners added with `addListener`.
`Tween<T>` is an abstract class that maps a double value, typically in the
range 0.0-1.0, to a typed value such as a `Color` or another double. Tweens
are stateless and immutable, having a notion of an output type, a beginning
and end value, and a way to interpolate between them. The `Curve` abstract
class maps doubles, also nominally in the range 0.0-1.0, to other doubles in
the same range, and `Curve` classes are also stateless and immutable.
Flutter offers implicit animations as a simple way to implement animations.
Implicit animations are a group of widgets that automatically animate
changes to their properties without requiring manual management of
intermediate behavior. An example of a versatile implicit animation widget
is `AnimatedContainer`.
resources:
- https://docs.flutter.dev/ui/animations
- https://docs.flutter.dev/ui/animations/overview
- https://docs.flutter.dev/ui/animations/tutorial
- https://docs.flutter.dev/learn/pathway/tutorial/implicit-animations
- https://docs.flutter.dev/learn/tutorial/implicit-animations
- https://docs.flutter.dev/ui/widgets/animation
- https://docs.flutter.dev/ui/animations/staggered-animations
- https://docs.flutter.dev/cookbook/animation/page-route-animation
- https://docs.flutter.dev/cookbook/animation/animated-container
- https://docs.flutter.dev/ui/animations/hero-animations
- https://docs.flutter.dev/ui/animations
- https://docs.flutter.dev/ui/animations/overview
- https://docs.flutter.dev/ui/animations/tutorial
- https://docs.flutter.dev/learn/pathway/tutorial/implicit-animations
- https://docs.flutter.dev/learn/tutorial/implicit-animations
- https://docs.flutter.dev/ui/animations/staggered-animations
- https://docs.flutter.dev/cookbook/animation/animated-container
- https://docs.flutter.dev/cookbook/animation/page-route-animation
- https://docs.flutter.dev/ui/animations/hero-animations
- https://docs.flutter.dev/cookbook/animation/physics-simulation
- https://docs.flutter.dev/ui/animations
- https://docs.flutter.dev/ui/animations/overview
- https://docs.flutter.dev/ui/animations/tutorial
- https://docs.flutter.dev/learn/pathway/tutorial/implicit-animations
- https://docs.flutter.dev/learn/tutorial/implicit-animations
- https://docs.flutter.dev/ui/animations/staggered-animations
- https://docs.flutter.dev/cookbook/animation/animated-container
- https://docs.flutter.dev/cookbook/animation/page-route-animation
- https://docs.flutter.dev/cookbook/animation/animated-container
- https://docs.flutter.dev/ui/widgets/animation
- https://docs.flutter.dev/cookbook/animation/page-route-animation
- name: flutter-localization
description: Configure your Flutter app to support different languages and regions
instructions: |
Localization in Flutter involves adapting an app to different languages and
regions. By default, Flutter only supports US English for its strings. To add
support for other languages, you need to include the `flutter_localizations`
package. You might also need Dart's `intl` package for internationalization
(i10n) features like date/time formatting.
When a `WidgetsApp` or `MaterialApp` is initialized, it creates a
`Localizations` widget with specified delegates. The device's current locale
is always accessible from the `Localizations` widget via a `Locale` object or
`Window.locale`. To access localized resources, you use the
`Localizations.of()` method to get a specific localizations class provided by
a delegate. The `intl_translation` package can be used to extract
translatable copy into `.arb` files for translation and then import them back
into the app for use with `intl`.
To set up an internationalized app, you add `flutter_localizations` and
`intl` as dependencies in your `pubspec.yaml` file. Then, you import the
`flutter_localizations` library and specify `localizationsDelegates` and
`supportedLocales` for your `MaterialApp` or `CupertinoApp`. For example, you
would include `GlobalMaterialLocalizations.delegate`,
`GlobalWidgetsLocalizations.delegate`, and
`GlobalCupertinoLocalizations.delegate` in `localizationsDelegates`. You also
define the `supportedLocales`, such as `Locale('en')` for English and
`Locale('es')` for Spanish. After this setup, Material and Cupertino packages
should be correctly localized, and widgets should adapt to localized messages
and layout (e.g., left-to-right or right-to-left).
The `Localizations` widget is crucial for loading and looking up objects
containing collections of localized values. Apps refer to these objects using
`Localizations.of(context, type)`. If the device's locale changes, the
`Localizations` widget automatically loads values for the new locale and
rebuilds dependent widgets. This behavior is similar to an `InheritedWidget`.
The `WidgetsApp` widget creates a `Localizations` widget and rebuilds it if
the system's locale changes. You can always find an app's current locale
using `Localizations.localeOf(context)`.
Some widgets, like `TextField`, require a `MaterialLocalizations` widget in
the widget tree. If `MaterialLocalizations` is not present, `TextField` will
throw an assertion error. You can introduce `MaterialLocalizations` by using
a `MaterialApp` at the root of your application, which includes them
automatically, or by adding a `Localization` widget with a
`MaterialLocalizations` delegate.
For iOS, even though Flutter handles localizations, you need to add the
supported languages in the Xcode project. This ensures that your app's entry
in the App Store correctly displays the supported languages. You can
configure supported locales by opening your project's `ios/Runner.xcodeproj`
file in Xcode, selecting the `Runner` project file, and then the `Info` tab.
In the `Localizations` section, you click the Add button to add supported
languages and regions. Xcode will then create empty `.strings` files and
update the `ios/Runner.xcodeproj/project.pbxproj` file, which the App Store
uses to determine supported languages.
Advanced locale definition might be necessary for languages with multiple
variants, such as Chinese, which requires specifying language code, script
code, and country code to differentiate between simplified and traditional
script, and regional differences. Similarly, other languages like French
(fr_FR, fr_CA) should be fully differentiated for nuanced localization. The
`Locale` class identifies the user's language, and internationalized apps
respond by displaying locale-specific values.
resources:
- https://docs.flutter.dev/release/breaking-changes/cupertino-tab-bar-localizations
- https://docs.flutter.dev/ui/internationalization
- https://docs.flutter.dev/release/breaking-changes/flutter-generate-i10n-source
- https://docs.flutter.dev/release/breaking-changes/material-localized-strings
- https://docs.flutter.dev/release/breaking-changes/text-field-material-localizations
- name: flutter-accessibility
description: Configure your Flutter app to support assistive technologies like Screen Readers
instructions: |
Accessibility is crucial for building high-quality applications that can be
used by a broad range of users. Poorly designed applications create barriers
for people of all ages. There is a moral and legal imperative to ensure
universal access to information systems, as stated by the UN Convention on
the Rights of Persons with Disabilities. Many countries enforce accessibility
as a requirement, and companies recognize the business advantages of
maximizing access to their services. It is strongly encouraged to include an
accessibility checklist as a key criterion before shipping an app.
Accessibility standards and regulations help ensure products are accessible
to people with disabilities. Many of these have been enacted into laws and
policies, making them requirements for products and services. Flutter
supports developers in making their apps more accessible by providing
first-class framework support for accessibility, in addition to what the
underlying operating system offers. This support includes UI Design and
styling, and Assistive Technologies like Screen Readers.
To create an accessible app, UI design should consider accessibility. Key
aspects of accessible UI design and styling include large fonts, sufficient
contrast, and appropriate tap target sizes. Flutter text widgets respect the
operating system's font size settings, calculating font sizes automatically
based on the OS setting. Developers should ensure their layout has enough
room to render all its contents when font sizes are increased. Sufficient
color contrast makes text and images easier to read, benefiting users with
visual impairments and all users in extreme lighting conditions. The W3C
recommends a contrast ratio of at least 4.5:1 for small text and 3.0:1 for
large text.
Flutter provides a catalog of accessibility widgets to help make apps
accessible. These include `ExcludeSemantics`, which drops the semantics of
its descendants, `MergeSemantics`, which merges the semantics of its
descendants, and `Semantics`, which annotates the widget tree with a
description of the meaning of widgets for accessibility tools.
For web accessibility, Flutter renders its UI on a single canvas, requiring a
special layer to expose the UI's meaning and structure to web browsers.
Flutter's web accessibility is not on by default for performance reasons.
Users can enable it by pressing an invisible button with `aria-label="Enable
accessibility"`, which then reflects accessibility information in the DOM
tree. Alternatively, accessibility mode can be turned on in code by adding
`SemanticsBinding.instance.ensureSemantics();` when running the app. Semantic
roles define the purpose of a UI element, helping screen readers and other
assistive tools interpret and present the application effectively. These
roles can indicate if a widget is a button, link, heading, slider, or part of
a table. While standard Flutter widgets often provide semantics
automatically, custom components may need explicit role assignment to be
comprehensible to screen reader users. Flutter provides the `Semantics`
widget with the `SemanticsRole` enum to assign specific roles to widgets.
These Flutter-specific roles are translated into corresponding ARIA roles in
the web page's HTML structure. Using standard widgets like `TabBar`,
`MenuAnchor`, and `Table` is preferred as they handle many accessibility
aspects out-of-the-box. For custom components or when default semantics are
insufficient, the `Semantics` widget can be used to define or override roles.
Adaptive design is about the UI being usable in the space, while responsive
design is about fitting the UI into the space. An adaptive app selects the
appropriate layout (e.g., bottom nav instead of side panel) and input devices
(e.g., mouse vs. touch) to feel natural on the current device. Responsive
design adjusts the placement of design elements to fit the available space.
Flutter aims to create a framework that allows apps from a single codebase to
look and feel great on any platform, accommodating various screen sizes and
input devices. It's important to design to the strengths of each form factor,
considering whether to focus on specific capabilities or even remove features
on certain device categories.
resources:
- https://docs.flutter.dev/ui/accessibility/assistive-technologies
- https://docs.flutter.dev/ui/accessibility/accessibility-testing
- https://docs.flutter.dev/release/breaking-changes/tooltip-semantics-order
- https://docs.flutter.dev/ui/widgets/accessibility
- https://docs.flutter.dev/accessibility-and-localization/accessibility
- https://docs.flutter.dev/ui/accessibility
- https://docs.flutter.dev/ui/adaptive-responsive
- https://docs.flutter.dev/ui/adaptive-responsive/best-practices
- https://docs.flutter.dev/ui/accessibility/ui-design-and-styling
- https://docs.flutter.dev/ui/adaptive-responsive/input
- https://docs.flutter.dev/ui/accessibility/web-accessibility
- https://docs.flutter.dev/resources/glossary
- name: flutter-state-management
description: Manage state in your Flutter application
instructions: |
State management in Flutter refers to how an app organizes its objects to
effectively access them and share them between different widgets. State is
information that can be read synchronously when a widget is built or
information that might change during the lifetime of a widget. Flutter's UI
is built to reflect the current state of the app, meaning that when state
changes, the app should trigger a rebuild of the UI that depends on that
state. This concept is often described as "UI is a function of state".
There are various approaches to state management in Flutter. A fundamental
concept is the distinction between `StatelessWidget` and `StatefulWidget`. A
`StatelessWidget` does not require a state change and has no internal state
to manage. Examples include `AboutDialog`, `CircleAvatar`, and `Text`. Its
`build` method is typically called when the widget is inserted into a tree,
when its parent changes its configuration, or when an `InheritedWidget` it
depends on changes. In contrast, a `StatefulWidget` is a widget that changes
state. If a widget's unique characteristics need to change based on user
interaction or other factors, it is stateful. `StatefulWidget`s store
mutable state in a separate class that subclasses `State`. To signal to the
framework that its internal state has changed, `setState()` must be called.
Calling `setState()` marks the widget as dirty and schedules it to be
rebuilt. If `setState()` is not called when modifying the internal state,
the UI might not update.
For sharing state between widgets, common patterns include using widget
constructors (also known as "prop drilling"), `InheritedWidget` (or similar
APIs like the `provider` package), and callbacks to notify a parent widget
of changes. `InheritedWidget` is a low-level approach used for communication
between ancestors and children in the widget tree. It includes an
`updateShouldNotify()` method that Flutter calls to determine if a state
change should trigger a rebuild of child widgets. Flutter itself extensively
uses `InheritedWidget` for shared state, such as the application's visual
theme. The `provider` package is a utility package that provides a wrapper
around `InheritedWidget`.
As applications grow, more advanced state management approaches become
attractive. Community-provided packages can help reduce boilerplate code,
provide debugging tools, and enable a clearer application architecture. The
best choice of package depends on the app's complexity, team preferences,
and specific problems.
The Model-View-ViewModel (MVVM) design pattern is often used with reactive
frameworks like Flutter. In MVVM, the `ViewModel` manages the UI state and
the `View` displays that state. `ViewModels` contain the logic to convert
app data into UI State, as data from repositories might be formatted
differently from what needs to be displayed. `ViewModels` use Flutter's
`ChangeNotifier` class to notify the UI when data changes. Extending
`ChangeNotifier` provides access to the `notifyListeners()` method, which
triggers UI rebuilds when called. The `Model` in MVVM is typically a Dart
class that handles low-level tasks like HTTP requests, data caching, or
managing system resources.
Flutter's architectural overview also highlights the concept of
unidirectional data flow (UDF). In UDF, state flows from the data layer
through the logic layer to the UI layer, while events from user interaction
flow in the opposite direction. The UI layer handles user events, which
invoke methods in the logic layer. The logic layer then calls methods in the
data layer (repositories) to mutate data. The data layer updates the data
and provides it back to the logic layer, which then sends its new state to
the UI for display. The key idea is that data changes always happen in the
Single Source of Truth (SSOT), which is the data layer. This makes code
easier to understand and less error-prone.
resources:
- https://docs.flutter.dev/app-architecture/concepts
- https://docs.flutter.dev/app-architecture/design-patterns
- https://docs.flutter.dev/app-architecture/design-patterns/optimistic-state
- https://docs.flutter.dev/app-architecture/guide
- https://docs.flutter.dev/app-architecture/recommendations
- https://docs.flutter.dev/data-and-backend/state-mgmt
- https://docs.flutter.dev/data-and-backend/state-mgmt/declarative
- https://docs.flutter.dev/data-and-backend/state-mgmt/ephemeral-vs-app
- https://docs.flutter.dev/data-and-backend/state-mgmt/intro
- https://docs.flutter.dev/data-and-backend/state-mgmt/options
- https://docs.flutter.dev/data-and-backend/state-mgmt/simple
- https://docs.flutter.dev/get-started/flutter-for/react-native-devs
- https://docs.flutter.dev/get-started/fundamentals/local-caching
- https://docs.flutter.dev/get-started/fundamentals/state-management
- https://docs.flutter.dev/learn/pathway
- https://docs.flutter.dev/learn/pathway/tutorial/change-notifier
- https://docs.flutter.dev/learn/tutorial/change-notifier
- https://docs.flutter.dev/perf/isolates
- https://docs.flutter.dev/resources/architectural-overview
- https://docs.flutter.dev/ui
- name: flutter-http-and-json
description: Make HTTP requests and encode / decode JSON in a Flutter app
instructions: |
HTTP and JSON are fundamental for networking and data handling in
applications.
**HTTP (Hypertext Transfer Protocol)**
HTTP is used for networking, allowing applications to fetch, send, update,
and delete data over the internet. The `http` package provides a simple way
to issue HTTP requests. This package is supported across various platforms
including Android, iOS, macOS, Windows, Linux, and the web. When making HTTP
requests, it's crucial to handle network errors; a status code of 200
typically indicates success, while other codes signify errors. For Android
apps, declaring internet usage in the `AndroidManifest.xml` is required.
Similarly, macOS apps need to allow network access in their `.entitlements`
files.
Common HTTP operations include fetching data from an API, making
authenticated requests, sending data, updating data, and deleting data. When
building HTTP requests, it's recommended to use constructors like
`Uri.https` to safely build URLs, as this handles encoding and formatting
more reliably than string concatenation. Asynchronous operations in HTTP
requests are managed using `async` and `await` keywords, where `async` marks
a method as asynchronous and `await` pauses execution until a `Future`
completes.
**JSON (JavaScript Object Notation)**
JSON is a lightweight data-interchange format often used with HTTP requests
for sending and receiving structured data. Applications frequently parse
JSON in the background. When a server returns a 200 OK response, the JSON
data can be parsed. For example, a `Summary` instance can be created from a
JSON map using a `fromJson` constructor. Similarly, an `ImageFile` can be
deserialized from JSON.
Reliable JSON output is essential for integrating AI into applications. When
working with AI models, you can specify the output schema in the system
instruction to ensure reliable JSON output. This allows for parsing the
model's text response as JSON and extracting specific data fields like
width, height, grid data, and clues data. JSON serialization is a key aspect
of data handling. For instance, when updating data over the internet, the
request body can be encoded into JSON using `jsonEncode`. Conversely,
`jsonDecode` is used to parse the JSON response body.
resources:
- https://docs.flutter.dev/ai/best-practices/structure-output
- https://docs.flutter.dev/cookbook/networking/background-parsing
- https://docs.flutter.dev/cookbook/networking/delete-data
- https://docs.flutter.dev/cookbook/networking/fetch-data
- https://docs.flutter.dev/cookbook/networking/send-data
- https://docs.flutter.dev/cookbook/networking/update-data
- https://docs.flutter.dev/data-and-backend/networking
- https://docs.flutter.dev/data-and-backend/serialization/json
- https://docs.flutter.dev/flutter-for/react-native-devs
- https://docs.flutter.dev/get-started/fundamentals/dart
- https://docs.flutter.dev/get-started/fundamentals/index.html.md
- https://docs.flutter.dev/get-started/fundamentals/networking
- https://docs.flutter.dev/learn/pathway/tutorial/http-requests
- https://docs.flutter.dev/release/breaking-changes/asset-manifest-dot-json
- https://docs.flutter.dev/release/breaking-changes/network-policy-ios-android
- name: flutter-databases
description: Work with databases in a Flutter app
instructions: |
Databases are a crucial component of an application's data layer, which
serves as the source of truth for all application data. This data layer,
also known as the model in MVVM terminology, is the only place where
application data should be updated. It is responsible for consuming data
from external APIs, exposing data to the UI, handling UI events that require
data updates, and sending update requests to external APIs. The data layer
typically consists of repositories and services.
Repositories are the source of truth for application data and contain logic
related to that data, such as updating data in response to user events or
polling for data from services. They are responsible for presenting local or
remote data and should be the only place where data can be modified.
Repositories transform raw data from services into domain models, which are
data models containing only the information needed by the rest of the app. A
service can be used by any number of repositories, and a repository can use
multiple services. For example, a `BookingRepository` might take an
`ApiClient` service as input to get and update raw data from a server. It's
important that the service is a private member so the UI layer cannot bypass
the repository and call a service directly. In offline-first applications,
repositories combine different local and remote data sources to provide a
single access point for data, regardless of device connectivity.
Databases are particularly useful for persisting and querying large amounts
of data on a local device, offering faster inserts, updates, and queries
compared to other local persistence solutions. Flutter applications can
utilize SQLite databases through the `sqflite` plugin. To work with SQLite
databases, you need to add the `sqflite` and `path` packages as
dependencies. The `path` package helps define the storage location for the
database on disk. When using SQLite, you typically define a data model
(e.g., a `Dog` data model with `id`, `name`, and `age`), open the database,
create tables (e.g., a `dogs` table), and then perform operations like
inserting, retrieving, updating, and deleting data. The `id` is often used
as the primary key for a table to improve query and update times.
For managing data persistence, a `TodoRepository` might act as the source of
truth for ToDo items, using a `DatabaseService` internally to access an SQL
database via the `sqflite` package. This `DatabaseService` can also be
implemented using other storage packages like `sqlite3`, `drift`, or cloud
solutions like `firebase_database`. The `TodoRepository` would handle
methods like `fetchTodos()`, `createTodo()`, and `deleteTodo()`, ensuring
the database is open before each request.
For caching data, various strategies exist:
* **`shared_preferences`**: A Flutter plugin that wraps platform-specific
key-value storage, suitable for small data sizes.
* **File system**: For scenarios where `shared_preferences` is
insufficient, caching data with the device's file system can be
explored.
* **On-device databases**: This is the most robust solution for local data
caching, offering significantly improved performance for large datasets
compared to simple files. Both relational (like SQLite, `drift`) and
non-relational (like `hive_ce`, `isar_community`) databases are
available.
* **Remote Caching**: A lightweight caching system specifically for API
responses.
* **Image Caching**: For images, the `cached_network_image` package can be
used to direct the Flutter app to store images on the file system.
resources:
- https://docs.flutter.dev/app-architecture/case-study/data-layer
- https://docs.flutter.dev/app-architecture/concepts
- https://docs.flutter.dev/app-architecture/design-patterns/key-value-data
- https://docs.flutter.dev/app-architecture/design-patterns/offline-first
- https://docs.flutter.dev/app-architecture/design-patterns/sql
- https://docs.flutter.dev/app-architecture/guide
- https://docs.flutter.dev/app-architecture/recommendations
- https://docs.flutter.dev/cookbook/forms/validation
- https://docs.flutter.dev/cookbook/lists/long-lists
- https://docs.flutter.dev/cookbook/lists/mixed-list
- https://docs.flutter.dev/cookbook/networking/fetch-data
- https://docs.flutter.dev/cookbook/persistence/sqlite
- https://docs.flutter.dev/cookbook/testing/unit/mocking
- https://docs.flutter.dev/data-and-backend
- https://docs.flutter.dev/get-started/fundamentals/local-caching
- https://docs.flutter.dev/resources/architectural-overview
- name: flutter-caching
description: Cache data in a Flutter app
instructions: |
Caching is a technique for retaining application data to show again at a
future time, rather than repeatedly loading it from a remote server. This
can prevent users from waiting for data to load every time they relaunch an
app.
All caching strategies involve a three-step operation: checking if the cache
contains the desired data, loading the data if the cache is empty, and then
returning the value in the cache. When the cache already contains the
desired information, it's called a "cache hit". If the cache is empty and
data needs to be loaded from the original source, it's a "cache miss".
There are different types of caching:
* **Local Caching** involves storing data on the device.
* **In-memory caching** stores data in memory, but this data will not
persist beyond a single user session.
* **Persistent caches** store data on the device's hard drive to
ensure performance benefits on fresh application launches.
* **`shared_preferences`** is a Flutter plugin that uses
platform-specific key-value storage, suitable for small data sizes.
* **File system caching** is an option when `shared_preferences` is
insufficient for larger data. The `path_provider` package can be
used to access common file system locations like temporary
directories (which the system can clear) or documents directories
(which persist until the app is deleted).
* **On-device databases** (relational or non-relational) offer
significantly improved performance for large datasets compared to
simple files. Examples include SQLite, Drift, Hive CE, and Isar
Community.
* **Image caching** can be handled with the `cached_network_image`
package, which uses the file system to store images. Image I/O can
be expensive, so caching provides snapshots of complex hierarchies
for easier rendering in subsequent frames. However, raster cache
entries are expensive to construct and use a lot of GPU memory, so
images should only be cached when absolutely necessary.
* **State restoration** is a pattern where aspects of a user's session,
such as navigation stacks, scroll positions, and form progress, are
persisted. Flutter's built-in state restoration syncs data from its
Element tree with the Flutter engine, which then caches it in
platform-specific storage.
* **FlutterEngine caching** can minimize Flutter's initialization time
when adding Flutter screens to an Android app. By default, each
`FlutterActivity` creates its own `FlutterEngine`, which has a
non-trivial warm-up time. A pre-warmed, cached `FlutterEngine` can be
used instead.
Caching can also be used to optimize widget rendering. While generally
preferable to rely on caching widgets, comparing properties of leaf widgets
(widgets with no children) can be more efficient than rebuilding them if
they rarely change. However, overriding `operator ==` can lead to
performance degradation.
resources:
- https://docs.flutter.dev/add-to-app/android/add-flutter-fragment/index.html.md
- https://docs.flutter.dev/add-to-app/android/add-flutter-screen
- https://docs.flutter.dev/app-architecture/design-patterns/offline-first
- https://docs.flutter.dev/cookbook/persistence/reading-writing-files
- https://docs.flutter.dev/cookbook/persistence/sqlite
- https://docs.flutter.dev/get-started/fundamentals
- https://docs.flutter.dev/get-started/fundamentals/local-caching
- https://docs.flutter.dev/learn/pathway
- https://docs.flutter.dev/perf/best-practices
- https://docs.flutter.dev/perf/ui-performance
- https://docs.flutter.dev/platform-integration/web/faq
- https://docs.flutter.dev/release/breaking-changes/image-cache-and-provider
- https://docs.flutter.dev/release/breaking-changes/imagecache-large-images
- https://docs.flutter.dev/release/breaking-changes/scroll-cache-extent
- name: flutter-platform-views
description: Add a native view into your Flutter app
instructions: |
Platform Views allow you to embed native views into a Flutter application.
This functionality enables the application of transforms, clips, and opacity
to the native view directly from Dart. For example, you can integrate native
Google Maps from the Android SDK or iOS SDK directly into your Flutter app.
Similarly, native web views can be used directly inside a Flutter app on
macOS.
Platform Views are available for Android, iOS, and macOS. For Android,
Platform Views require API 23+. On Android, there are two implementations
for Platform Views: Hybrid Composition and Texture Layer (or Texture Layer
Hybrid Composition). Hybrid Composition renders Platform Views normally,
with Flutter content rendered into a texture, and SurfaceFlinger composing
both. This offers the best performance and fidelity for Android views but
can cause Flutter performance to suffer, lower application FPS, and prevent
certain transformations on Flutter widgets from working with platform views.
Texture Layer renders Platform Views into a texture, with Flutter drawing
them via the texture and Flutter content rendered directly into a Surface.
This provides good performance for Android Views and best performance for
Flutter rendering, with all transformations working correctly. However,
quick scrolling (e.g., in a web view) can be janky, SurfaceViews are
problematic and moved into a virtual display (breaking accessibility), and
text magnifiers will break unless Flutter is rendered into a TextureView.
Prior to Android 10, hybrid composition copied each Flutter frame out of
graphics memory into main memory and then back to a GPU texture, impacting
overall Flutter UI performance; in Android 10 and above, this copy happens
only once.
On iOS, only Hybrid Composition is used, where the native `UIView` is
appended to the view hierarchy. Platform views in Flutter come with
performance trade-offs. Techniques to mitigate performance issues for
complex cases include using a placeholder texture during animations in Dart,
such as rendering a screenshot of the native view as a texture if an
animation is slow while a platform view is rendered. There are also
composition limitations for iOS Platform Views, where `ShaderMask` and
`ColorFiltered` widgets are not supported, and `BackdropFilter` has
limitations. For macOS, platform view support is not fully functional as of
the current release, with gesture support not yet available.
To create a platform view on Android, you need to create a Widget on the
Dart side and add a build implementation. This involves importing necessary
Flutter packages and implementing a `build()` method that specifies a
`viewType` and can pass parameters to the platform side. Handling
`SurfaceViews` is problematic for Flutter and should be avoided when
possible. Certain Android Views, like `SurfaceView` and `SurfaceTexture`, do
not invalidate themselves when their content changes, requiring manual
invalidation by calling `invalidate` on the View or a parent view.
Flutter can be added to existing web applications, including those using
HTML DOM-based frameworks (Dart or JS), server-side rendered frameworks, or
even "VanillaJS". The minimum requirement is that the existing application
supports importing JavaScript libraries and creating HTML elements for
Flutter to render into. After building Flutter normally, embedding
instructions are followed to place Flutter views on the page. Multi-view
mode is not supported for mobile limitations but can be enabled for web
applications by setting `multiViewEnabled: true` in the `initializeEngine`
method. Flutter views can be managed from JavaScript using an `app` object
returned by `runApp`, allowing for adding and removing views. View additions
and removals are surfaced to Flutter through the `didChangeMetrics` method
of the `WidgetsBinding` class, and the complete list of views is available
via `WidgetsBinding.instance.platformDispatcher.views`. To render content
into each `FlutterView`, the Flutter app needs to create a `View` widget,
which can be grouped under a `ViewCollection` widget.
resources:
- https://docs.flutter.dev/add-to-app
- https://docs.flutter.dev/add-to-app/android/add-flutter-view
- https://docs.flutter.dev/add-to-app/multiple-flutters
- https://docs.flutter.dev/flutter-for/android-devs
- https://docs.flutter.dev/get-started/flutter-for/android-devs
- https://docs.flutter.dev/get-started/flutter-for/swiftui-devs
- https://docs.flutter.dev/platform-integration
- https://docs.flutter.dev/platform-integration/android/platform-views
- https://docs.flutter.dev/platform-integration/android/platform-views?tab=android-platform-views-java-tab
- https://docs.flutter.dev/platform-integration/ios/platform-views
- https://docs.flutter.dev/platform-integration/macos/platform-views
- https://docs.flutter.dev/platform-integration/platform-channels
- https://docs.flutter.dev/platform-integration/web/embedding-flutter-web
- https://docs.flutter.dev/release/breaking-changes/platform-views-using-html-slots-web
- https://docs.flutter.dev/resources/architectural-overview
- https://docs.flutter.dev/resources/faq
- name: flutter-native-interop
description: Interoperate with native APIs in a Flutter app on Android, iOS, and the web
instructions: |
Native interop on Android, iOS, and Web involves several methods for
integrating Flutter applications with platform-specific code and features.
For Android, Flutter allows binding to native C code using the `dart:ffi`
library. This library, which stands for foreign function interface, enables
Flutter mobile and desktop apps to call native C APIs. While a legacy
approach to C interop on Android is documented, a `package_ffi` template
with build hooks is now recommended for C interop since Flutter 3.38.
However, the legacy `plugin_ffi` template remains useful for accessing the
Flutter Plugin API or configuring a Google Play services runtime. Flutter
also supports writing custom platform-specific code for Android using Kotlin
or Java. Messages can be passed between the Flutter UI and the Android
platform using platform channels, with `MethodChannel` for Android receiving
method calls and sending back results. Android developers can leverage their
existing knowledge when building Flutter apps, as Flutter relies on the
mobile operating system for various capabilities.
On iOS, Flutter supports binding to native C, Objective-C, and Swift code.
Similar to Android, the `dart:ffi` library can be used to call native C
APIs. For C interop on iOS, a `package_ffi` template with build hooks is
recommended since Flutter 3.38, though the `plugin_ffi` template is still
useful for accessing the Flutter Plugin API or using static linking. When
binding to native macOS code, which shares similarities with iOS, the FFI
library can only bind against C symbols, requiring C++ symbols to be marked
`extern "C"`. Attributes like `__attribute__((visibility("default")))
__attribute__((used))` should be added to prevent the linker from discarding
symbols during link-time optimization. Dynamically linked libraries are
automatically loaded when the app starts, and their symbols can be resolved
using `DynamicLibrary.process`. Flutter also supports writing custom
platform-specific code for iOS using Swift or Objective-C. Platform channels
are used to pass messages asynchronously between the Flutter UI and the iOS
platform, with `FlutterMethodChannel` for iOS handling method calls. Flutter
also supports new and upcoming iOS features and allows embedding native
macOS views.
For the web, Flutter offers several integration options. This includes
adding custom integrations with the web platform, customizing app
initialization, embedding native web content, and embedding a Flutter app
within another web app. Flutter can compile to WebAssembly (Wasm) to take
advantage of its benefits. However, Flutter compiled to Wasm currently
cannot run on the iOS version of any browser due to WebKit requirements and
compatibility issues. Interoperability with JavaScript is also supported,
allowing integration from Dart code. For web-specific code, JS
interoperability is generally used instead of platform channels. Dart has
introduced new, lightweight interop solutions built around static JS
interop, such as `package:web` (replacing `dart:html`) and `dart:js_interop`
(replacing `package:js` and `dart:js`), to support compilation to Wasm.
Across all platforms, Flutter allows writing custom platform-specific code
using platform channels. The Pigeon package can be used to generate
type-safe platform-specific code. Messages are passed asynchronously between
the client (UI) and host (platform) to ensure a responsive user interface.
Flutter also supports adding Flutter to an existing app on Android, iOS, and
web. This "add-to-app" feature supports multi-engine on Android and iOS,
allowing multiple isolated Flutter instances, and multi-view on the web,
where multiple `FlutterViews` can share objects within a single Dart
program. Common use cases for add-to-app include hybrid navigation stacks
and partial-screen views.
resources:
- https://docs.flutter.dev/platform-integration
- https://docs.flutter.dev/platform-integration/android/c-interop
- https://docs.flutter.dev/platform-integration/android/call-jetpack-apis
- https://docs.flutter.dev/platform-integration/android/platform-views
- https://docs.flutter.dev/platform-integration/bind-native-code
- https://docs.flutter.dev/platform-integration/ios
- https://docs.flutter.dev/platform-integration/ios/c-interop
- https://docs.flutter.dev/platform-integration/ios/platform-views
- https://docs.flutter.dev/platform-integration/macos/c-interop
- https://docs.flutter.dev/platform-integration/platform-channels
- https://docs.flutter.dev/platform-integration/web/wasm
- https://docs.flutter.dev/platform-integration/web/web-content-in-flutter
- https://docs.flutter.dev/resources/faq
- name: flutter-plugins
description: Build a Flutter plugin that provides native interop for other Flutter apps to use
instructions: |
To build a plugin, you first need to create the package. You can create a
plugin package using the `flutter create --template=plugin` command. When
creating the package, you can specify the supported platforms using the
`--platforms=` option, followed by a comma-separated list of platforms such
as `android`, `ios`, `web`, `linux`, `macos`, and `windows`. If no platforms
are specified, the project will not support any platforms. You can also use
the `--org` option to specify your organization using reverse domain name
notation, which is used in package and bundle identifiers. By default, the
plugin project uses Swift for iOS and Kotlin for Android, but you can
specify Objective-C or Java using the `-i` and `-a` flags respectively.
For FFI plugins, which are useful for accessing the Flutter Plugin API,
configuring Google Play services on Android, or using static linking on iOS
or macOS, you would use `flutter create --template=plugin_ffi`. This creates
an FFI plugin project with Dart code in `lib` that defines the API and calls
native code using `dart:ffi`, and native source code in `src` with a
`CMakeLists.txt` file for building a dynamic library. FFI plugin packages
support bundling native code and method channel registration code, but not
method channels themselves. If you need to use both method channels and FFI,
you should use a non-FFI plugin. Each platform can use either an FFI or
non-FFI plugin.
After creating the package, you need to implement it. The API of the plugin
package is defined in Dart code, typically in `lib/<package name>.dart`. For
Android platform code, it's recommended to edit it using Android Studio. You
should build the code at least once before editing, then open the
`hello/example/android/build.gradle` or
`hello/example/android/build.gradle.kts` file in Android Studio. The Android
platform code for your plugin is located in
`hello/java/com.example.hello/HelloPlugin`. For Windows, you can open the
`hello/example/build/windows/hello_example.sln` file in Visual Studio, and
the Windows platform code is in `hello_plugin/Source Files` and
`hello_plugin/Header Files`. After making changes to plugin code, you must
rebuild the solution.
You also need to connect the Dart API with the platform-specific
implementations using a platform channel or through interfaces defined in a
platform interface package. To add support for specific platforms to an
existing plugin project, you can run `flutter create --template=plugin`
again in the project directory with the `--platforms=` flag. You might also
need to update the `podspec` file to set dependencies and deployment targets
for iOS and macOS.
Federated plugins are a way to split a plugin's API into a platform
interface, independent platform implementations, and an app-facing
interface. This allows different teams with different expertise to build
plugin implementations for various platforms. A federated plugin requires an
app-facing interface for users, one or more platform implementations for
platform-specific code, and a platform interface that connects the
app-facing interface to the implementations. Package-separated federated
plugins separate these components into their own Dart packages. You can add
new platform implementations to endorsed federated plugins on pub.dev by
coordinating with the original plugin author.
For Android plugins, if possible, move logic from `registerWith()` into a
private method that both `registerWith()` and `onAttachedToEngine()` can
call, as only one will be called. Document all non-overridden public
members. If your plugin needs an `Activity` reference, implement the
`ActivityAware` interface. If it's expected to be held in a background
`Service`, implement `ServiceAware`. Update the example app's
`MainActivity.java` to use the v2 embedding `FlutterActivity`. You might
also need a public constructor for your plugin class.
resources:
- https://docs.flutter.dev/add-to-app/android/plugin-setup
- https://docs.flutter.dev/packages-and-plugins/developing-packages
- https://docs.flutter.dev/packages-and-plugins/swift-package-manager/for-plugin-authors
- https://docs.flutter.dev/packages-and-plugins/using-packages
- https://docs.flutter.dev/platform-integration/desktop
- https://docs.flutter.dev/platform-integration/ios/apple-frameworks
- https://docs.flutter.dev/platform-integration/platform-channels
- https://docs.flutter.dev/release/breaking-changes/flutter-gradle-plugin-apply
- https://docs.flutter.dev/release/breaking-changes/plugin-api-migration
- https://docs.flutter.dev/testing/plugins-in-tests
- https://docs.flutter.dev/testing/testing-plugins
- https://docs.flutter.dev/tools/android-studio
- name: flutter-testing
description: Add Flutter unit tests, widget tests, or integration tests
instructions: |
Automated testing is crucial for ensuring an app performs correctly before
publication and for maintaining feature and bug fix velocity, especially as
an app gains more features, making manual testing harder. Good testing
practices contribute to app flexibility, making it straightforward and
low-risk to add new logic and UI. Testing is a key aspect of software
development, encompassing various types of tests and considerations for
different platforms and architectural components.
Automated testing generally falls into three main categories: unit tests,
widget tests, and integration tests. A well-tested app typically includes
many unit and widget tests, with code coverage tracking, and enough
integration tests to cover important use cases. There are trade-offs between
these different kinds of testing regarding confidence, maintenance cost,
dependencies, and execution speed.
Unit tests focus on verifying the correctness of a single function, method,
or class. The goal is to test a unit of logic under various conditions,
often by mocking out external dependencies. Unit tests generally do not
involve disk I/O, screen rendering, or user actions from outside the test
process. For architectural components, it is strongly recommended to write
unit tests for every service, repository, and ViewModel class, testing the
logic of each method individually.
Widget tests, also known as component tests in other UI frameworks, test a
single widget. The purpose of a widget test is to ensure the widget's UI
looks and interacts as expected. Testing a widget involves multiple classes
and requires a test environment that provides the appropriate widget
lifecycle context. Widget tests should be written for views.
Integration tests verify the behavior of a complete app or a large part of
an app. These tests can also be referred to as end-to-end testing or GUI
testing. Integration tests are used to validate how individual pieces of an
app work together and to capture the performance of an app running on a real
device, which unit and widget tests do not cover. The Flutter SDK includes
the `integration_test` package for running these tests. Integration tests
are particularly important for testing routing and dependency injection. To
run integration tests, the `integration_test` package needs to be added as a
dependency for the Flutter app's test file. Integration tests can be run
from the command line or a CI system for desktop platforms, from the command
line or Firebase Test Lab for mobile platforms, and from the command line
for web browsers. For Linux apps, a CI system must invoke an X server, often
using the `xvfb-run` tool.
When testing plugins, all usual types of Flutter tests apply, but due to
native code, plugins often require additional types of tests. Dart unit
tests and widget tests can be used to test the Dart portion of a plugin.
Native unit tests are also relevant. For Android, JUnit tests are configured
in `android/src/test/`. For iOS and macOS, XCTest tests are found in
`example/ios/RunnerTests/` and `example/macos/RunnerTests/` respectively,
run via the example app's project. For Linux and Windows, GoogleTest tests
are located in `linux/test/` and `windows/test/` respectively. Native UI
tests, such as Espresso or XCUITest, can be useful if a plugin cannot be
tested without native UI interactions, as they interact with both native and
Flutter UI elements. Since only integration tests can test communication
between Dart and native languages, it's recommended to have at least one
integration test for each platform channel call. If certain flows, like
those requiring native UI interaction or mocking device state, cannot be
tested with integration tests, "end-to-end" tests can be implemented using
native unit tests that call into the method channel entry point with a
synthesized call, and Dart unit tests that mock the platform channel and
call the plugin's public API.
Testing architectural components separately and together is a strong
recommendation. Observability and testability are important architectural
principles, advocating for building in logging, metrics, tracing, and
ensuring components can be unit and integration tested.
resources:
- https://docs.flutter.dev/app-architecture/case-study/testing
- https://docs.flutter.dev/app-architecture/concepts
- https://docs.flutter.dev/app-architecture/recommendations
- https://docs.flutter.dev/cookbook/testing/integration
- https://docs.flutter.dev/cookbook/testing/integration/introduction
- https://docs.flutter.dev/cookbook/testing/unit/introduction
- https://docs.flutter.dev/cookbook/testing/widget/finders
- https://docs.flutter.dev/cookbook/testing/widget/introduction
- https://docs.flutter.dev/resources/faq
- https://docs.flutter.dev/testing
- https://docs.flutter.dev/testing/integration-tests
- https://docs.flutter.dev/testing/overview
- https://docs.flutter.dev/testing/testing-plugins
- name: flutter-app-size
description: Measure and reduce the size of the Flutter app bundle, APK, or IPA
instructions: |
To effectively reduce app size, an agent needs to understand how to measure
app size, analyze its components, and implement specific reduction
strategies.
**Measuring and Analyzing App Size:**
The size of a compiled app, whether an APK, app bundle, or IPA, is a
significant concern because larger apps require more device space, take
longer to download, and can exceed limits for features like Android instant
apps. Debug builds are not representative of the final app size. To measure
app size, the `--analyze-size` flag can be used with `flutter build`
commands for various platforms like `apk`, `appbundle`, `ios`, `linux`,
`macos`, and `windows`. This build process compiles Dart in a way that
records code size usage of Dart packages and provides a high-level summary
in the terminal. It also generates a `*-code-size-analysis_*.json` file for
more detailed analysis in DevTools.
For iOS, a `.app` file is created, which is useful for evaluating the
relative size of its content, but for a closer estimate of download size,
the "Estimating total size" section should be referenced. An upload package
is not always representative of end-users' download size, as redundant
native library architectures and asset densities can be filtered by app
stores. End users' download sizes can also vary based on their hardware.
Deeper analysis can be performed in DevTools by uploading the
`*-code-size-analysis_*.json` file. The DevTools app size tool allows for a
tree or treemap view to break down application contents to individual file
and function levels for the Dart AOT artifact. This tool can be accessed by
running `dart devtools`, selecting "Open app size tool," and uploading the
JSON file. DevTools can also compare two builds by loading two
`*-code-size-analysis_*.json` files. The "size information" file contains
data for the total application size. The Dart AOT compiler performs
tree-shaking in profile or release modes, optimizing app size by removing
unused or unreachable code. The result is a collection of packages,
libraries, classes, and functions in the binary output, along with their
sizes in bytes, which can be analyzed in the app size tool.
For iOS, an Xcode App Size Report can be created by configuring the app
version and build, then running `flutter build ipa --export-method
development`. Opening the archive in Xcode, selecting "Distribute App"
(development is simplest), choosing "all compatible device variants" in App
Thinning, and stripping Swift symbols, allows for signing and exporting the
IPA. The exported directory will contain `App Thinning Size Report.txt` with
projected application sizes for different devices and iOS versions.
**Strategies for App Size Reduction:**
When building a release version of an app, using the `--split-debug-info`
tag can significantly reduce code size. Other methods to make an app smaller
include removing unused resources, minimizing resources imported from
libraries, and compressing PNG and JPEG files.
resources:
- https://docs.flutter.dev/ai-best-practices
- https://docs.flutter.dev/deployment/ios
- https://docs.flutter.dev/perf
- https://docs.flutter.dev/perf/app-size
- https://docs.flutter.dev/perf/best-practices
- https://docs.flutter.dev/platform-integration/ios/ios-app-clip
- https://docs.flutter.dev/platform-integration/windows/building
- https://docs.flutter.dev/resources/faq
- https://docs.flutter.dev/tools/devtools/app-size
- https://docs.flutter.dev/tools/devtools/memory
- https://docs.flutter.dev/tools/devtools/performance
- https://docs.flutter.dev/tools/sdk
- https://docs.flutter.dev/ui/adaptive-responsive
- https://docs.flutter.dev/ui/adaptive-responsive/best-practices
- https://docs.flutter.dev/ui/adaptive-responsive/general
- https://docs.flutter.dev/ui/adaptive-responsive/large-screens
- name: flutter-concurrency
description: Execute long-running tasks in a background thread in Flutter
instructions: |
Dart has a single-threaded execution model, which includes support for
Isolates, an event loop, and asynchronous code. An Isolate is Dart's
implementation of a lightweight thread. All Dart code runs in isolates,
which are similar to threads but have their own isolated memory and do not
share state. Isolates can only communicate by messaging. By default, Flutter
applications perform all their work on a single isolate, known as the main
isolate. This model is often sufficient for simpler programming and to keep
the application's UI responsive.
Unless an Isolate is explicitly spawned, Dart code runs in the main UI
thread, which is driven by an event loop. Flutter's event loop is comparable
to the iOS main loop. Dart's single-threaded model does not necessitate
running all operations as blocking tasks that would freeze the UI. Instead,
Dart provides asynchronous features like `async` and `await`. An
asynchronous operation allows other operations to execute before it
completes. The `async` keyword indicates that a function performs
asynchronous work, and `await` tells the system to wait for a result from
that function.
In Dart, a `Future` object represents a value that will be provided in the
future. Functions marked as `async` automatically return a `Future`. Flutter
uses `FutureBuilder` and `StreamBuilder` widgets to display the results of a
`Future` in the UI.
For long-running operations that might block UI rendering, especially on
multi-core hardware, tasks can be offloaded to a worker isolate, also known
as a background worker. As of Dart 2.19, `Isolate.run()` can be used to
spawn an isolate and execute computations. This method spawns an isolate,
passes a callback for computation, returns the result, and then shuts down
the isolate upon completion, all while running concurrently with the main
isolate without blocking it. The `Isolate.run` method requires a single
argument, which is a callback function that runs on the new isolate. This
callback's function signature must have exactly one required, unnamed
argument. When the computation finishes, its value is returned to the main
isolate, and the spawned isolate exits. An example use case is decoding a
large JSON blob, which, if not offloaded, could make the UI unresponsive.
For long-lived isolates that need to pass multiple messages over time, the
`Isolate` API and Ports can be used. These are useful for processes that run
repeatedly or over a period, yielding multiple return values to the main
isolate. Communication between isolates is exclusively through `ReceivePort`
and `SendPort`. `SendPort` acts like a `StreamController` for sending
messages, while `ReceivePort` functions as a listener, calling a provided
callback when a new message is received.
resources:
- https://docs.flutter.dev/add-to-app/performance
- https://docs.flutter.dev/data-and-backend/serialization/json
- https://docs.flutter.dev/data-and-backend/state-mgmt/options
- https://docs.flutter.dev/flutter-for/dart-swift-concurrency
- https://docs.flutter.dev/flutter-for/react-native-devs
- https://docs.flutter.dev/flutter-for/uikit-devs
- https://docs.flutter.dev/get-started/flutter-for/android-devs
- https://docs.flutter.dev/get-started/flutter-for/dart-swift-concurrency
- https://docs.flutter.dev/get-started/flutter-for/uikit-devs
- https://docs.flutter.dev/get-started/fundamentals/dart
- https://docs.flutter.dev/perf/isolates
- https://docs.flutter.dev/platform-integration/web/faq
- https://docs.flutter.dev/resources/architectural-overview
- https://docs.flutter.dev/resources/bootstrap-into-dart
- https://docs.flutter.dev/resources/faq
- name: flutter-home-screen-widget
description: Adding a Home Screen widget to your Flutter App
instructions: |
Home screen widgets allow users to see and interact with your app's data
directly from their device's home screen. Adding a home screen widget to a
Flutter app involves using native frameworks for each platform (SwiftUI for
iOS and XML for Android) to create the widget's UI, while sharing data and
resources between the Flutter app and the native components.
Common approaches involve using the `home_widget` package to facilitate
communication between the Flutter app and the native widget. On iOS, this
typically involves creating a Widget Extension target in Xcode and using
App Groups to share data. On Android, you create an `AppWidgetProvider`
and use `SharedPreferences` for data sharing. Key techniques include
sending data updates to the widget, using custom fonts, and even
rendering Flutter widgets as images for display in the native widget UI.
resources:
- https://codelabs.developers.google.com/flutter-home-screen-widgets#0
- https://pub.dev/packages/home_widget