I am new to Flutter. I am experimenting with the framework and I would like to explore multiplatform apps. I am specifically targeting:
For each platform I'm using their own theme and icon sets (e.g. fluent & fluent_icons on Windows, adwaita & adwaita_icons on linux, cupertino & macos_ui on mac,...). However, even though the design is different across different platforms, I am sharing the component's behaviour by leveraging MVVM and platform-agnostic components.
I've been reading through all the flutter docs of packages vs plugins , however I think that either I didn't get something or there is something I'm missing.
When I perform a platform-specific build I would like to get rid of all the unnecessary dependencies (e.g. cupertino on Windows). How can I achieve this? I was thinking about creating:
With this approach, I can have separate pubspec.yaml
for each individual platform and, therefore, I can include only the needed dependencies.
my_app
- my_app_linux // Only support for Linux with Adwaita widgets
- linux
- lib
- pubspec.yaml
- my_app_windows // Only support for Windows with Fluent widgets
- windows
- lib
- pubspec.yaml
- my_app_macos // Only support for Macos with MacOs widgets
- macos
- lib
- pubspec.yaml
- my_app_shared (here I can just actually use the root project's "/lib" folder)
- lib
- pubspec.yaml
Have you got any advice/experience? Did I miss something in the official documentation of package vs plugin?
As of now, this is not possible without any workaround. Take a look at following GitHub issue: https://github.com/flutter/flutter/issues/23122#issuecomment-927938161
In essence, you can create platform-specific widgets and inject those widgets during compile time by passing an environment variable with --dart-define
.
class MyApp extends StatelessWidget {
static const bool MACOS_PLATFORM = bool.fromEnvironment("MACOS_PLATFORM", defaultValue: false);
static const bool LINUX_PLATFORM = bool.fromEnvironment("LINUX_PLATFORM", defaultValue: false);
static const bool WINDOWS_PLATFORM = bool.fromEnvironment("WINDOWS_PLATFORM", defaultValue: false);
@override
Widget build(BuildContext context) {
/// Important note about tree shaking:
/// For this to work you have to make a direct constructor call or a static function call e.g. MacOSWidget()
///
/// This will NOT work:
///
/// MacOSWidget macOSWidget;
/// if (MACOS_PLATFORM) return macOSWidget;
if (MACOS_PLATFORM) return MacOSWidget();
else if (LINUX_PLATFORM) return LinuxWidget();
else if (WINDOWS_PLATFORM) return WindowsWidget();
else return MyDefaultWidget();
}
}
And then run your app with flutter run my_app --dart-define MACOS_PLATFORM=true
or build it with flutter build my_app --dart-define MACOS_PLATFORM=true
.
Do NOT forget to include the argument --dart-define <desired_platform>=true
. Otherwise, the environment variable is not exposed at compile time and tree shaking will not work.