diff --git a/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml index 364d9b62d3c..3c90433879d 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml @@ -19,7 +19,7 @@ dependencies: # the parent directory to use the current plugin's version. path: ../ google_maps_flutter_android: ^2.1.10 - google_maps_flutter_platform_interface: ^2.2.1 + google_maps_flutter_platform_interface: ^2.4.0 dev_dependencies: build_runner: ^2.1.10 diff --git a/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md index 7ce99409ddd..6a0d40f1eff 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md @@ -1,8 +1,10 @@ -## NEXT +## 2.5.0 +* Adds implementation for `cloudMapId` parameter to support cloud-based map styling. * Updates minimum supported SDK version to Flutter 3.7/Dart 2.19. ## 2.4.16 + * Removes old empty override methods. * Fixes unawaited_futures violations. diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java index ad5179a69a4..fa82b77743d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java @@ -55,6 +55,10 @@ void setInitialCameraPosition(CameraPosition position) { options.camera(position); } + public void setMapId(String mapId) { + options.mapId(mapId); + } + @Override public void setCompassEnabled(boolean compassEnabled) { options.compassEnabled(compassEnabled); diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java index f7bf1f9d7ac..c4f6a98b6cf 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapFactory.java @@ -37,7 +37,8 @@ public PlatformView create(@NonNull Context context, int id, @Nullable Object ar Map params = (Map) args; final GoogleMapBuilder builder = new GoogleMapBuilder(); - Convert.interpretGoogleMapOptions(params.get("options"), builder); + final Object options = params.get("options"); + Convert.interpretGoogleMapOptions(options, builder); if (params.containsKey("initialCameraPosition")) { CameraPosition position = Convert.toCameraPosition(params.get("initialCameraPosition")); builder.setInitialCameraPosition(position); @@ -57,6 +58,11 @@ public PlatformView create(@NonNull Context context, int id, @Nullable Object ar if (params.containsKey("tileOverlaysToAdd")) { builder.setInitialTileOverlays((List>) params.get("tileOverlaysToAdd")); } + final Object cloudMapId = ((Map) options).get("cloudMapId"); + if (cloudMapId != null) { + builder.setMapId((String) cloudMapId); + } + return builder.build(id, context, binaryMessenger, lifecycleProvider); } } diff --git a/packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/google_maps_tests.dart b/packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/google_maps_tests.dart index a0a9d3049c7..d22767c44c2 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/google_maps_tests.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/example/integration_test/google_maps_tests.dart @@ -17,6 +17,7 @@ const LatLng _kInitialMapCenter = LatLng(0, 0); const double _kInitialZoomLevel = 5; const CameraPosition _kInitialCameraPosition = CameraPosition(target: _kInitialMapCenter, zoom: _kInitialZoomLevel); +const String _kCloudMapId = '000000000000000'; // Dummy map ID. void googleMapsTests() { GoogleMapsFlutterPlatform.instance.enableDebugInspection(); @@ -1178,6 +1179,32 @@ void googleMapsTests() { expect(tileOverlayInfo1, isNull); }, ); + + testWidgets( + 'testCloudMapId', + (WidgetTester tester) async { + final Completer mapIdCompleter = Completer(); + final Key key = GlobalKey(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + cloudMapId: _kCloudMapId, + ), + ), + ); + + // Await mapIdCompleter to finish to make sure map can be created with styledMapId + // Styled map + await mapIdCompleter.future; + }, + ); } class _DebugTileProvider implements TileProvider { diff --git a/packages/google_maps_flutter/google_maps_flutter_android/example/lib/example_google_map.dart b/packages/google_maps_flutter/google_maps_flutter_android/example/lib/example_google_map.dart index 1d791d909cd..f176b987e28 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/example/lib/example_google_map.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/example/lib/example_google_map.dart @@ -244,6 +244,7 @@ class ExampleGoogleMap extends StatefulWidget { this.onCameraIdle, this.onTap, this.onLongPress, + this.cloudMapId, }); /// Callback method for when the map is ready to be used. @@ -346,6 +347,12 @@ class ExampleGoogleMap extends StatefulWidget { /// Which gestures should be consumed by the map. final Set> gestureRecognizers; + /// Identifier that's associated with a specific cloud-based map style. + /// + /// See https://developers.google.com/maps/documentation/get-map-id + /// for more details. + final String? cloudMapId; + /// Creates a [State] for this [ExampleGoogleMap]. @override State createState() => _ExampleGoogleMapState(); @@ -531,5 +538,6 @@ MapConfiguration _configurationFromMapWidget(ExampleGoogleMap map) { indoorViewEnabled: map.indoorViewEnabled, trafficEnabled: map.trafficEnabled, buildingsEnabled: map.buildingsEnabled, + cloudMapId: map.cloudMapId, ); } diff --git a/packages/google_maps_flutter/google_maps_flutter_android/example/lib/main.dart b/packages/google_maps_flutter/google_maps_flutter_android/example/lib/main.dart index cc9ef7e29ac..9b9c32aad96 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/example/lib/main.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/example/lib/main.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:google_maps_flutter_android/google_maps_flutter_android.dart'; import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; @@ -10,6 +12,7 @@ import 'animate_camera.dart'; import 'lite_mode.dart'; import 'map_click.dart'; import 'map_coordinates.dart'; +import 'map_map_id.dart'; import 'map_ui.dart'; import 'marker_icons.dart'; import 'move_camera.dart'; @@ -39,6 +42,7 @@ final List _allPages = [ const SnapshotPage(), const LiteModePage(), const TileOverlayPage(), + const MapIdPage(), ]; /// MapsDemo is the Main Application. @@ -74,5 +78,32 @@ void main() { final GoogleMapsFlutterPlatform platform = GoogleMapsFlutterPlatform.instance; // Default to Hybrid Composition for the example. (platform as GoogleMapsFlutterAndroid).useAndroidViewSurface = true; + initializeMapRenderer(); runApp(const MaterialApp(home: MapsDemo())); } + +Completer? _initializedRendererCompleter; + +/// Initializes map renderer to the `latest` renderer type. +/// +/// The renderer must be requested before creating GoogleMap instances, +/// as the renderer can be initialized only once per application context. +Future initializeMapRenderer() async { + if (_initializedRendererCompleter != null) { + return _initializedRendererCompleter!.future; + } + + final Completer completer = + Completer(); + _initializedRendererCompleter = completer; + + WidgetsFlutterBinding.ensureInitialized(); + + final GoogleMapsFlutterPlatform platform = GoogleMapsFlutterPlatform.instance; + unawaited((platform as GoogleMapsFlutterAndroid) + .initializeWithRenderer(AndroidMapRenderer.latest) + .then((AndroidMapRenderer initializedRenderer) => + completer.complete(initializedRenderer))); + + return completer.future; +} diff --git a/packages/google_maps_flutter/google_maps_flutter_android/example/lib/map_map_id.dart b/packages/google_maps_flutter/google_maps_flutter_android/example/lib/map_map_id.dart new file mode 100644 index 00000000000..984e32a8ea5 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_android/example/lib/map_map_id.dart @@ -0,0 +1,138 @@ +// 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. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_android/google_maps_flutter_android.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'main.dart'; +import 'page.dart'; + +class MapIdPage extends GoogleMapExampleAppPage { + const MapIdPage({Key? key}) + : super(const Icon(Icons.map), 'Cloud-based maps styling', key: key); + + @override + Widget build(BuildContext context) { + return const MapIdBody(); + } +} + +class MapIdBody extends StatefulWidget { + const MapIdBody({super.key}); + + @override + State createState() => MapIdBodyState(); +} + +const LatLng _kMapCenter = LatLng(52.4478, -3.5402); + +class MapIdBodyState extends State { + ExampleGoogleMapController? controller; + + Key _key = const Key('mapId#'); + String? _mapId; + final TextEditingController _mapIdController = TextEditingController(); + AndroidMapRenderer? _initializedRenderer; + + @override + void initState() { + initializeMapRenderer() + .then((AndroidMapRenderer? initializedRenderer) => setState(() { + _initializedRenderer = initializedRenderer; + })); + super.initState(); + } + + String _getInitializedsRendererType() { + switch (_initializedRenderer) { + case AndroidMapRenderer.latest: + return 'latest'; + case AndroidMapRenderer.legacy: + return 'legacy'; + case AndroidMapRenderer.platformDefault: + case null: + break; + } + return 'unknown'; + } + + void _setMapId() { + setState(() { + _mapId = _mapIdController.text; + + // Change key to initialize new map instance for new mapId. + _key = Key(_mapId ?? 'mapId#'); + }); + } + + @override + Widget build(BuildContext context) { + final ExampleGoogleMap googleMap = ExampleGoogleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: const CameraPosition( + target: _kMapCenter, + zoom: 7.0, + ), + key: _key, + cloudMapId: _mapId, + ); + + final List columnChildren = [ + Padding( + padding: const EdgeInsets.all(10.0), + child: Center( + child: SizedBox( + width: 300.0, + height: 200.0, + child: googleMap, + ), + ), + ), + Padding( + padding: const EdgeInsets.all(10.0), + child: TextField( + controller: _mapIdController, + decoration: const InputDecoration( + hintText: 'Map Id', + ), + )), + Padding( + padding: const EdgeInsets.all(10.0), + child: ElevatedButton( + onPressed: () => _setMapId(), + child: const Text( + 'Press to use specified map Id', + ), + )), + if (_initializedRenderer != AndroidMapRenderer.latest) + Padding( + padding: const EdgeInsets.all(10.0), + child: Text( + 'On Android, Cloud-based maps styling only works with "latest" renderer.\n\n' + 'Current initialized renderer is "${_getInitializedsRendererType()}".'), + ), + ]; + + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: columnChildren, + ); + } + + @override + void dispose() { + _mapIdController.dispose(); + super.dispose(); + } + + void _onMapCreated(ExampleGoogleMapController controllerParam) { + setState(() { + controller = controllerParam; + }); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_android/example/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_android/example/pubspec.yaml index a80b3027567..6f42485f477 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/example/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_android/example/pubspec.yaml @@ -18,7 +18,7 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ - google_maps_flutter_platform_interface: ^2.2.1 + google_maps_flutter_platform_interface: ^2.4.0 dev_dependencies: build_runner: ^2.1.10 diff --git a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart index 55fb147d20e..d5a79f3e4a0 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart @@ -740,6 +740,7 @@ Map _jsonForMapConfiguration(MapConfiguration config) { if (config.trafficEnabled != null) 'trafficEnabled': config.trafficEnabled!, if (config.buildingsEnabled != null) 'buildingsEnabled': config.buildingsEnabled!, + if (config.cloudMapId != null) 'cloudMapId': config.cloudMapId!, }; } diff --git a/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml index 0c4501f36a8..3e23cae778d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml @@ -2,7 +2,7 @@ name: google_maps_flutter_android description: Android implementation of the google_maps_flutter plugin. repository: https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22 -version: 2.4.16 +version: 2.5.0 environment: sdk: ">=2.19.0 <4.0.0" @@ -21,7 +21,7 @@ dependencies: flutter: sdk: flutter flutter_plugin_android_lifecycle: ^2.0.1 - google_maps_flutter_platform_interface: ^2.2.1 + google_maps_flutter_platform_interface: ^2.4.0 stream_transform: ^2.0.0 dev_dependencies: diff --git a/packages/google_maps_flutter/google_maps_flutter_android/test/google_maps_flutter_android_test.dart b/packages/google_maps_flutter/google_maps_flutter_android/test/google_maps_flutter_android_test.dart index 29c02c836a8..a7b1b959095 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/test/google_maps_flutter_android_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/test/google_maps_flutter_android_test.dart @@ -1,6 +1,7 @@ // 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. +import 'dart:async'; import 'package:async/async.dart'; import 'package:flutter/services.dart'; @@ -168,6 +169,54 @@ void main() { expect(widget, isA()); }); + + testWidgets('cloudMapId is passed', (WidgetTester tester) async { + const String cloudMapId = '000000000000000'; // Dummy map ID. + final Completer passedCloudMapIdCompleter = Completer(); + + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler( + SystemChannels.platform_views, + (MethodCall methodCall) { + if (methodCall.method == 'create') { + final Map args = Map.from( + methodCall.arguments as Map); + if (args.containsKey('params')) { + final Uint8List paramsUint8List = args['params'] as Uint8List; + const StandardMessageCodec codec = StandardMessageCodec(); + final ByteData byteData = ByteData.sublistView(paramsUint8List); + final Map creationParams = + Map.from( + codec.decodeMessage(byteData) as Map); + if (creationParams.containsKey('options')) { + final Map options = Map.from( + creationParams['options'] as Map); + if (options.containsKey('cloudMapId')) { + passedCloudMapIdCompleter + .complete(options['cloudMapId'] as String); + } + } + } + } + return null; + }, + ); + + final GoogleMapsFlutterAndroid maps = GoogleMapsFlutterAndroid(); + + await tester.pumpWidget(maps.buildViewWithConfiguration(1, (int id) {}, + widgetConfiguration: const MapWidgetConfiguration( + initialCameraPosition: + CameraPosition(target: LatLng(0, 0), zoom: 1), + textDirection: TextDirection.ltr), + mapConfiguration: const MapConfiguration(cloudMapId: cloudMapId))); + + expect( + await passedCloudMapIdCompleter.future, + cloudMapId, + reason: 'Should pass cloudMapId on PlatformView creation message', + ); + }); } /// This allows a value of type T or T? to be treated as a value of type T?. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md index 51a04afcccc..60e44549a9a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 2.3.0 +* Adds implementation for `cloudMapId` parameter to support cloud-based maps styling. * Updates minimum supported SDK version to Flutter 3.7/Dart 2.19. * Fixes unawaited_futures violations. @@ -25,7 +26,6 @@ ## 2.1.14 * Updates links for the merge of flutter/plugins into flutter/packages. -* Updates minimum Flutter version to 3.0. ## 2.1.13 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios11/integration_test/google_maps_test.dart b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios11/integration_test/google_maps_test.dart index bb6b97e25c5..ef8cab9bd64 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios11/integration_test/google_maps_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios11/integration_test/google_maps_test.dart @@ -16,6 +16,7 @@ const LatLng _kInitialMapCenter = LatLng(0, 0); const double _kInitialZoomLevel = 5; const CameraPosition _kInitialCameraPosition = CameraPosition(target: _kInitialMapCenter, zoom: _kInitialZoomLevel); +const String _kCloudMapId = '000000000000000'; // Dummy map ID. void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); @@ -1024,6 +1025,19 @@ void main() { expect(tileOverlayInfo1, isNull); }, ); + + testWidgets('testSetStyleMapId', (WidgetTester tester) async { + final Key key = GlobalKey(); + + await tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + cloudMapId: _kCloudMapId, + ), + )); + }); } class _DebugTileProvider implements TileProvider { diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios11/lib/main.dart b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios11/lib/main.dart index 0e4efc0f788..09fa814fdcf 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios11/lib/main.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios11/lib/main.dart @@ -7,6 +7,7 @@ import 'package:maps_example_dart/animate_camera.dart'; import 'package:maps_example_dart/lite_mode.dart'; import 'package:maps_example_dart/map_click.dart'; import 'package:maps_example_dart/map_coordinates.dart'; +import 'package:maps_example_dart/map_map_id.dart'; import 'package:maps_example_dart/map_ui.dart'; import 'package:maps_example_dart/maps_demo.dart'; import 'package:maps_example_dart/marker_icons.dart'; @@ -39,5 +40,6 @@ void main() { SnapshotPage(), LiteModePage(), TileOverlayPage(), + MapIdPage(), ]))); } diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios11/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios11/pubspec.yaml index 86f3fa76a88..055ca6e6fd6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios11/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios11/pubspec.yaml @@ -18,7 +18,7 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../../ - google_maps_flutter_platform_interface: ^2.2.1 + google_maps_flutter_platform_interface: ^2.4.0 maps_example_dart: path: ../shared/maps_example_dart/ diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios12/lib/main.dart b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios12/lib/main.dart index 0e4efc0f788..09fa814fdcf 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios12/lib/main.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios12/lib/main.dart @@ -7,6 +7,7 @@ import 'package:maps_example_dart/animate_camera.dart'; import 'package:maps_example_dart/lite_mode.dart'; import 'package:maps_example_dart/map_click.dart'; import 'package:maps_example_dart/map_coordinates.dart'; +import 'package:maps_example_dart/map_map_id.dart'; import 'package:maps_example_dart/map_ui.dart'; import 'package:maps_example_dart/maps_demo.dart'; import 'package:maps_example_dart/marker_icons.dart'; @@ -39,5 +40,6 @@ void main() { SnapshotPage(), LiteModePage(), TileOverlayPage(), + MapIdPage(), ]))); } diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios12/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios12/pubspec.yaml index 86f3fa76a88..055ca6e6fd6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios12/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios12/pubspec.yaml @@ -18,7 +18,7 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../../ - google_maps_flutter_platform_interface: ^2.2.1 + google_maps_flutter_platform_interface: ^2.4.0 maps_example_dart: path: ../shared/maps_example_dart/ diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios13/lib/main.dart b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios13/lib/main.dart index 0e4efc0f788..09fa814fdcf 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios13/lib/main.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios13/lib/main.dart @@ -7,6 +7,7 @@ import 'package:maps_example_dart/animate_camera.dart'; import 'package:maps_example_dart/lite_mode.dart'; import 'package:maps_example_dart/map_click.dart'; import 'package:maps_example_dart/map_coordinates.dart'; +import 'package:maps_example_dart/map_map_id.dart'; import 'package:maps_example_dart/map_ui.dart'; import 'package:maps_example_dart/maps_demo.dart'; import 'package:maps_example_dart/marker_icons.dart'; @@ -39,5 +40,6 @@ void main() { SnapshotPage(), LiteModePage(), TileOverlayPage(), + MapIdPage(), ]))); } diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios13/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios13/pubspec.yaml index 86f3fa76a88..055ca6e6fd6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios13/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios13/pubspec.yaml @@ -18,7 +18,7 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../../ - google_maps_flutter_platform_interface: ^2.2.1 + google_maps_flutter_platform_interface: ^2.4.0 maps_example_dart: path: ../shared/maps_example_dart/ diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/shared/maps_example_dart/lib/example_google_map.dart b/packages/google_maps_flutter/google_maps_flutter_ios/example/shared/maps_example_dart/lib/example_google_map.dart index 1d791d909cd..f176b987e28 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/shared/maps_example_dart/lib/example_google_map.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/shared/maps_example_dart/lib/example_google_map.dart @@ -244,6 +244,7 @@ class ExampleGoogleMap extends StatefulWidget { this.onCameraIdle, this.onTap, this.onLongPress, + this.cloudMapId, }); /// Callback method for when the map is ready to be used. @@ -346,6 +347,12 @@ class ExampleGoogleMap extends StatefulWidget { /// Which gestures should be consumed by the map. final Set> gestureRecognizers; + /// Identifier that's associated with a specific cloud-based map style. + /// + /// See https://developers.google.com/maps/documentation/get-map-id + /// for more details. + final String? cloudMapId; + /// Creates a [State] for this [ExampleGoogleMap]. @override State createState() => _ExampleGoogleMapState(); @@ -531,5 +538,6 @@ MapConfiguration _configurationFromMapWidget(ExampleGoogleMap map) { indoorViewEnabled: map.indoorViewEnabled, trafficEnabled: map.trafficEnabled, buildingsEnabled: map.buildingsEnabled, + cloudMapId: map.cloudMapId, ); } diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/shared/maps_example_dart/lib/map_map_id.dart b/packages/google_maps_flutter/google_maps_flutter_ios/example/shared/maps_example_dart/lib/map_map_id.dart new file mode 100644 index 00000000000..037bafd8a35 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/shared/maps_example_dart/lib/map_map_id.dart @@ -0,0 +1,108 @@ +// 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. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +class MapIdPage extends GoogleMapExampleAppPage { + const MapIdPage({Key? key}) + : super(const Icon(Icons.map), 'Cloud-based maps styling', key: key); + + @override + Widget build(BuildContext context) { + return const MapIdBody(); + } +} + +class MapIdBody extends StatefulWidget { + const MapIdBody({super.key}); + + @override + State createState() => MapIdBodyState(); +} + +const LatLng _kMapCenter = LatLng(52.4478, -3.5402); + +class MapIdBodyState extends State { + ExampleGoogleMapController? controller; + + Key _key = const Key('mapId#'); + String? _mapId; + final TextEditingController _mapIdController = TextEditingController(); + + void _setMapId() { + setState(() { + _mapId = _mapIdController.text; + + // Change key to initialize new map instance for new mapId. + _key = Key(_mapId ?? 'mapId#'); + }); + } + + @override + Widget build(BuildContext context) { + final ExampleGoogleMap googleMap = ExampleGoogleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: const CameraPosition( + target: _kMapCenter, + zoom: 7.0, + ), + key: _key, + cloudMapId: _mapId, + ); + + final List columnChildren = [ + Padding( + padding: const EdgeInsets.all(10.0), + child: Center( + child: SizedBox( + width: 300.0, + height: 200.0, + child: googleMap, + ), + ), + ), + Padding( + padding: const EdgeInsets.all(10.0), + child: TextField( + controller: _mapIdController, + decoration: const InputDecoration( + hintText: 'Map Id', + ), + ), + ), + Padding( + padding: const EdgeInsets.all(10.0), + child: ElevatedButton( + onPressed: () => _setMapId(), + child: const Text( + 'Press to use specified map Id', + ), + ), + ) + ]; + + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: columnChildren, + ); + } + + @override + void dispose() { + _mapIdController.dispose(); + super.dispose(); + } + + void _onMapCreated(ExampleGoogleMapController controllerParam) { + setState(() { + controller = controllerParam; + }); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/shared/maps_example_dart/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_ios/example/shared/maps_example_dart/pubspec.yaml index 095292153b8..081f506b501 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/shared/maps_example_dart/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/shared/maps_example_dart/pubspec.yaml @@ -18,7 +18,7 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../../../ - google_maps_flutter_platform_interface: ^2.2.1 + google_maps_flutter_platform_interface: ^2.4.0 dev_dependencies: flutter_test: diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.m b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.m index f85f4344849..b85ffc3fd7c 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.m @@ -78,7 +78,23 @@ - (instancetype)initWithFrame:(CGRect)frame registrar:(NSObject *)registrar { GMSCameraPosition *camera = [FLTGoogleMapJSONConversions cameraPostionFromDictionary:args[@"initialCameraPosition"]]; - GMSMapView *mapView = [GMSMapView mapWithFrame:frame camera:camera]; + GMSMapView *mapView; + id mapID = nil; + NSString *cloudMapId = args[@"options"][@"cloudMapId"]; + + if (cloudMapId) { + Class mapIDClass = NSClassFromString(@"GMSMapID"); + if (mapIDClass && [mapIDClass respondsToSelector:@selector(mapIDWithIdentifier:)]) { + mapID = [mapIDClass mapIDWithIdentifier:cloudMapId]; + } + } + + if (mapID && [GMSMapView respondsToSelector:@selector(mapWithFrame:mapID:camera:)]) { + mapView = [GMSMapView mapWithFrame:frame mapID:mapID camera:camera]; + } else { + mapView = [GMSMapView mapWithFrame:frame camera:camera]; + } + return [self initWithMapView:mapView viewIdentifier:viewId arguments:args registrar:registrar]; } diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/lib/src/google_maps_flutter_ios.dart b/packages/google_maps_flutter/google_maps_flutter_ios/lib/src/google_maps_flutter_ios.dart index 9aefc2f4f83..782e326f370 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/lib/src/google_maps_flutter_ios.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios/lib/src/google_maps_flutter_ios.dart @@ -630,6 +630,7 @@ Map _jsonForMapConfiguration(MapConfiguration config) { if (config.trafficEnabled != null) 'trafficEnabled': config.trafficEnabled!, if (config.buildingsEnabled != null) 'buildingsEnabled': config.buildingsEnabled!, + if (config.cloudMapId != null) 'cloudMapId': config.cloudMapId!, }; } diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml index 83bd417d3b9..90a3adddcfd 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml @@ -2,7 +2,7 @@ name: google_maps_flutter_ios description: iOS implementation of the google_maps_flutter plugin. repository: https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter_ios issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22 -version: 2.2.3 +version: 2.3.0 environment: sdk: ">=2.19.0 <4.0.0" @@ -19,7 +19,7 @@ flutter: dependencies: flutter: sdk: flutter - google_maps_flutter_platform_interface: ^2.2.1 + google_maps_flutter_platform_interface: ^2.4.0 stream_transform: ^2.0.0 dev_dependencies: diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/test/google_maps_flutter_ios_test.dart b/packages/google_maps_flutter/google_maps_flutter_ios/test/google_maps_flutter_ios_test.dart index a5d376da168..3ae9b3284a2 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/test/google_maps_flutter_ios_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios/test/google_maps_flutter_ios_test.dart @@ -1,9 +1,11 @@ // 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. +import 'dart:async'; import 'package:async/async.dart'; import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:google_maps_flutter_ios/google_maps_flutter_ios.dart'; import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; @@ -126,6 +128,56 @@ void main() { expect((await markerDragEndStream.next).value.value, equals('drag-end-marker')); }); + + testWidgets('cloudMapId is passed', (WidgetTester tester) async { + const String cloudMapId = '000000000000000'; // Dummy map ID. + final Completer passedCloudMapIdCompleter = Completer(); + + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler( + SystemChannels.platform_views, + (MethodCall methodCall) { + if (methodCall.method == 'create') { + final Map args = Map.from( + methodCall.arguments as Map); + if (args.containsKey('params')) { + final Uint8List paramsUint8List = args['params'] as Uint8List; + const StandardMessageCodec codec = StandardMessageCodec(); + final ByteData byteData = ByteData.sublistView(paramsUint8List); + final Map creationParams = + Map.from( + codec.decodeMessage(byteData) as Map); + if (creationParams.containsKey('options')) { + final Map options = Map.from( + creationParams['options'] as Map); + if (options.containsKey('cloudMapId')) { + passedCloudMapIdCompleter + .complete(options['cloudMapId'] as String); + } + } + } + } + return null; + }, + ); + + final GoogleMapsFlutterIOS maps = GoogleMapsFlutterIOS(); + + await tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: maps.buildViewWithConfiguration(1, (int id) {}, + widgetConfiguration: const MapWidgetConfiguration( + initialCameraPosition: + CameraPosition(target: LatLng(0, 0), zoom: 1), + textDirection: TextDirection.ltr), + mapConfiguration: const MapConfiguration(cloudMapId: cloudMapId)))); + + expect( + await passedCloudMapIdCompleter.future, + cloudMapId, + reason: 'Should pass cloudMapId on PlatformView creation message', + ); + }); } /// This allows a value of type T or T? to be treated as a value of type T?. diff --git a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md index 77a934d9b15..00104c96880 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_web/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 0.5.4 +* Adds implementation for `cloudMapId` parameter to support cloud-based maps styling. * Updates minimum supported SDK version to Flutter 3.7/Dart 2.19. ## 0.5.3 diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart index fda38f29b52..51c36a55a47 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/integration_test/google_maps_controller_test.dart @@ -13,6 +13,11 @@ import 'package:google_maps_flutter_web/google_maps_flutter_web.dart'; import 'package:integration_test/integration_test.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; +import 'google_maps_controller_test.mocks.dart'; + +// This value is used when comparing long~num, like +// LatLng values. +const String _kCloudMapId = '000000000000000'; // Dummy map ID. @GenerateNiceMocks(>[ MockSpec(), @@ -21,7 +26,6 @@ import 'package:mockito/mockito.dart'; MockSpec(), MockSpec(), ]) -import 'google_maps_controller_test.mocks.dart'; /// Test Google Map Controller void main() { @@ -361,6 +365,7 @@ void main() { mapConfiguration: const MapConfiguration( mapType: MapType.satellite, zoomControlsEnabled: true, + cloudMapId: _kCloudMapId, fortyFiveDegreeImageryEnabled: false, )); controller.debugSetOverrides( @@ -374,6 +379,7 @@ void main() { expect(capturedOptions, isNotNull); expect(capturedOptions!.mapTypeId, gmaps.MapTypeId.SATELLITE); expect(capturedOptions!.zoomControl, true); + expect(capturedOptions!.mapId, _kCloudMapId); expect(capturedOptions!.gestureHandling, 'auto', reason: 'by default the map handles zoom/pan gestures internally'); diff --git a/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml index c91fefa4604..080115fb80e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_web/example/pubspec.yaml @@ -9,7 +9,7 @@ environment: dependencies: flutter: sdk: flutter - google_maps_flutter_platform_interface: ^2.2.1 + google_maps_flutter_platform_interface: ^2.4.0 google_maps_flutter_web: path: ../ diff --git a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart index 1e5e9192c45..01c5f5e65a7 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart +++ b/packages/google_maps_flutter/google_maps_flutter_web/lib/src/convert.dart @@ -82,6 +82,8 @@ gmaps.MapOptions _configurationAndStyleToGmapsOptions( options.styles = styles; + options.mapId = configuration.cloudMapId; + return options; } diff --git a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml index 487519401f7..9532ae93e81 100644 --- a/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_web/pubspec.yaml @@ -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.3 +version: 0.5.4 environment: sdk: ">=2.19.0 <4.0.0"