mirror of
https://github.com/flutter/agent-plugins.git
synced 2026-09-14 16:19:33 +08:00
1444 lines
90 KiB
YAML
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 |