Skip to content

Commit 9627de9

Browse files
[google_maps_flutter] Move iOS inspector to Pigeon (flutter#6937)
Converts the inspector API (only intended for use in integration tests) of the iOS implementation to Pigeon. This is a small, simple API surface to start the migration with, allowing setting up the basic Pigeon plumbing without major changes. For the cases where the API would always return a hard-coded value due to that query not applying on iOS, that hard-coding has been moved to the Dart side per the general practice of doing logic in Dart rather than native code when convenient. On the Dart side, this is largely identical to flutter/packages#6958 Part of flutter#117907
1 parent cbfffa6 commit 9627de9

13 files changed

+1102
-103
lines changed

packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 2.8.2
2+
3+
* Converts inspector interface platform calls to Pigeon.
4+
15
## 2.8.1
26

37
* Improves Objective-C type handling.

packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapTileOverlayController.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@
88
NS_ASSUME_NONNULL_BEGIN
99

1010
@interface FLTGoogleMapTileOverlayController : NSObject
11+
/// The layer managed by this controller instance.
12+
@property(readonly, nonatomic) GMSTileLayer *layer;
13+
1114
- (instancetype)initWithTileLayer:(GMSTileLayer *)tileLayer
1215
mapView:(GMSMapView *)mapView
1316
options:(NSDictionary *)optionsData;
1417
- (void)removeTileOverlay;
1518
- (void)clearTileCache;
16-
- (NSDictionary *)getTileOverlayInfo;
1719
@end
1820

1921
@interface FLTTileProviderController : GMSTileLayer
@@ -30,7 +32,7 @@ NS_ASSUME_NONNULL_BEGIN
3032
- (void)changeTileOverlays:(NSArray *)tileOverlaysToChange;
3133
- (void)removeTileOverlayWithIdentifiers:(NSArray *)identifiers;
3234
- (void)clearTileCacheWithIdentifier:(NSString *)identifier;
33-
- (nullable NSDictionary *)tileOverlayInfoWithIdentifier:(NSString *)identifier;
35+
- (nullable FLTGoogleMapTileOverlayController *)tileOverlayWithIdentifier:(NSString *)identifier;
3436
@end
3537

3638
NS_ASSUME_NONNULL_END

packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapTileOverlayController.m

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,6 @@ - (void)clearTileCache {
3434
[self.layer clearTileCache];
3535
}
3636

37-
- (NSDictionary *)getTileOverlayInfo {
38-
NSMutableDictionary *info = [[NSMutableDictionary alloc] init];
39-
BOOL visible = self.layer.map != nil;
40-
info[@"visible"] = @(visible);
41-
info[@"fadeIn"] = @(self.layer.fadeIn);
42-
float transparency = 1.0 - self.layer.opacity;
43-
info[@"transparency"] = @(transparency);
44-
info[@"zIndex"] = @(self.layer.zIndex);
45-
return info;
46-
}
47-
4837
- (void)setFadeIn:(BOOL)fadeIn {
4938
self.layer.fadeIn = fadeIn;
5039
}
@@ -182,7 +171,8 @@ - (void)requestTileForX:(NSUInteger)x
182171

183172
@interface FLTTileOverlaysController ()
184173

185-
@property(strong, nonatomic) NSMutableDictionary *tileOverlayIdentifierToController;
174+
@property(strong, nonatomic) NSMutableDictionary<NSString *, FLTGoogleMapTileOverlayController *>
175+
*tileOverlayIdentifierToController;
186176
@property(strong, nonatomic) FlutterMethodChannel *methodChannel;
187177
@property(weak, nonatomic) GMSMapView *mapView;
188178

@@ -248,11 +238,8 @@ - (void)clearTileCacheWithIdentifier:(NSString *)identifier {
248238
[controller clearTileCache];
249239
}
250240

251-
- (nullable NSDictionary *)tileOverlayInfoWithIdentifier:(NSString *)identifier {
252-
if (self.tileOverlayIdentifierToController[identifier] == nil) {
253-
return nil;
254-
}
255-
return [self.tileOverlayIdentifierToController[identifier] getTileOverlayInfo];
241+
- (nullable FLTGoogleMapTileOverlayController *)tileOverlayWithIdentifier:(NSString *)identifier {
242+
return self.tileOverlayIdentifierToController[identifier];
256243
}
257244

258245
+ (NSString *)identifierForTileOverlay:(NSDictionary *)tileOverlay {

packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#import "GoogleMapMarkerController.h"
99
#import "GoogleMapPolygonController.h"
1010
#import "GoogleMapPolylineController.h"
11+
#import "messages.g.h"
1112

1213
NS_ASSUME_NONNULL_BEGIN
1314

packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.m

Lines changed: 121 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#import "GoogleMapController.h"
66
#import "FLTGoogleMapJSONConversions.h"
77
#import "FLTGoogleMapTileOverlayController.h"
8+
#import "messages.g.h"
89

910
#pragma mark - Conversion of JSON-like values sent via platform channels. Forward declarations.
1011

@@ -56,6 +57,33 @@ - (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar
5657

5758
@end
5859

60+
#pragma mark -
61+
62+
/// Implementation of the Pigeon maps inspector API.
63+
///
64+
/// This is a separate object from the maps controller because the Pigeon API registration keeps a
65+
/// strong reference to the implementor, but as the FlutterPlatformView, the lifetime of the
66+
/// FLTGoogleMapController instance is what needs to trigger Pigeon unregistration, so can't be
67+
/// the target of the registration.
68+
@interface FGMMapInspector : NSObject <FGMMapsInspectorApi>
69+
- (instancetype)initWithMapController:(nonnull FLTGoogleMapController *)controller
70+
messenger:(NSObject<FlutterBinaryMessenger> *)messenger
71+
pigeonSuffix:(NSString *)suffix;
72+
@end
73+
74+
/// Private declarations.
75+
// This is separate in case the above is made public in the future (e.g., for unit testing).
76+
@interface FGMMapInspector ()
77+
/// The map controller this inspector corresponds to.
78+
@property(nonatomic, weak) FLTGoogleMapController *controller;
79+
/// The messenger this instance was registered with by Pigeon.
80+
@property(nonatomic, copy) NSObject<FlutterBinaryMessenger> *messenger;
81+
/// The suffix this instance was registered under with Pigeon.
82+
@property(nonatomic, copy) NSString *pigeonSuffix;
83+
@end
84+
85+
#pragma mark -
86+
5987
@interface FLTGoogleMapController ()
6088

6189
@property(nonatomic, strong) GMSMapView *mapView;
@@ -72,6 +100,8 @@ @interface FLTGoogleMapController ()
72100
// creation time and there's no mechanism to return non-fatal error details during platform view
73101
// initialization.
74102
@property(nonatomic, copy) NSString *styleError;
103+
// The inspector API implementation, separate to avoid lifetime extension.
104+
@property(nonatomic, strong) FGMMapInspector *inspector;
75105

76106
@end
77107

@@ -114,9 +144,7 @@ - (instancetype)initWithMapView:(GMSMapView *_Nonnull)mapView
114144
binaryMessenger:registrar.messenger];
115145
__weak __typeof__(self) weakSelf = self;
116146
[_channel setMethodCallHandler:^(FlutterMethodCall *call, FlutterResult result) {
117-
if (weakSelf) {
118-
[weakSelf onMethodCall:call result:result];
119-
}
147+
[weakSelf onMethodCall:call result:result];
120148
}];
121149
_mapView.delegate = weakSelf;
122150
_mapView.paddingAdjustmentBehavior = kGMSMapViewPaddingAdjustmentBehaviorNever;
@@ -158,10 +186,22 @@ - (instancetype)initWithMapView:(GMSMapView *_Nonnull)mapView
158186
}
159187

160188
[_mapView addObserver:self forKeyPath:@"frame" options:0 context:nil];
189+
190+
NSString *suffix = [NSString stringWithFormat:@"%lld", viewId];
191+
_inspector = [[FGMMapInspector alloc] initWithMapController:self
192+
messenger:registrar.messenger
193+
pigeonSuffix:suffix];
194+
SetUpFGMMapsInspectorApiWithSuffix(registrar.messenger, _inspector, suffix);
161195
}
162196
return self;
163197
}
164198

199+
- (void)dealloc {
200+
// Unregister the API implementations so that they can be released; the registration created an
201+
// owning reference.
202+
SetUpFGMMapsInspectorApiWithSuffix(_inspector.messenger, nil, _inspector.pigeonSuffix);
203+
}
204+
165205
- (UIView *)view {
166206
return self.mapView;
167207
}
@@ -356,41 +396,8 @@ - (void)onMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
356396
id rawTileOverlayId = call.arguments[@"tileOverlayId"];
357397
[self.tileOverlaysController clearTileCacheWithIdentifier:rawTileOverlayId];
358398
result(nil);
359-
} else if ([call.method isEqualToString:@"map#isCompassEnabled"]) {
360-
NSNumber *isCompassEnabled = @(self.mapView.settings.compassButton);
361-
result(isCompassEnabled);
362-
} else if ([call.method isEqualToString:@"map#isMapToolbarEnabled"]) {
363-
NSNumber *isMapToolbarEnabled = @NO;
364-
result(isMapToolbarEnabled);
365-
} else if ([call.method isEqualToString:@"map#getMinMaxZoomLevels"]) {
366-
NSArray *zoomLevels = @[ @(self.mapView.minZoom), @(self.mapView.maxZoom) ];
367-
result(zoomLevels);
368399
} else if ([call.method isEqualToString:@"map#getZoomLevel"]) {
369400
result(@(self.mapView.camera.zoom));
370-
} else if ([call.method isEqualToString:@"map#isZoomGesturesEnabled"]) {
371-
NSNumber *isZoomGesturesEnabled = @(self.mapView.settings.zoomGestures);
372-
result(isZoomGesturesEnabled);
373-
} else if ([call.method isEqualToString:@"map#isZoomControlsEnabled"]) {
374-
NSNumber *isZoomControlsEnabled = @NO;
375-
result(isZoomControlsEnabled);
376-
} else if ([call.method isEqualToString:@"map#isTiltGesturesEnabled"]) {
377-
NSNumber *isTiltGesturesEnabled = @(self.mapView.settings.tiltGestures);
378-
result(isTiltGesturesEnabled);
379-
} else if ([call.method isEqualToString:@"map#isRotateGesturesEnabled"]) {
380-
NSNumber *isRotateGesturesEnabled = @(self.mapView.settings.rotateGestures);
381-
result(isRotateGesturesEnabled);
382-
} else if ([call.method isEqualToString:@"map#isScrollGesturesEnabled"]) {
383-
NSNumber *isScrollGesturesEnabled = @(self.mapView.settings.scrollGestures);
384-
result(isScrollGesturesEnabled);
385-
} else if ([call.method isEqualToString:@"map#isMyLocationButtonEnabled"]) {
386-
NSNumber *isMyLocationButtonEnabled = @(self.mapView.settings.myLocationButton);
387-
result(isMyLocationButtonEnabled);
388-
} else if ([call.method isEqualToString:@"map#isTrafficEnabled"]) {
389-
NSNumber *isTrafficEnabled = @(self.mapView.trafficEnabled);
390-
result(isTrafficEnabled);
391-
} else if ([call.method isEqualToString:@"map#isBuildingsEnabled"]) {
392-
NSNumber *isBuildingsEnabled = @(self.mapView.buildingsEnabled);
393-
result(isBuildingsEnabled);
394401
} else if ([call.method isEqualToString:@"map#setStyle"]) {
395402
id mapStyle = [call arguments];
396403
self.styleError = [self setMapStyle:(mapStyle == [NSNull null] ? nil : mapStyle)];
@@ -401,9 +408,6 @@ - (void)onMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
401408
}
402409
} else if ([call.method isEqualToString:@"map#getStyleError"]) {
403410
result(self.styleError);
404-
} else if ([call.method isEqualToString:@"map#getTileOverlayInfo"]) {
405-
NSString *rawTileOverlayId = call.arguments[@"tileOverlayId"];
406-
result([self.tileOverlaysController tileOverlayInfoWithIdentifier:rawTileOverlayId]);
407411
} else {
408412
result(FlutterMethodNotImplemented);
409413
}
@@ -659,3 +663,81 @@ - (void)interpretMapOptions:(NSDictionary *)data {
659663
}
660664

661665
@end
666+
667+
#pragma mark -
668+
669+
@implementation FGMMapInspector
670+
671+
- (instancetype)initWithMapController:(nonnull FLTGoogleMapController *)controller
672+
messenger:(NSObject<FlutterBinaryMessenger> *)messenger
673+
pigeonSuffix:(NSString *)suffix {
674+
self = [super init];
675+
if (self) {
676+
_controller = controller;
677+
_messenger = messenger;
678+
_pigeonSuffix = suffix;
679+
}
680+
return self;
681+
}
682+
683+
- (nullable NSNumber *)areBuildingsEnabledWithError:
684+
(FlutterError *_Nullable __autoreleasing *_Nonnull)error {
685+
return @(self.controller.mapView.buildingsEnabled);
686+
}
687+
688+
- (nullable NSNumber *)areRotateGesturesEnabledWithError:
689+
(FlutterError *_Nullable __autoreleasing *_Nonnull)error {
690+
return @(self.controller.mapView.settings.rotateGestures);
691+
}
692+
693+
- (nullable NSNumber *)areScrollGesturesEnabledWithError:
694+
(FlutterError *_Nullable __autoreleasing *_Nonnull)error {
695+
return @(self.controller.mapView.settings.scrollGestures);
696+
}
697+
698+
- (nullable NSNumber *)areTiltGesturesEnabledWithError:
699+
(FlutterError *_Nullable __autoreleasing *_Nonnull)error {
700+
return @(self.controller.mapView.settings.tiltGestures);
701+
}
702+
703+
- (nullable NSNumber *)areZoomGesturesEnabledWithError:
704+
(FlutterError *_Nullable __autoreleasing *_Nonnull)error {
705+
return @(self.controller.mapView.settings.zoomGestures);
706+
}
707+
708+
- (nullable FGMPlatformTileLayer *)
709+
getInfoForTileOverlayWithIdentifier:(nonnull NSString *)tileOverlayId
710+
error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error {
711+
GMSTileLayer *layer =
712+
[self.controller.tileOverlaysController tileOverlayWithIdentifier:tileOverlayId].layer;
713+
if (!layer) {
714+
return nil;
715+
}
716+
return [FGMPlatformTileLayer makeWithVisible:(layer.map != nil)
717+
fadeIn:layer.fadeIn
718+
opacity:layer.opacity
719+
zIndex:layer.zIndex];
720+
}
721+
722+
- (nullable NSNumber *)isCompassEnabledWithError:
723+
(FlutterError *_Nullable __autoreleasing *_Nonnull)error {
724+
return @(self.controller.mapView.settings.compassButton);
725+
}
726+
727+
- (nullable NSNumber *)isMyLocationButtonEnabledWithError:
728+
(FlutterError *_Nullable __autoreleasing *_Nonnull)error {
729+
return @(self.controller.mapView.settings.myLocationButton);
730+
}
731+
732+
- (nullable NSNumber *)isTrafficEnabledWithError:
733+
(FlutterError *_Nullable __autoreleasing *_Nonnull)error {
734+
return @(self.controller.mapView.trafficEnabled);
735+
}
736+
737+
- (nullable FGMPlatformZoomRange *)zoomRange:
738+
(FlutterError *_Nullable __autoreleasing *_Nonnull)error {
739+
return [FGMPlatformZoomRange makeWithMin:self.controller.mapView.minZoom
740+
max:self.controller.mapView.maxZoom];
741+
}
742+
743+
@end
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
// Autogenerated from Pigeon (v20.0.1), do not edit directly.
5+
// See also: https://pub.dev/packages/pigeon
6+
7+
#import <Foundation/Foundation.h>
8+
9+
@protocol FlutterBinaryMessenger;
10+
@protocol FlutterMessageCodec;
11+
@class FlutterError;
12+
@class FlutterStandardTypedData;
13+
14+
NS_ASSUME_NONNULL_BEGIN
15+
16+
@class FGMPlatformTileLayer;
17+
@class FGMPlatformZoomRange;
18+
19+
/// Pigeon equivalent of GMSTileLayer properties.
20+
@interface FGMPlatformTileLayer : NSObject
21+
/// `init` unavailable to enforce nonnull fields, see the `make` class method.
22+
- (instancetype)init NS_UNAVAILABLE;
23+
+ (instancetype)makeWithVisible:(BOOL)visible
24+
fadeIn:(BOOL)fadeIn
25+
opacity:(double)opacity
26+
zIndex:(NSInteger)zIndex;
27+
@property(nonatomic, assign) BOOL visible;
28+
@property(nonatomic, assign) BOOL fadeIn;
29+
@property(nonatomic, assign) double opacity;
30+
@property(nonatomic, assign) NSInteger zIndex;
31+
@end
32+
33+
/// Possible outcomes of launching a URL.
34+
@interface FGMPlatformZoomRange : NSObject
35+
/// `init` unavailable to enforce nonnull fields, see the `make` class method.
36+
- (instancetype)init NS_UNAVAILABLE;
37+
+ (instancetype)makeWithMin:(double)min max:(double)max;
38+
@property(nonatomic, assign) double min;
39+
@property(nonatomic, assign) double max;
40+
@end
41+
42+
/// The codec used by all APIs.
43+
NSObject<FlutterMessageCodec> *FGMGetMessagesCodec(void);
44+
45+
/// Inspector API only intended for use in integration tests.
46+
@protocol FGMMapsInspectorApi
47+
/// @return `nil` only when `error != nil`.
48+
- (nullable NSNumber *)areBuildingsEnabledWithError:(FlutterError *_Nullable *_Nonnull)error;
49+
/// @return `nil` only when `error != nil`.
50+
- (nullable NSNumber *)areRotateGesturesEnabledWithError:(FlutterError *_Nullable *_Nonnull)error;
51+
/// @return `nil` only when `error != nil`.
52+
- (nullable NSNumber *)areScrollGesturesEnabledWithError:(FlutterError *_Nullable *_Nonnull)error;
53+
/// @return `nil` only when `error != nil`.
54+
- (nullable NSNumber *)areTiltGesturesEnabledWithError:(FlutterError *_Nullable *_Nonnull)error;
55+
/// @return `nil` only when `error != nil`.
56+
- (nullable NSNumber *)areZoomGesturesEnabledWithError:(FlutterError *_Nullable *_Nonnull)error;
57+
/// @return `nil` only when `error != nil`.
58+
- (nullable NSNumber *)isCompassEnabledWithError:(FlutterError *_Nullable *_Nonnull)error;
59+
/// @return `nil` only when `error != nil`.
60+
- (nullable NSNumber *)isMyLocationButtonEnabledWithError:(FlutterError *_Nullable *_Nonnull)error;
61+
/// @return `nil` only when `error != nil`.
62+
- (nullable NSNumber *)isTrafficEnabledWithError:(FlutterError *_Nullable *_Nonnull)error;
63+
- (nullable FGMPlatformTileLayer *)
64+
getInfoForTileOverlayWithIdentifier:(NSString *)tileOverlayId
65+
error:(FlutterError *_Nullable *_Nonnull)error;
66+
/// @return `nil` only when `error != nil`.
67+
- (nullable FGMPlatformZoomRange *)zoomRange:(FlutterError *_Nullable *_Nonnull)error;
68+
@end
69+
70+
extern void SetUpFGMMapsInspectorApi(id<FlutterBinaryMessenger> binaryMessenger,
71+
NSObject<FGMMapsInspectorApi> *_Nullable api);
72+
73+
extern void SetUpFGMMapsInspectorApiWithSuffix(id<FlutterBinaryMessenger> binaryMessenger,
74+
NSObject<FGMMapsInspectorApi> *_Nullable api,
75+
NSString *messageChannelSuffix);
76+
77+
NS_ASSUME_NONNULL_END

0 commit comments

Comments
 (0)