[google_maps_ios] Cache `+[GMSServices sharedServices]` when first map is created (#6211)

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 e4b243a..33d96e9 100644
--- a/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md
+++ b/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 2.1.11
+
+* Precaches Google Maps services initialization and syncing.
+
 ## 2.1.10
 
 * Splits iOS implementation out of `google_maps_flutter` as a federated
diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsTests.m b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsTests.m
index a8768e1..71f1162 100644
--- a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsTests.m
+++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsTests.m
@@ -5,10 +5,15 @@
 @import google_maps_flutter_ios;
 @import google_maps_flutter_ios.Test;
 @import XCTest;
+@import GoogleMaps;
 
 #import <OCMock/OCMock.h>
 #import "PartiallyMockedMapView.h"
 
+@interface FLTGoogleMapFactory (Test)
+@property(strong, nonatomic, readonly) id<NSObject> sharedMapServices;
+@end
+
 @interface GoogleMapsTests : XCTestCase
 @end
 
@@ -39,4 +44,16 @@
   XCTAssertEqual(mapView.frameObserverCount, 0);
 }
 
+- (void)testMapsServiceSync {
+  id registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar));
+  FLTGoogleMapFactory *factory1 = [[FLTGoogleMapFactory alloc] initWithRegistrar:registrar];
+  XCTAssertNotNil(factory1.sharedMapServices);
+  FLTGoogleMapFactory *factory2 = [[FLTGoogleMapFactory alloc] initWithRegistrar:registrar];
+  // Test pointer equality, should be same retained singleton +[GMSServices sharedServices] object.
+  // Retaining the opaque object should be enough to avoid multiple internal initializations,
+  // but don't test the internals of the GoogleMaps API. Assume that it does what is documented.
+  // https://developers.google.com/maps/documentation/ios-sdk/reference/interface_g_m_s_services#a436e03c32b1c0be74e072310a7158831
+  XCTAssertEqual(factory1.sharedMapServices, factory2.sharedMapServices);
+}
+
 @end
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 41c5d77..bd50c2d 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
@@ -11,11 +11,14 @@
 @interface FLTGoogleMapFactory ()
 
 @property(weak, nonatomic) NSObject<FlutterPluginRegistrar> *registrar;
+@property(strong, nonatomic, readonly) id<NSObject> sharedMapServices;
 
 @end
 
 @implementation FLTGoogleMapFactory
 
+@synthesize sharedMapServices = _sharedMapServices;
+
 - (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
   self = [super init];
   if (self) {
@@ -31,11 +34,26 @@
 - (NSObject<FlutterPlatformView> *)createWithFrame:(CGRect)frame
                                     viewIdentifier:(int64_t)viewId
                                          arguments:(id _Nullable)args {
+  // Precache shared map services, if needed.
+  // Retain the shared map services singleton, don't use the result for anything.
+  (void)[self sharedMapServices];
+
   return [[FLTGoogleMapController alloc] initWithFrame:frame
                                         viewIdentifier:viewId
                                              arguments:args
                                              registrar:self.registrar];
 }
+
+- (id<NSObject>)sharedMapServices {
+  if (_sharedMapServices == nil) {
+    // Calling this prepares GMSServices on a background thread controlled
+    // by the GoogleMaps framework.
+    // Retain the singleton to cache the initialization work across all map views.
+    _sharedMapServices = [GMSServices sharedServices];
+  }
+  return _sharedMapServices;
+}
+
 @end
 
 @interface FLTGoogleMapController ()
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 f55da6e..a870962 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 @@
 description: iOS implementation of the google_maps_flutter plugin.
 repository: https://github.com/flutter/plugins/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.1.10
+version: 2.1.11
 
 environment:
   sdk: ">=2.14.0 <3.0.0"