Skip to content

[google_maps_flutter] Add cameraControl enable/disable & position on web #9089

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.13.0

* Adds support for camera control button on web.

## 2.12.3

* Updates the example app to use the zIndexInt param instead of the deprecated zIndex.
Original file line number Diff line number Diff line change
@@ -61,6 +61,8 @@ class MapUiBodyState extends State<MapUiBody> {
late GoogleMapController _controller;
bool _nightMode = false;
String _mapStyle = '';
bool _webCameraControlEnabled = true;
WebCameraControlPosition? _webCameraControlPosition;

@override
void initState() {
@@ -72,6 +74,67 @@ class MapUiBodyState extends State<MapUiBody> {
super.dispose();
}

Widget _webCameraControlToggler() {
return TextButton(
child: Text(
'${_webCameraControlEnabled ? 'disable' : 'enable'} web camera control'),
onPressed: () {
setState(() {
_webCameraControlEnabled = !_webCameraControlEnabled;
});
},
);
}

Widget _webCameraControlPositionToggler() {
return TextButton(
onPressed: () => showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Web camera control position'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
DropdownButton<WebCameraControlPosition>(
hint: const Text('Web camera control position'),
value: _webCameraControlPosition,
items: WebCameraControlPosition.values
.map(
(WebCameraControlPosition e) =>
DropdownMenuItem<WebCameraControlPosition>(
value: e,
child: Text(e.name),
),
)
.toList(),
onChanged: (WebCameraControlPosition? value) {
setState(
() {
_webCameraControlPosition = value;
},
);
},
),
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text(
'Ok',
),
)
],
),
);
},
),
child: const Text(
'change web camera control position',
),
);
}

Widget _compassToggler() {
return TextButton(
child: Text('${_compassEnabled ? 'disable' : 'enable'} compass'),
@@ -264,6 +327,8 @@ class MapUiBodyState extends State<MapUiBody> {
@override
Widget build(BuildContext context) {
final GoogleMap googleMap = GoogleMap(
webCameraControlEnabled: _webCameraControlEnabled,
webCameraControlPosition: _webCameraControlPosition,
onMapCreated: onMapCreated,
initialCameraPosition: _kInitialPosition,
compassEnabled: _compassEnabled,
@@ -324,6 +389,11 @@ class MapUiBodyState extends State<MapUiBody> {
_myLocationButtonToggler(),
_myTrafficToggler(),
_nightModeToggler(),
if (kIsWeb) ...<Widget>[
_webCameraControlToggler(),
if (_webCameraControlEnabled)
_webCameraControlPositionToggler(),
]
],
),
),
Original file line number Diff line number Diff line change
@@ -21,6 +21,13 @@ dependencies:
google_maps_flutter_android: ^2.16.1
google_maps_flutter_platform_interface: ^2.12.1


# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.
# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins
dependency_overrides:
google_maps_flutter_platform_interface: {path: ../../../../packages/google_maps_flutter/google_maps_flutter_platform_interface}
google_maps_flutter_web: {path: ../../../../packages/google_maps_flutter/google_maps_flutter_web}

dev_dependencies:
build_runner: ^2.1.10
espresso: ^0.4.0
Original file line number Diff line number Diff line change
@@ -56,6 +56,7 @@ export 'package:google_maps_flutter_platform_interface/google_maps_flutter_platf
TileOverlay,
TileOverlayId,
TileProvider,
WebCameraControlPosition,
WebGestureHandling,
WeightedLatLng;

Original file line number Diff line number Diff line change
@@ -95,6 +95,8 @@ class GoogleMap extends StatefulWidget {
this.onMapCreated,
this.gestureRecognizers = const <Factory<OneSequenceGestureRecognizer>>{},
this.webGestureHandling,
this.webCameraControlPosition,
this.webCameraControlEnabled = true,
this.compassEnabled = true,
this.mapToolbarEnabled = true,
this.cameraTargetBounds = CameraTargetBounds.unbounded,
@@ -349,6 +351,18 @@ class GoogleMap extends StatefulWidget {
/// See [WebGestureHandling] for more details.
final WebGestureHandling? webGestureHandling;

/// This setting controls how the API handles cameraControl button position on the map. Web only.
///
/// If null, the Google Maps API will use its default camera control position.
///
/// See [WebCameraControlPosition] for more details.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment should describe what happens if this is null.

final WebCameraControlPosition? webCameraControlPosition;

/// Enables or disables the Camera controls. Web only.
///
/// See https://developers.google.com/maps/documentation/javascript/controls for more details.
final bool webCameraControlEnabled;

/// Identifier that's associated with a specific cloud-based map style.
///
/// See https://developers.google.com/maps/documentation/get-map-id
@@ -652,6 +666,8 @@ class _GoogleMapState extends State<GoogleMap> {
/// Builds a [MapConfiguration] from the given [map].
MapConfiguration _configurationFromMapWidget(GoogleMap map) {
return MapConfiguration(
webCameraControlPosition: map.webCameraControlPosition,
webCameraControlEnabled: map.webCameraControlEnabled,
webGestureHandling: map.webGestureHandling,
compassEnabled: map.compassEnabled,
mapToolbarEnabled: map.mapToolbarEnabled,
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ name: google_maps_flutter
description: A Flutter plugin for integrating Google Maps in iOS and Android applications.
repository: https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22
version: 2.12.3
version: 2.13.0

environment:
sdk: ^3.6.0
@@ -26,6 +26,12 @@ dependencies:
google_maps_flutter_platform_interface: ^2.12.1
google_maps_flutter_web: ^0.5.12

# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.
# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins
dependency_overrides:
google_maps_flutter_platform_interface: {path: ../../../packages/google_maps_flutter/google_maps_flutter_platform_interface}
google_maps_flutter_web: {path: ../../../packages/google_maps_flutter/google_maps_flutter_web}

dev_dependencies:
flutter_test:
sdk: flutter
Original file line number Diff line number Diff line change
@@ -32,4 +32,4 @@ dev_dependencies:
flutter:
uses-material-design: true
assets:
- assets/
- assets/
Original file line number Diff line number Diff line change
@@ -36,4 +36,4 @@ dev_dependencies:
topics:
- google-maps
- google-maps-flutter
- map
- map
Original file line number Diff line number Diff line change
@@ -31,4 +31,4 @@ dev_dependencies:
flutter:
uses-material-design: true
assets:
- assets/
- assets/
Original file line number Diff line number Diff line change
@@ -31,4 +31,4 @@ dev_dependencies:
flutter:
uses-material-design: true
assets:
- assets/
- assets/
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.13.0

* Adds support for disabling or moving the camera control button on web.

## 2.12.1

* Fixes the `zIndex` issue in the `copyWith` method.
Original file line number Diff line number Diff line change
@@ -15,6 +15,8 @@ class MapConfiguration {
/// as either a full configuration selection, or an update to an existing
/// configuration where only non-null values are updated.
const MapConfiguration({
this.webCameraControlPosition,
this.webCameraControlEnabled,
this.webGestureHandling,
this.compassEnabled,
this.mapToolbarEnabled,
@@ -44,6 +46,18 @@ class MapConfiguration {
/// See [WebGestureHandling] for more details.
final WebGestureHandling? webGestureHandling;

/// This setting controls how the API handles cameraControl button position on the map. Web only.
///
/// If null, the Google Maps API will use its default camera control position.
///
/// See [WebCameraControlPosition] for more details.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment here; the null behavior should be documented.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

final WebCameraControlPosition? webCameraControlPosition;

/// This setting controls how the API handles cameraControl button on the map. Web only.
///
/// See https://developers.google.com/maps/documentation/javascript/controls for more details.
final bool? webCameraControlEnabled;

/// True if the compass UI should be shown.
final bool? compassEnabled;

@@ -123,6 +137,14 @@ class MapConfiguration {
/// that are different from [other].
MapConfiguration diffFrom(MapConfiguration other) {
return MapConfiguration(
webCameraControlPosition:
webCameraControlPosition != other.webCameraControlPosition
? webCameraControlPosition
: null,
webCameraControlEnabled:
webCameraControlEnabled != other.webCameraControlEnabled
? webCameraControlEnabled
: null,
webGestureHandling: webGestureHandling != other.webGestureHandling
? webGestureHandling
: null,
@@ -188,6 +210,10 @@ class MapConfiguration {
/// replacing the previous values.
MapConfiguration applyDiff(MapConfiguration diff) {
return MapConfiguration(
webCameraControlPosition:
diff.webCameraControlPosition ?? webCameraControlPosition,
webCameraControlEnabled:
diff.webCameraControlEnabled ?? webCameraControlEnabled,
webGestureHandling: diff.webGestureHandling ?? webGestureHandling,
compassEnabled: diff.compassEnabled ?? compassEnabled,
mapToolbarEnabled: diff.mapToolbarEnabled ?? mapToolbarEnabled,
@@ -219,6 +245,8 @@ class MapConfiguration {

/// True if no options are set.
bool get isEmpty =>
webCameraControlPosition == null &&
webCameraControlEnabled == null &&
webGestureHandling == null &&
compassEnabled == null &&
mapToolbarEnabled == null &&
@@ -251,6 +279,8 @@ class MapConfiguration {
return false;
}
return other is MapConfiguration &&
webCameraControlPosition == other.webCameraControlPosition &&
webCameraControlEnabled == other.webCameraControlEnabled &&
webGestureHandling == other.webGestureHandling &&
compassEnabled == other.compassEnabled &&
mapToolbarEnabled == other.mapToolbarEnabled &&
@@ -278,6 +308,8 @@ class MapConfiguration {
@override
int get hashCode => Object.hashAll(<Object?>[
webGestureHandling,
webCameraControlPosition,
webCameraControlEnabled,
compassEnabled,
mapToolbarEnabled,
cameraTargetBounds,
Original file line number Diff line number Diff line change
@@ -44,4 +44,5 @@ export 'utils/marker.dart';
export 'utils/polygon.dart';
export 'utils/polyline.dart';
export 'utils/tile_overlay.dart';
export 'web_camera_control_position.dart';
export 'web_gesture_handling.dart';
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Identifiers used to specify the placement of controls on the map.
// Controls are positioned relative to other controls in the same layout position.
// Controls that are added first are positioned closer to the edge of the map.
// Usage of "logical values"
// (see https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_logical_properties_and_values)
// is recommended in order to be able to automatically support both
// left-to-right (LTR) and right-to-left (RTL) layout contexts.

// Elements in the top or bottom row flow towards the middle of the row.
// Elements in the left or right column flow towards the middle of the column.

/// This setting controls how the API handles camera control button on the map
/// See https://developers.google.com/maps/documentation/javascript/reference/control#ControlPosition for more details.
enum WebCameraControlPosition {
/// Equivalent to BOTTOM_CENTER in both LTR and RTL.
blockEndInlineCenter,

/// Equivalent to BOTTOM_LEFT in LTR, or BOTTOM_RIGHT in RTL.
blockEndInlineStart,

/// EEquivalent to TOP_RIGHT in LTR, or TOP_LEFT in RTL.
blockEndInlineEnd,

/// Equivalent to TOP_CENTER in both LTR and RTL.
blockStartInlineCenter,

/// Equivalent to TOP_LEFT in LTR, or TOP_RIGHT in RTL.
blockStartInlineStart,

/// Equivalent to TOP_RIGHT in LTR, or TOP_LEFT in RTL.
blockStartInlineEnd,

/// Elements are positioned in the center of the bottom row.
/// Consider using BLOCK_END_INLINE_CENTER instead.
bottomCenter,

/// Elements are positioned in the bottom left and flow towards the middle.
/// Elements are positioned to the right of the Google logo.
/// Consider using BLOCK_END_INLINE_START instead.
bottomLeft,

/// Elements are positioned in the bottom right and flow towards the middle.
/// Elements are positioned to the left of the copyrights.
/// Consider using BLOCK_END_INLINE_END instead.
bottomRight,

/// Equivalent to RIGHT_CENTER in LTR, or LEFT_CENTER in RTL.
inlineEndBlockCenter,

/// Equivalent to RIGHT_BOTTOM in LTR, or LEFT_BOTTOM in RTL.
inlineEndBlockEnd,

/// Equivalent to RIGHT_TOP in LTR, or LEFT_TOP in RTL.
inlineEndBlockStart,

/// Equivalent to LEFT_CENTER in LTR, or RIGHT_CENTER in RTL.
inlineStartBlockCenter,

/// Equivalent to LEFT_BOTTOM in LTR, or RIGHT_BOTTOM in RTL.
inlineStartBlockEnd,

/// Equivalent to LEFT_TOP in LTR, or RIGHT_TOP in RTL.
inlineStartBlockStart,

/// Elements are positioned on the left, above bottom-left elements,
/// and flow upwards. Consider using INLINE_START_BLOCK_END instead.
leftBottom,

/// Elements are positioned in the center of the left side.
/// Consider using INLINE_START_BLOCK_CENTER instead.
leftCenter,

/// Elements are positioned on the left, below top-left elements,
/// and flow downwards. Consider using INLINE_START_BLOCK_START instead.
leftTop,

/// Elements are positioned on the right, above bottom-right elements,
/// and flow upwards. Consider using INLINE_END_BLOCK_END instead.
rightBottom,

/// Elements are positioned in the center of the right side.
/// Consider using INLINE_END_BLOCK_CENTER instead.
rightCenter,

/// Elements are positioned on the right, below top-right elements,
/// and flow downwards. Consider using INLINE_END_BLOCK_START instead.
rightTop,

/// Elements are positioned in the center of the top row.
/// Consider using BLOCK_START_INLINE_CENTER instead.
topCenter,

/// Elements are positioned in the top left and flow towards the middle.
/// Consider using BLOCK_START_INLINE_START instead.
topLeft,

/// Elements are positioned in the top right and flow towards the middle.
/// Consider using BLOCK_START_INLINE_END instead.
topRight,
}
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ repository: https://github.com/flutter/packages/tree/main/packages/google_maps_f
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22
# NOTE: We strongly prefer non-breaking changes, even at the expense of a
# less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
version: 2.12.1
version: 2.13.0

environment:
sdk: ^3.6.0
Original file line number Diff line number Diff line change
@@ -12,6 +12,8 @@ void main() {
group('diffs', () {
// A options instance with every field set, to test diffs against.
final MapConfiguration diffBase = MapConfiguration(
webCameraControlPosition: WebCameraControlPosition.topRight,
webCameraControlEnabled: false,
webGestureHandling: WebGestureHandling.auto,
compassEnabled: false,
mapToolbarEnabled: false,
@@ -59,6 +61,7 @@ void main() {
expect(updated.padding, isNot(null));
expect(updated.trafficEnabled, isNot(null));
expect(updated.cloudMapId, null);
expect(updated.webCameraControlPosition, isNot(null));
});

test('handle webGestureHandling', () async {
@@ -78,6 +81,42 @@ void main() {
expect(empty.hashCode, isNot(diff.hashCode));
});

test('handle webCameraControlPosition', () async {
const MapConfiguration diff = MapConfiguration(
webCameraControlPosition: WebCameraControlPosition.blockEndInlineEnd,
);

const MapConfiguration empty = MapConfiguration();
final MapConfiguration updated = diffBase.applyDiff(diff);

// A diff applied to empty options should be the diff itself.
expect(empty.applyDiff(diff), diff);
// The diff from empty options should be the diff itself.
expect(diff.diffFrom(empty), diff);
// A diff applied to non-empty options should update that field.
expect(updated.webCameraControlPosition,
WebCameraControlPosition.blockEndInlineEnd);
// The hash code should change.
expect(empty.hashCode, isNot(diff.hashCode));
});

test('handle webCameraControlEnabled', () async {
const MapConfiguration diff =
MapConfiguration(webCameraControlEnabled: true);

const MapConfiguration empty = MapConfiguration();
final MapConfiguration updated = diffBase.applyDiff(diff);

// A diff applied to empty options should be the diff itself.
expect(empty.applyDiff(diff), diff);
// The diff from empty options should be the diff itself.
expect(diff.diffFrom(empty), diff);
// A diff applied to non-empty options should update that field.
expect(updated.webCameraControlEnabled, true);
// The hash code should change.
expect(empty.hashCode, isNot(diff.hashCode));
});

test('handle compassEnabled', () async {
const MapConfiguration diff = MapConfiguration(compassEnabled: true);

@@ -435,6 +474,13 @@ void main() {
expect(nullOptions.isEmpty, true);
});

test('is false with webCameraControlEnabled', () async {
const MapConfiguration diff =
MapConfiguration(webCameraControlEnabled: true);

expect(diff.isEmpty, false);
});

test('is false with compassEnabled', () async {
const MapConfiguration diff = MapConfiguration(compassEnabled: true);

Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.5.13

* Adds support to camera control button.

## 0.5.12+2

* Fix broken cameraTargetBounds option on web.
Original file line number Diff line number Diff line change
@@ -28,9 +28,8 @@ flutter:
assets:
- assets/

# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.
# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins
dependency_overrides:
# Override the google_maps_flutter dependency on google_maps_flutter_web.
# TODO(ditman): Unwind the circular dependency. This will create problems
# if we need to make a breaking change to google_maps_flutter_web.
google_maps_flutter_web:
path: ../
google_maps_flutter_platform_interface: {path: ../../../../packages/google_maps_flutter/google_maps_flutter_platform_interface}
google_maps_flutter_web: {path: ../}
Original file line number Diff line number Diff line change
@@ -91,6 +91,16 @@ gmaps.MapOptions _configurationAndStyleToGmapsOptions(
options.gestureHandling = WebGestureHandling.auto.name;
}

if (configuration.webCameraControlEnabled != null) {
options.cameraControl = configuration.webCameraControlEnabled;
}

if (configuration.webCameraControlPosition != null) {
options.cameraControlOptions = gmaps.CameraControlOptions(
position: _toControlPosition(configuration.webCameraControlPosition!),
);
}

if (configuration.fortyFiveDegreeImageryEnabled != null) {
options.rotateControl = configuration.fortyFiveDegreeImageryEnabled;
}
@@ -737,3 +747,59 @@ gmaps.LatLng _pixelToLatLng(gmaps.Map map, int x, int y) {

return projection.fromPointToLatLng(point)!;
}

/// Converts a [WebCameraControlPosition] to [gmaps.ControlPosition].
gmaps.ControlPosition _toControlPosition(
WebCameraControlPosition webCameraControlPosition,
) {
switch (webCameraControlPosition) {
case WebCameraControlPosition.blockEndInlineCenter:
return gmaps.ControlPosition.BLOCK_END_INLINE_CENTER;
case WebCameraControlPosition.blockEndInlineEnd:
return gmaps.ControlPosition.BLOCK_END_INLINE_END;
case WebCameraControlPosition.blockEndInlineStart:
return gmaps.ControlPosition.BLOCK_END_INLINE_START;
case WebCameraControlPosition.blockStartInlineCenter:
return gmaps.ControlPosition.BLOCK_START_INLINE_CENTER;
case WebCameraControlPosition.blockStartInlineEnd:
return gmaps.ControlPosition.BLOCK_START_INLINE_END;
case WebCameraControlPosition.blockStartInlineStart:
return gmaps.ControlPosition.BLOCK_START_INLINE_START;
case WebCameraControlPosition.bottomCenter:
return gmaps.ControlPosition.BOTTOM_CENTER;
case WebCameraControlPosition.bottomLeft:
return gmaps.ControlPosition.BOTTOM_LEFT;
case WebCameraControlPosition.bottomRight:
return gmaps.ControlPosition.BOTTOM_RIGHT;
case WebCameraControlPosition.inlineEndBlockCenter:
return gmaps.ControlPosition.INLINE_END_BLOCK_CENTER;
case WebCameraControlPosition.inlineEndBlockEnd:
return gmaps.ControlPosition.INLINE_END_BLOCK_END;
case WebCameraControlPosition.inlineEndBlockStart:
return gmaps.ControlPosition.INLINE_END_BLOCK_START;
case WebCameraControlPosition.inlineStartBlockCenter:
return gmaps.ControlPosition.INLINE_START_BLOCK_CENTER;
case WebCameraControlPosition.inlineStartBlockEnd:
return gmaps.ControlPosition.INLINE_START_BLOCK_END;
case WebCameraControlPosition.inlineStartBlockStart:
return gmaps.ControlPosition.INLINE_START_BLOCK_START;
case WebCameraControlPosition.leftBottom:
return gmaps.ControlPosition.LEFT_BOTTOM;
case WebCameraControlPosition.leftCenter:
return gmaps.ControlPosition.LEFT_CENTER;
case WebCameraControlPosition.leftTop:
return gmaps.ControlPosition.LEFT_TOP;
case WebCameraControlPosition.rightBottom:
return gmaps.ControlPosition.RIGHT_BOTTOM;
case WebCameraControlPosition.rightCenter:
return gmaps.ControlPosition.RIGHT_CENTER;
case WebCameraControlPosition.rightTop:
return gmaps.ControlPosition.RIGHT_TOP;
case WebCameraControlPosition.topCenter:
return gmaps.ControlPosition.TOP_CENTER;
case WebCameraControlPosition.topLeft:
return gmaps.ControlPosition.TOP_LEFT;
case WebCameraControlPosition.topRight:
return gmaps.ControlPosition.TOP_RIGHT;
}
}
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ name: google_maps_flutter_web
description: Web platform implementation of google_maps_flutter
repository: https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter_web
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22
version: 0.5.12+2
version: 0.5.13

environment:
sdk: ^3.6.0
@@ -28,6 +28,13 @@ dependencies:
stream_transform: ^2.0.0
web: ">=0.5.1 <2.0.0"

# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.
# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins
dependency_overrides:
google_maps_flutter_platform_interface: {path: ../../../packages/google_maps_flutter/google_maps_flutter_platform_interface}



dev_dependencies:
flutter_test:
sdk: flutter