physical_platform 0.3.1 copy "physical_platform: ^0.3.1" to clipboard
physical_platform: ^0.3.1 copied to clipboard

A Flutter package that simplifies the cross-platform development process by providing declarative and pragmatic instruments.

Welcome to physical_platform, a package that provides pragmatic physical-platform utils.

NB: If you are using also virtual_platform, you can opt to only use omni_platform instead. omni_platform integrates virtual_platform and physical_platform, without adding any extra functionality. This way you only need to declare one package in your pubspec.yaml.

Warning: Prefer virtual_platform or design_language wherever possible

In order to increase testability, my recommendation is to rely first on either:

  • a virtual platform matcher/dispatcher
    • it is used in case the design language does not change at runtime (usually that means only one design language is used); consult the virtual_platform package for more information.
  • a design language matcher/dispatcher
    • it is used in case the design language changes at runtime; consult the design_language package for more information.

In certain cases, however, it is not possible to use the packages above; that is when this package becomes very handy.

Getting started #

You need to add physical_platform to your dependencies.

dependencies:
  physical_platform: ^latest # replace latest with version number

Next, you have to import package:physical_platform/physical_platform.dart.

Usage #

Many parts of code only depend on the physical platform. This package offers expression-based, pragmatic physical-platform utils, allowing developers to write more declarative code compared to typical Dart code (see examples below). It has a syntax similar to the ony of virtual_platform.

The arguments of all instruments are functions, i.e., PhysicalPlatformDispatcher and matchPhysicalPlatform are of type Widget Function(BuildContext context, Widget? child) and T Function(), respectively. If the goal is to only select a widget or a value — a function expression is what needs to be passed, e.g., (_, __) => Text('text') or () => 'value', respectively.

Platforms and platform groups are summarized at the end of this README.

PhysicalPlatformDispatcher #

This dispatcher relies on the physical platform.

It builds a widget, and it is used when a widget is not supported only by all platforms. For example, as of 2022 the flutter_webview plugin does not support the desktop OSs yet:

PhysicalPlatformDispatcher(
  android: (_, __) => MyWebView(),
  ios: (_, __) => MyWebView(),
  other: (_, __) => Center(child: Text('platform not supported')),
);

or also:

PhysicalPlatformDispatcher(
  mobileSystems: (_, __) => MyWebView(),
  other: (_, __) => Center(child: Text('platform not supported')),
);

Platforms and platform groups are summarized at the end of this README.

Context and child provision

One might need the context in some cases. The first parameter of all builders is a BuildContext context. You can also specify a Widget? child widget, so that you do not have to repeat it in all builders.

Example:

return MaterialApp(
    title: 'Flutter Demo',
    theme: ThemeData(
        primarySwatch: Colors.blue,
    ),
    home: Scaffold(
        appBar: AppBar(title: const Text('example')),
        body: PhysicalPlatformDispatcher(
            child: const CommonSubtree(),
            mobileSystems: (context, child) => SpecialWidget(
                child,
                onPressed(() {do something with context}),
            ),
            other: (context, child) => OtherSpecialWidget(
                child,
                onPressed(() {do something with context}),
            ),
        );
    ),
);

matchPhysicalPlatform #

matchPhysicalPlatform is a declarative pattern to invoke the right function for the matching physical platform. It uses generics.

Usage example:

// one should use path_provider here to do it correctly
final dbPath = matchPhysicalPlatform(
  other: () => 'default/path/to/db',
  android: () => 'path/to/db/on/android',
  macos: () => 'path/to/db/on/android',
);

dbPath will have value 'default/path/to/db' on all platforms (including web), except on Android and macOS.

This function will probably be the instrument you are going to use the most from the physical_platform package.

How is this solution more pragmatic than typical Dart?

Example 1

This package:

matchPhysicalPlatform(
    mobileSystems: () {...},
    desktopSystems: () {...},
    web: () {...},
    other: () {...},
);

Typical Dart:

if (kIsWeb) { // this should always go first
    ...
} else if (Platform.isIOS || Platform.isAndroid) {
    ...
} else if (Platform.isLinux || Platform.isWindows || Platform.isMacOS) {
    ...
} else {
    ...
}

Example 2

This package:

matchPhysicalPlatform(
    android: () {...},
    ios: () {...},
    web: () {...},
    other: () {...},
);

Typical Dart:

if (kIsWeb) {
    ...
} else if (Platform.isIOS) {
    ...
} else if (Platform.isAndroid) {
    ...
} else {
    ...
}

Platforms and platform groups #


Platform appleSystems mobileSystems desktopSystems
android
ios
linux
macos
windows
web
fuchsia

Priority order: from left to right.

1
likes
160
pub points
5%
popularity

Publisher

verified publishermanuelplavsic.ch

A Flutter package that simplifies the cross-platform development process by providing declarative and pragmatic instruments.

Repository (GitLab)
View/report issues

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

abstract_platform, flutter

More

Packages that depend on physical_platform