Skip to content
This repository has been archived by the owner on Feb 22, 2023. It is now read-only.

Commit

Permalink
[google_maps_flutter] Objective-C code clean up (#5780)
Browse files Browse the repository at this point in the history
  • Loading branch information
Chris Yang authored Jun 1, 2022
1 parent 4cf7437 commit 801c1f6
Show file tree
Hide file tree
Showing 23 changed files with 1,190 additions and 981 deletions.
4 changes: 4 additions & 0 deletions packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.1.7

* Objective-C code cleanup.

## 2.1.6

* Fixes issue in Flutter v3.0.0 where some updates to the map don't take effect on Android.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
4510D964F3B1259FEDD3ABA6 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7755F8F4BABC3D6A0BD4048B /* libPods-Runner.a */; };
6851F3562835BC180032B7C8 /* FLTGoogleMapJSONConversionsConversionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6851F3552835BC180032B7C8 /* FLTGoogleMapJSONConversionsConversionTests.m */; };
68E4726A2836FF0C00BDDDAC /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 68E472692836FF0C00BDDDAC /* MapKit.framework */; };
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
Expand Down Expand Up @@ -55,6 +57,8 @@
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
6851F3552835BC180032B7C8 /* FLTGoogleMapJSONConversionsConversionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLTGoogleMapJSONConversionsConversionTests.m; sourceTree = "<group>"; };
68E472692836FF0C00BDDDAC /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.0.sdk/System/iOSSupport/System/Library/Frameworks/MapKit.framework; sourceTree = DEVELOPER_DIR; };
733AFAB37683A9DA7512F09C /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
7755F8F4BABC3D6A0BD4048B /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
Expand Down Expand Up @@ -95,6 +99,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
68E4726A2836FF0C00BDDDAC /* MapKit.framework in Frameworks */,
FC8F35FC8CD533B128950487 /* libPods-RunnerTests.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -112,6 +117,7 @@
1E7CF0857EFC88FC263CF3B2 /* Frameworks */ = {
isa = PBXGroup;
children = (
68E472692836FF0C00BDDDAC /* MapKit.framework */,
7755F8F4BABC3D6A0BD4048B /* libPods-Runner.a */,
F267F68029D1A4E2E4C572A7 /* libPods-RunnerTests.a */,
);
Expand Down Expand Up @@ -190,6 +196,7 @@
F7151F11265D7ED70028CB91 /* RunnerTests */ = {
isa = PBXGroup;
children = (
6851F3552835BC180032B7C8 /* FLTGoogleMapJSONConversionsConversionTests.m */,
F7151F12265D7ED70028CB91 /* GoogleMapsTests.m */,
982F2A6A27BADE17003C81F4 /* PartiallyMockedMapView.h */,
982F2A6B27BADE17003C81F4 /* PartiallyMockedMapView.m */,
Expand Down Expand Up @@ -446,6 +453,7 @@
buildActionMask = 2147483647;
files = (
F7151F13265D7ED70028CB91 /* GoogleMapsTests.m in Sources */,
6851F3562835BC180032B7C8 /* FLTGoogleMapJSONConversionsConversionTests.m in Sources */,
982F2A6C27BADE17003C81F4 /* PartiallyMockedMapView.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,290 @@
// 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 google_maps_flutter;
@import google_maps_flutter.Test;
@import XCTest;
@import MapKit;
@import GoogleMaps;

#import <OCMock/OCMock.h>
#import "PartiallyMockedMapView.h"

@interface FLTGoogleMapJSONConversionsTests : XCTestCase
@end

@implementation FLTGoogleMapJSONConversionsTests

- (void)testLocationFromLatLong {
NSArray<NSNumber *> *latlong = @[ @1, @2 ];
CLLocationCoordinate2D location = [FLTGoogleMapJSONConversions locationFromLatLong:latlong];
XCTAssertEqual(location.latitude, 1);
XCTAssertEqual(location.longitude, 2);
}

- (void)testPointFromArray {
NSArray<NSNumber *> *array = @[ @1, @2 ];
CGPoint point = [FLTGoogleMapJSONConversions pointFromArray:array];
XCTAssertEqual(point.x, 1);
XCTAssertEqual(point.y, 2);
}

- (void)testArrayFromLocation {
CLLocationCoordinate2D location = CLLocationCoordinate2DMake(1, 2);
NSArray<NSNumber *> *array = [FLTGoogleMapJSONConversions arrayFromLocation:location];
XCTAssertEqual([array[0] integerValue], 1);
XCTAssertEqual([array[1] integerValue], 2);
}

- (void)testColorFromRGBA {
NSNumber *rgba = @(0x01020304);
UIColor *color = [FLTGoogleMapJSONConversions colorFromRGBA:rgba];
CGFloat red, green, blue, alpha;
BOOL success = [color getRed:&red green:&green blue:&blue alpha:&alpha];
XCTAssertTrue(success);
const CGFloat accuracy = 0.0001;
XCTAssertEqualWithAccuracy(red, 2 / 255.0, accuracy);
XCTAssertEqualWithAccuracy(green, 3 / 255.0, accuracy);
XCTAssertEqualWithAccuracy(blue, 4 / 255.0, accuracy);
XCTAssertEqualWithAccuracy(alpha, 1 / 255.0, accuracy);
}

- (void)testPointsFromLatLongs {
NSArray<NSArray *> *latlongs = @[ @[ @1, @2 ], @[ @(3), @(4) ] ];
NSArray<CLLocation *> *locations = [FLTGoogleMapJSONConversions pointsFromLatLongs:latlongs];
XCTAssertEqual(locations.count, 2);
XCTAssertEqual(locations[0].coordinate.latitude, 1);
XCTAssertEqual(locations[0].coordinate.longitude, 2);
XCTAssertEqual(locations[1].coordinate.latitude, 3);
XCTAssertEqual(locations[1].coordinate.longitude, 4);
}

- (void)testHolesFromPointsArray {
NSArray<NSArray *> *pointsArray =
@[ @[ @[ @1, @2 ], @[ @(3), @(4) ] ], @[ @[ @(5), @(6) ], @[ @(7), @(8) ] ] ];
NSArray<NSArray<CLLocation *> *> *holes =
[FLTGoogleMapJSONConversions holesFromPointsArray:pointsArray];
XCTAssertEqual(holes.count, 2);
XCTAssertEqual(holes[0][0].coordinate.latitude, 1);
XCTAssertEqual(holes[0][0].coordinate.longitude, 2);
XCTAssertEqual(holes[0][1].coordinate.latitude, 3);
XCTAssertEqual(holes[0][1].coordinate.longitude, 4);
XCTAssertEqual(holes[1][0].coordinate.latitude, 5);
XCTAssertEqual(holes[1][0].coordinate.longitude, 6);
XCTAssertEqual(holes[1][1].coordinate.latitude, 7);
XCTAssertEqual(holes[1][1].coordinate.longitude, 8);
}

- (void)testDictionaryFromPosition {
id mockPosition = OCMClassMock([GMSCameraPosition class]);
NSValue *locationValue = [NSValue valueWithMKCoordinate:CLLocationCoordinate2DMake(1, 2)];
[(GMSCameraPosition *)[[mockPosition stub] andReturnValue:locationValue] target];
[[[mockPosition stub] andReturnValue:@(2.0)] zoom];
[[[mockPosition stub] andReturnValue:@(3.0)] bearing];
[[[mockPosition stub] andReturnValue:@(75.0)] viewingAngle];
NSDictionary *dictionary = [FLTGoogleMapJSONConversions dictionaryFromPosition:mockPosition];
NSArray *targetArray = @[ @1, @2 ];
XCTAssertEqualObjects(dictionary[@"target"], targetArray);
XCTAssertEqualObjects(dictionary[@"zoom"], @2.0);
XCTAssertEqualObjects(dictionary[@"bearing"], @3.0);
XCTAssertEqualObjects(dictionary[@"tilt"], @75.0);
}

- (void)testDictionaryFromPoint {
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);
}

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

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);
}

- (void)testCameraPostionFromDictionary {
XCTAssertNil([FLTGoogleMapJSONConversions cameraPostionFromDictionary:nil]);

NSDictionary *channelValue =
@{@"target" : @[ @1, @2 ], @"zoom" : @3, @"bearing" : @4, @"tilt" : @5};

GMSCameraPosition *cameraPosition =
[FLTGoogleMapJSONConversions cameraPostionFromDictionary:channelValue];

const CGFloat accuracy = 0.001;
XCTAssertEqualWithAccuracy(cameraPosition.target.latitude, 1, accuracy);
XCTAssertEqualWithAccuracy(cameraPosition.target.longitude, 2, accuracy);
XCTAssertEqualWithAccuracy(cameraPosition.zoom, 3, accuracy);
XCTAssertEqualWithAccuracy(cameraPosition.bearing, 4, accuracy);
XCTAssertEqualWithAccuracy(cameraPosition.viewingAngle, 5, accuracy);
}

- (void)testPointFromDictionary {
XCTAssertNil([FLTGoogleMapJSONConversions cameraPostionFromDictionary:nil]);

NSDictionary *dictionary = @{
@"x" : @1,
@"y" : @2,
};

CGPoint point = [FLTGoogleMapJSONConversions pointFromDictionary:dictionary];

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

- (void)testCoordinateBoundsFromLatLongs {
NSArray<NSNumber *> *latlong1 = @[ @1, @2 ];
NSArray<NSNumber *> *latlong2 = @[ @(3), @(4) ];

GMSCoordinateBounds *bounds =
[FLTGoogleMapJSONConversions coordinateBoundsFromLatLongs:@[ latlong1, latlong2 ]];

const CGFloat accuracy = 0.001;
XCTAssertEqualWithAccuracy(bounds.southWest.latitude, 1, accuracy);
XCTAssertEqualWithAccuracy(bounds.southWest.longitude, 2, accuracy);
XCTAssertEqualWithAccuracy(bounds.northEast.latitude, 3, accuracy);
XCTAssertEqualWithAccuracy(bounds.northEast.longitude, 4, accuracy);
}

- (void)testMapViewTypeFromTypeValue {
XCTAssertEqual(kGMSTypeNormal, [FLTGoogleMapJSONConversions mapViewTypeFromTypeValue:@1]);
XCTAssertEqual(kGMSTypeSatellite, [FLTGoogleMapJSONConversions mapViewTypeFromTypeValue:@2]);
XCTAssertEqual(kGMSTypeTerrain, [FLTGoogleMapJSONConversions mapViewTypeFromTypeValue:@3]);
XCTAssertEqual(kGMSTypeHybrid, [FLTGoogleMapJSONConversions mapViewTypeFromTypeValue:@4]);
XCTAssertEqual(kGMSTypeNone, [FLTGoogleMapJSONConversions mapViewTypeFromTypeValue:@5]);
}

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

// TODO(cyanglaz): Fix the test for CameraUpdateFromChannelValue 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.
// This class method conflicts with certain category method in OCMock, causing OCMock not able to
// disambigious them.
//
// 2. Directly verify the GMSCameraUpdate object returned by the method.
// The GMSCameraUpdate object returned from the method doesn't have any accessors to the "target"
// property. It can be used to update the "camera" property in GMSMapView. However, [GMSMapView
// moveCamera:] doesn't update the camera immediately. Thus the GMSCameraUpdate object cannot be
// verified.
//
// The code in below test uses the 2nd approach.
- (void)skip_testCameraUpdateFromChannelValueNewLatLong {
NSArray *channelValue = @[ @"newLatLng", @[ @1, @2 ] ];

GMSCameraUpdate *update = [FLTGoogleMapJSONConversions cameraUpdateFromChannelValue:channelValue];

GMSMapView *mapView = [[GMSMapView alloc]
initWithFrame:CGRectZero
camera:[GMSCameraPosition cameraWithTarget:CLLocationCoordinate2DMake(5, 6) zoom:1]];
[mapView moveCamera:update];
const CGFloat accuracy = 0.001;
XCTAssertEqualWithAccuracy(mapView.camera.target.latitude, 1,
accuracy); // mapView.camera.target.latitude is still 5.
XCTAssertEqualWithAccuracy(mapView.camera.target.longitude, 2,
accuracy); // mapView.camera.target.longitude is still 6.
}

- (void)testCameraUpdateFromChannelValueNewLatLngBounds {
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];

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

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

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

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

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

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

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

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

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

[[classMockCameraUpdate expect] zoomBy:1];

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

[FLTGoogleMapJSONConversions cameraUpdateFromChannelValue:channelValueWithPoint];

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

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

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

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

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

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

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

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

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

[[classMockCameraUpdate expect] zoomTo:1];
[classMockCameraUpdate stopMocking];
}

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// 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 <Flutter/Flutter.h>
#import <GoogleMaps/GoogleMaps.h>

NS_ASSUME_NONNULL_BEGIN

@interface FLTGoogleMapJSONConversions : NSObject

+ (CLLocationCoordinate2D)locationFromLatLong:(NSArray *)latlong;
+ (CGPoint)pointFromArray:(NSArray *)array;
+ (NSArray *)arrayFromLocation:(CLLocationCoordinate2D)location;
+ (UIColor *)colorFromRGBA:(NSNumber *)data;
+ (NSArray<CLLocation *> *)pointsFromLatLongs:(NSArray *)data;
+ (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;

@end

NS_ASSUME_NONNULL_END
Loading

0 comments on commit 801c1f6

Please sign in to comment.