Google Maps Integration iOS Swift. Part 1

Andrii Petrovskyi
5 min readJul 8, 2021

Description: — GoogleMaps with custom theme and Clustering. iOS Swift

Content:

  • Preparing GoogleMaps API_KEY
  • GoogleMaps integration (Using Swift Package Manager)
  • Let’s code (add and set MapView, add Clustering, set Custom GoogleMap Theme)

Useful Links:

MapStyleWithGoogle
GoogleMapsSPM
GoogleMapsUtils
GoogleMapsDoc

Preparing GoogleMaps API_KEY
1. Go to credentials page (before this step you need to check is Maps SDK for iOS enable in your project here, if not just choose Maps SDK for iOS and then enable)

2. Click to Create Credentials

3. Choose API Key

4. Then click on Restrict key

5. Choose iOS apps and add Bundle ID

6. Select Restrict key and then select Maps SDK for iOS in list

7. And finally copy your API_KEY and save somewhere in project

GoogleMaps integrating
- add GoogleMaps Swift Package. GoogleMapsSPM
-
add GoogleMapsUtiles Swift Package. GoogleMapsUtils

Lets’s code
Part 1 — Add and setup GMSMapView
In this project i will be Using MVP Architecture to separate responsobilites
So first of all i will create New Group and call it “MapScene”

Then i will create also View and Presenter Folders with controller and presenter files inside. At the end it should look something like this.

Now we could start implementing GMSMapView:

  1. Import GoogleMaps
  2. Create GMSMapView instance
  3. Create some default GMSCameraPosition to focus our map on a specific area. In my case it will be my lovely city Kyiv
import UIKitimport GoogleMapsstruct KyivLocation {  static let latitude: CLLocationDegrees = 50.450001  static let longitude: CLLocationDegrees = 30.523333}final class MapViewController: UIViewController {   private lazy var mapView: GMSMapView? = {         return GMSMapView(frame: view.bounds,                            camera: camera)}() private lazy var camera: GMSCameraPosition = {        return GMSCameraPosition(latitude: KyivLocation.latitude,                                 longitude: KyivLocation.longitude,                                  zoom: 7)  }()}

4. Now we need to add and layout mapView (i prefer do this programmatically), So we need to write some layout function, but before this i want to add some UIView’s extension to make our live easier. This method will be look something like this:

import UIKitextension UIView {func addSubview(_ subview: UIView, layout: (_ subview: UIView) -> ([NSLayoutConstraint])) {
guard let subview = subview else { return }
subview.translatesAutoresizingMaskIntoConstraints = false addSubview(subview) let constraints = layout(subview) NSLayoutConstraint.activate(constraints)}}

P.S. — You can put this method in file with your Extension for UIView like I do.

Okay, let’s clip out mapView using this method(in my case i want to let some top space free):

private func layoutMapView() {    view.addSubview(mapView) { [         $0.topAnchor.constraint(equalTo: view.topAnchor, constant: 40),         $0.leftAnchor.constraint(equalTo: view.leftAnchor),         $0.rightAnchor.constraint(equalTo: view.rightAnchor),         $0.bottomAnchor.constraint(equalTo: view.bottomAnchor)   ] }}

Now we need to override viewDidLoad method and call our layoutMapView() inside:

override func viewDidLoad() {
super.viewDidLoad()
layoutMapView()}

Nice! At this point we created MapView and clip it to the view. We are almost ready to run app, but before this, don’t forget to provide your ApiKey.
So better to do this before we open the Map, so let’s provide ApiKey inside didFinishLaunchingWithOptions, so you can simply open your AppDelegate file, and put this line of code at the end of didFinishLaunchingWithOptions method, so your method should look like this, and don’t forget to import GoogleMaps inside AppDelegate:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {    // Override point for customization after application launch.
GMSServices.provideAPIKey("YOUR_API_KEY")
return true
}

Or if you want to do this in better way, we could create some protocol, call hime GooglMapsProvider, and give hime some default method with name provideGMSApiKey(), and then just conform our AppDelegate to this protocol and call this method inside didFinishLaunchingWithOptions:

This is how our GoogleMapsProvider will be looks like

import Foundationimport GoogleMapsprotocol GoogleMapsProvider {}extension GoogleMapsProvider {   func provideGMSApiKey() {       GMSServices.provideAPIKey("YOUR_API_KEY")    }}

And this is how our AppDelegate will be looks like:

5. At this point almost done with MapView, let one important thing! We need to add NSLocationWhenInUseUsageDescription and NSLocationAlwaysAndWhenInUseUsageDescription to use and show users current location, so open Info.plis as source code and past there this four lines:

<key>NSLocationWhenInUseUsageDescription</key><string>Location usage Description</string><key>NSLocationAlwaysAndWhenInUseUsageDescription</key><string>Location usage Description</string>

6. We’v done with view, so now we can run the app, but before we need to pass to MapViewController from our base ViewContrller, so i will add only one button on this controller which will present our MapViewController, so my ViewController will look like this:

import UIKitclass ViewController: UIViewController {   let button: UIButton = {       let btn = UIButton()       btn.setTitle("Open Map", for: .normal)       btn.backgroundColor = .black       btn.tintColor = .white       btn.addTarget(self, action: #selector(openMap), for: .touchUpInside)      return btn  }()  override func viewDidLoad() {      super.viewDidLoad()      layoutButton()  }  @objc func openMap() {      let mapControler = MapViewController()      present(mapControler, animated: true)   }   private func layoutButton() {      view.addSubview(button) { [          $0.centerYAnchor.constraint(equalTo: view.centerYAnchor),          $0.centerXAnchor.constraint(equalTo: view.centerXAnchor),          $0.widthAnchor.constraint(equalToConstant: 150),          $0.heightAnchor.constraint(equalToConstant: 55)     ] }  }}

So we are ready to run the App:

--

--