Skip to content

Commit

Permalink
[google_maps_flutter] Semi-convert remaining iOS host API calls to Pi…
Browse files Browse the repository at this point in the history
…geon (#7079)

Does a "shallow" Pigeon conversion of the remaining host API calls in the iOS implementation. All of the actual method calls are now Pigeon, but for the most part the data structures are not yet converted, and the Pigeon representations of the map objects are instead placeholders that currently just wrap the existing JSON serialization. This is done for a few reasons:
- Keeps the incremental PR relatively small and easy to understand.
- Quickly gets us to a state where any new APIs added will automatically use Pigeon, reducing further accumulation of technical debt.
- Avoids duplication of handling code until flutter/flutter#150631 is resolved. As noted in a TODO added in this PR, almost all of the data structures that are passed in these methods are also passed through the PlatformView factory constructor, and Pigeon doesn't yet support using the Pigeon codec in non-Pigeon-generated code, so we would need to have both the structured *and* JSON handler for all of these objects if we converted them now.

Future PRs will be able to incrementally convert each map object to a structured form. Converting the Flutter APIs (Java->Dart) will also be done in a follow-up, to limit the scope of this PR.

This is the iOS equivalent of #6980, and the Dart code is largely the same.

Part of flutter/flutter#117907
  • Loading branch information
stuartmorgan committed Jul 9, 2024
1 parent 47a92db commit edb38e0
Show file tree
Hide file tree
Showing 24 changed files with 3,610 additions and 515 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.9.0

* Converts additional platform calls to Pigeon.

## 2.8.2

* Converts inspector interface platform calls to Pigeon.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,25 +113,26 @@ - (void)testDictionaryFromPosition {
XCTAssertEqualObjects(dictionary[@"tilt"], @75.0);
}

- (void)testDictionaryFromPoint {
- (void)testPigeonPointForGCPoint {
CGPoint point = CGPointMake(10, 20);
NSDictionary *dictionary = [FLTGoogleMapJSONConversions dictionaryFromPoint:point];
const CGFloat accuracy = 0.0001;
XCTAssertEqualWithAccuracy([dictionary[@"x"] floatValue], point.x, accuracy);
XCTAssertEqualWithAccuracy([dictionary[@"y"] floatValue], point.y, accuracy);
FGMPlatformPoint *pigeonPoint = FGMGetPigeonPointForCGPoint(point);
XCTAssertEqualWithAccuracy(pigeonPoint.x, point.x, DBL_EPSILON);
XCTAssertEqualWithAccuracy(pigeonPoint.y, point.y, DBL_EPSILON);
}

- (void)testDictionaryFromCoordinateBounds {
XCTAssertNil([FLTGoogleMapJSONConversions dictionaryFromCoordinateBounds:nil]);

- (void)testPigeonLatLngBoundsForCoordinateBounds {
GMSCoordinateBounds *bounds =
[[GMSCoordinateBounds alloc] initWithCoordinate:CLLocationCoordinate2DMake(10, 20)
coordinate:CLLocationCoordinate2DMake(30, 40)];
NSDictionary *dictionary = [FLTGoogleMapJSONConversions dictionaryFromCoordinateBounds:bounds];
NSArray *southwest = @[ @10, @20 ];
NSArray *northeast = @[ @30, @40 ];
XCTAssertEqualObjects(dictionary[@"southwest"], southwest);
XCTAssertEqualObjects(dictionary[@"northeast"], northeast);
FGMPlatformLatLngBounds *pigeonBounds = FGMGetPigeonLatLngBoundsForCoordinateBounds(bounds);
XCTAssertEqualWithAccuracy(pigeonBounds.southwest.latitude, bounds.southWest.latitude,
DBL_EPSILON);
XCTAssertEqualWithAccuracy(pigeonBounds.southwest.longitude, bounds.southWest.longitude,
DBL_EPSILON);
XCTAssertEqualWithAccuracy(pigeonBounds.northeast.latitude, bounds.northEast.latitude,
DBL_EPSILON);
XCTAssertEqualWithAccuracy(pigeonBounds.northeast.longitude, bounds.northEast.longitude,
DBL_EPSILON);
}

- (void)testCameraPostionFromDictionary {
Expand All @@ -151,19 +152,13 @@ - (void)testCameraPostionFromDictionary {
XCTAssertEqualWithAccuracy(cameraPosition.viewingAngle, 5, accuracy);
}

- (void)testPointFromDictionary {
XCTAssertNil([FLTGoogleMapJSONConversions cameraPostionFromDictionary:nil]);
- (void)testCGPointForPigeonPoint {
FGMPlatformPoint *pigeonPoint = [FGMPlatformPoint makeWithX:1.0 y:2.0];

NSDictionary *dictionary = @{
@"x" : @1,
@"y" : @2,
};
CGPoint point = FGMGetCGPointForPigeonPoint(pigeonPoint);

CGPoint point = [FLTGoogleMapJSONConversions pointFromDictionary:dictionary];

const CGFloat accuracy = 0.001;
XCTAssertEqualWithAccuracy(point.x, 1, accuracy);
XCTAssertEqualWithAccuracy(point.y, 2, accuracy);
XCTAssertEqualWithAccuracy(pigeonPoint.x, point.x, DBL_EPSILON);
XCTAssertEqualWithAccuracy(pigeonPoint.y, point.y, DBL_EPSILON);
}

- (void)testCoordinateBoundsFromLatLongs {
Expand All @@ -188,18 +183,18 @@ - (void)testMapViewTypeFromTypeValue {
XCTAssertEqual(kGMSTypeNone, [FLTGoogleMapJSONConversions mapViewTypeFromTypeValue:@5]);
}

- (void)testCameraUpdateFromChannelValueNewCameraPosition {
- (void)testCameraUpdateFromArrayNewCameraPosition {
NSArray *channelValue = @[
@"newCameraPosition", @{@"target" : @[ @1, @2 ], @"zoom" : @3, @"bearing" : @4, @"tilt" : @5}
];
id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]);
[FLTGoogleMapJSONConversions cameraUpdateFromChannelValue:channelValue];
[FLTGoogleMapJSONConversions cameraUpdateFromArray:channelValue];
[[classMockCameraUpdate expect]
setCamera:[FLTGoogleMapJSONConversions cameraPostionFromDictionary:channelValue[1]]];
[classMockCameraUpdate stopMocking];
}

// TODO(cyanglaz): Fix the test for CameraUpdateFromChannelValue with the "NewLatlng" key.
// TODO(cyanglaz): Fix the test for cameraUpdateFromArray with the "NewLatlng" key.
// 2 approaches have been tried and neither worked for the tests.
//
// 1. Use OCMock to vefiry that [GMSCameraUpdate setTarget:] is triggered with the correct value.
Expand All @@ -213,10 +208,10 @@ - (void)testCameraUpdateFromChannelValueNewCameraPosition {
// verified.
//
// The code in below test uses the 2nd approach.
- (void)skip_testCameraUpdateFromChannelValueNewLatLong {
- (void)skip_testCameraUpdateFromArrayNewLatLong {
NSArray *channelValue = @[ @"newLatLng", @[ @1, @2 ] ];

GMSCameraUpdate *update = [FLTGoogleMapJSONConversions cameraUpdateFromChannelValue:channelValue];
GMSCameraUpdate *update = [FLTGoogleMapJSONConversions cameraUpdateFromArray:channelValue];

GMSMapViewOptions *options = [[GMSMapViewOptions alloc] init];
options.frame = CGRectZero;
Expand All @@ -230,81 +225,81 @@ - (void)skip_testCameraUpdateFromChannelValueNewLatLong {
accuracy); // mapView.camera.target.longitude is still 6.
}

- (void)testCameraUpdateFromChannelValueNewLatLngBounds {
- (void)testCameraUpdateFromArrayNewLatLngBounds {
NSArray<NSNumber *> *latlong1 = @[ @1, @2 ];
NSArray<NSNumber *> *latlong2 = @[ @(3), @(4) ];
GMSCoordinateBounds *bounds =
[FLTGoogleMapJSONConversions coordinateBoundsFromLatLongs:@[ latlong1, latlong2 ]];

NSArray *channelValue = @[ @"newLatLngBounds", @[ latlong1, latlong2 ], @20 ];
id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]);
[FLTGoogleMapJSONConversions cameraUpdateFromChannelValue:channelValue];
[FLTGoogleMapJSONConversions cameraUpdateFromArray:channelValue];

[[classMockCameraUpdate expect] fitBounds:bounds withPadding:20];
[classMockCameraUpdate stopMocking];
}

- (void)testCameraUpdateFromChannelValueNewLatLngZoom {
- (void)testCameraUpdateFromArrayNewLatLngZoom {
NSArray *channelValue = @[ @"newLatLngZoom", @[ @1, @2 ], @3 ];

id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]);
[FLTGoogleMapJSONConversions cameraUpdateFromChannelValue:channelValue];
[FLTGoogleMapJSONConversions cameraUpdateFromArray:channelValue];

[[classMockCameraUpdate expect] setTarget:CLLocationCoordinate2DMake(1, 2) zoom:3];
[classMockCameraUpdate stopMocking];
}

- (void)testCameraUpdateFromChannelValueScrollBy {
- (void)testCameraUpdateFromArrayScrollBy {
NSArray *channelValue = @[ @"scrollBy", @1, @2 ];

id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]);
[FLTGoogleMapJSONConversions cameraUpdateFromChannelValue:channelValue];
[FLTGoogleMapJSONConversions cameraUpdateFromArray:channelValue];

[[classMockCameraUpdate expect] scrollByX:1 Y:2];
[classMockCameraUpdate stopMocking];
}

- (void)testCameraUpdateFromChannelValueZoomBy {
- (void)testCameraUpdateFromArrayZoomBy {
NSArray *channelValueNoPoint = @[ @"zoomBy", @1 ];

id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]);
[FLTGoogleMapJSONConversions cameraUpdateFromChannelValue:channelValueNoPoint];
[FLTGoogleMapJSONConversions cameraUpdateFromArray:channelValueNoPoint];

[[classMockCameraUpdate expect] zoomBy:1];

NSArray *channelValueWithPoint = @[ @"zoomBy", @1, @[ @2, @3 ] ];

[FLTGoogleMapJSONConversions cameraUpdateFromChannelValue:channelValueWithPoint];
[FLTGoogleMapJSONConversions cameraUpdateFromArray:channelValueWithPoint];

[[classMockCameraUpdate expect] zoomBy:1 atPoint:CGPointMake(2, 3)];
[classMockCameraUpdate stopMocking];
}

- (void)testCameraUpdateFromChannelValueZoomIn {
- (void)testCameraUpdateFromArrayZoomIn {
NSArray *channelValueNoPoint = @[ @"zoomIn" ];

id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]);
[FLTGoogleMapJSONConversions cameraUpdateFromChannelValue:channelValueNoPoint];
[FLTGoogleMapJSONConversions cameraUpdateFromArray:channelValueNoPoint];

[[classMockCameraUpdate expect] zoomIn];
[classMockCameraUpdate stopMocking];
}

- (void)testCameraUpdateFromChannelValueZoomOut {
- (void)testCameraUpdateFromArrayZoomOut {
NSArray *channelValueNoPoint = @[ @"zoomOut" ];

id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]);
[FLTGoogleMapJSONConversions cameraUpdateFromChannelValue:channelValueNoPoint];
[FLTGoogleMapJSONConversions cameraUpdateFromArray:channelValueNoPoint];

[[classMockCameraUpdate expect] zoomOut];
[classMockCameraUpdate stopMocking];
}

- (void)testCameraUpdateFromChannelValueZoomTo {
- (void)testCameraUpdateFromArrayZoomTo {
NSArray *channelValueNoPoint = @[ @"zoomTo", @1 ];

id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]);
[FLTGoogleMapJSONConversions cameraUpdateFromChannelValue:channelValueNoPoint];
[FLTGoogleMapJSONConversions cameraUpdateFromArray:channelValueNoPoint];

[[classMockCameraUpdate expect] zoomTo:1];
[classMockCameraUpdate stopMocking];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,29 @@
#import <Flutter/Flutter.h>
#import <GoogleMaps/GoogleMaps.h>

#import "messages.g.h"

NS_ASSUME_NONNULL_BEGIN

/// Returns dict[key], or nil if dict[key] is NSNull.
extern id _Nullable FGMGetValueOrNilFromDict(NSDictionary *dict, NSString *key);

/// Creates a CGPoint from its Pigeon equivalent.
extern CGPoint FGMGetCGPointForPigeonPoint(FGMPlatformPoint *point);

/// Converts a CGPoint to its Pigeon equivalent.
extern FGMPlatformPoint *FGMGetPigeonPointForCGPoint(CGPoint point);

/// Creates a CLLocationCoordinate2D from its Pigeon representation.
extern CLLocationCoordinate2D FGMGetCoordinateForPigeonLatLng(FGMPlatformLatLng *latLng);

/// Converts a CLLocationCoordinate2D to its Pigeon representation.
extern FGMPlatformLatLng *FGMGetPigeonLatLngForCoordinate(CLLocationCoordinate2D coord);

/// Converts a GMSCoordinateBounds to its Pigeon representation.
extern FGMPlatformLatLngBounds *FGMGetPigeonLatLngBoundsForCoordinateBounds(
GMSCoordinateBounds *bounds);

@interface FLTGoogleMapJSONConversions : NSObject

+ (CLLocationCoordinate2D)locationFromLatLong:(NSArray *)latlong;
Expand All @@ -20,13 +38,10 @@ extern id _Nullable FGMGetValueOrNilFromDict(NSDictionary *dict, NSString *key);
+ (NSArray<NSArray<CLLocation *> *> *)holesFromPointsArray:(NSArray *)data;
+ (nullable NSDictionary<NSString *, id> *)dictionaryFromPosition:
(nullable GMSCameraPosition *)position;
+ (NSDictionary<NSString *, NSNumber *> *)dictionaryFromPoint:(CGPoint)point;
+ (nullable NSDictionary *)dictionaryFromCoordinateBounds:(nullable GMSCoordinateBounds *)bounds;
+ (nullable GMSCameraPosition *)cameraPostionFromDictionary:(nullable NSDictionary *)channelValue;
+ (CGPoint)pointFromDictionary:(NSDictionary *)dictionary;
+ (GMSCoordinateBounds *)coordinateBoundsFromLatLongs:(NSArray *)latlongs;
+ (GMSMapViewType)mapViewTypeFromTypeValue:(NSNumber *)value;
+ (nullable GMSCameraUpdate *)cameraUpdateFromChannelValue:(NSArray *)channelValue;
+ (nullable GMSCameraUpdate *)cameraUpdateFromArray:(NSArray *)channelValue;

/// Return GMS strokestyle object array populated using the patterns and stroke colors passed in.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,28 @@ id FGMGetValueOrNilFromDict(NSDictionary *dict, NSString *key) {
return value == [NSNull null] ? nil : value;
}

CGPoint FGMGetCGPointForPigeonPoint(FGMPlatformPoint *point) {
return CGPointMake(point.x, point.y);
}

FGMPlatformPoint *FGMGetPigeonPointForCGPoint(CGPoint point) {
return [FGMPlatformPoint makeWithX:point.x y:point.y];
}

CLLocationCoordinate2D FGMGetCoordinateForPigeonLatLng(FGMPlatformLatLng *latLng) {
return CLLocationCoordinate2DMake(latLng.latitude, latLng.longitude);
}

FGMPlatformLatLng *FGMGetPigeonLatLngForCoordinate(CLLocationCoordinate2D coord) {
return [FGMPlatformLatLng makeWithLatitude:coord.latitude longitude:coord.longitude];
}

FGMPlatformLatLngBounds *FGMGetPigeonLatLngBoundsForCoordinateBounds(GMSCoordinateBounds *bounds) {
return
[FGMPlatformLatLngBounds makeWithNortheast:FGMGetPigeonLatLngForCoordinate(bounds.northEast)
southwest:FGMGetPigeonLatLngForCoordinate(bounds.southWest)];
}

@implementation FLTGoogleMapJSONConversions

+ (CLLocationCoordinate2D)locationFromLatLong:(NSArray *)latlong {
Expand Down Expand Up @@ -67,23 +89,6 @@ + (UIColor *)colorFromRGBA:(NSNumber *)numberColor {
};
}

+ (NSDictionary<NSString *, NSNumber *> *)dictionaryFromPoint:(CGPoint)point {
return @{
@"x" : @(lroundf(point.x)),
@"y" : @(lroundf(point.y)),
};
}

+ (nullable NSDictionary *)dictionaryFromCoordinateBounds:(GMSCoordinateBounds *)bounds {
if (!bounds) {
return nil;
}
return @{
@"southwest" : [FLTGoogleMapJSONConversions arrayFromLocation:[bounds southWest]],
@"northeast" : [FLTGoogleMapJSONConversions arrayFromLocation:[bounds northEast]],
};
}

+ (nullable GMSCameraPosition *)cameraPostionFromDictionary:(nullable NSDictionary *)data {
if (!data) {
return nil;
Expand All @@ -95,12 +100,6 @@ + (nullable GMSCameraPosition *)cameraPostionFromDictionary:(nullable NSDictiona
viewingAngle:[data[@"tilt"] doubleValue]];
}

+ (CGPoint)pointFromDictionary:(NSDictionary *)dictionary {
double x = [dictionary[@"x"] doubleValue];
double y = [dictionary[@"y"] doubleValue];
return CGPointMake(x, y);
}

+ (GMSCoordinateBounds *)coordinateBoundsFromLatLongs:(NSArray *)latlongs {
return [[GMSCoordinateBounds alloc]
initWithCoordinate:[FLTGoogleMapJSONConversions locationFromLatLong:latlongs[0]]
Expand All @@ -112,7 +111,7 @@ + (GMSMapViewType)mapViewTypeFromTypeValue:(NSNumber *)typeValue {
return (GMSMapViewType)(value == 0 ? 5 : value);
}

+ (nullable GMSCameraUpdate *)cameraUpdateFromChannelValue:(NSArray *)channelValue {
+ (nullable GMSCameraUpdate *)cameraUpdateFromArray:(NSArray *)channelValue {
NSString *update = channelValue[0];
if ([update isEqualToString:@"newCameraPosition"]) {
return [GMSCameraUpdate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#import <Flutter/Flutter.h>
#import <GoogleMaps/GoogleMaps.h>

#import "messages.g.h"

NS_ASSUME_NONNULL_BEGIN

@interface FLTGoogleMapTileOverlayController : NSObject
Expand All @@ -28,9 +30,10 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)init:(FlutterMethodChannel *)methodChannel
mapView:(GMSMapView *)mapView
registrar:(NSObject<FlutterPluginRegistrar> *)registrar;
- (void)addTileOverlays:(NSArray *)tileOverlaysToAdd;
- (void)changeTileOverlays:(NSArray *)tileOverlaysToChange;
- (void)removeTileOverlayWithIdentifiers:(NSArray *)identifiers;
- (void)addJSONTileOverlays:(NSArray<NSDictionary<NSString *, id> *> *)tileOverlaysToAdd;
- (void)addTileOverlays:(NSArray<FGMPlatformTileOverlay *> *)tileOverlaysToAdd;
- (void)changeTileOverlays:(NSArray<FGMPlatformTileOverlay *> *)tileOverlaysToChange;
- (void)removeTileOverlayWithIdentifiers:(NSArray<NSString *> *)identifiers;
- (void)clearTileCacheWithIdentifier:(NSString *)identifier;
- (nullable FLTGoogleMapTileOverlayController *)tileOverlayWithIdentifier:(NSString *)identifier;
@end
Expand Down
Loading

0 comments on commit edb38e0

Please sign in to comment.