Categories
Uncategorized

How to use Google Maps in SwiftUI apps

by Ahmed Mgua (@_mgua)

In this tutorial we’ll create a simple reusable Google Maps view that you can use in your SwiftUI apps. The process is simple but it takes a few steps:

  1. Use CocoaPods to get the Google Maps SDK for our Xcode project
  2. Obtain and set up the API key using the Google Cloud Platform
  3. Create a custom AppDelegate to prepare the API calls
  4. Create a reusable Google Maps view we can use in our SwiftUI app

This tutorial is also suitable for beginners who have not yet worked with CocoaPods.

Disclaimer: Google Maps cannot be directly integrated into SwiftUI views. Therefore, we choose a workaround by using the UIViewRepresentable protocol. Also note that you will need a Google Cloud Platform account. However, for the purposes of this tutorial, a free trial account is sufficient (more on that below).

Installing the GoogleMaps SDK using CocoaPods 🌎

Let’s start creating a new Xcode project. Select “App” under the “Multiplatform” or your preferred platform tab. Name your project “GoogleMapsDemo” and make sure to use SwiftUI as the “Interface” and “Life Cycle” mode. Then go ahead creating your project at your preferred location.

After you created your project quit Xcode by pressing CMD-Q and open your Terminal. Type in the following code:

sudo gem install cocoapods

CocoaPods are written in Ruby, so don’t worry if the code looks foreign to you. Enter your password when prompted. Installing CocoaPods may take a few minutes. Once the installation process is complete, finish the setup by typing in the following code:

pod setup --verbose

This step could take a while as it clones the MasterSpecs repo from CocoaPods. By using the — verbose command we tell the Terminal to return the progress of this process.

Once the setup is complete, we need to navigate to our project folder. You can do this by typing in cd ~/…… completing it with the path to your project folder and pressing enter. You can also type cd and drag and drop your project folder and then press enter.

Once you’re in the project folder, type in this line and press enter.

pod init

This creates a PodFile in your project folder. You can find this PodFile by opening your project folder in the Finder. However, don’t close your Terminal yet. Open the PodFile using the Text Editor.

The code inside the file should look like this:

Uncomment the next line to define a global platform for your project
 platform :ios, '9.0'
 target 'GoogleMapsDemo' do
   # Comment the next line if you don't want to use dynamic frameworks
   use_frameworks!
 # Pods for GoogleMapsDemo
 end

Now we need to specify the pod we would like to install which is the GoogleMaps pod. To do this, add the following line to your PodFile:

Uncomment the next line to define a global platform for your project
 platform :ios, '9.0'
 target 'GoogleMapsDemo' do
   # Comment the next line if you don't want to use dynamic frameworks
   use_frameworks!
 # Pods for GoogleMapsDemo
      pod 'GoogleMaps', '4.1.0'
 end

Next, save and close the PodFile. To install the specified pods we go back to the terminal and enter the following command:

pod install --verbose

Using the –verbose command again the terminal will show us the progress as it downloads the dependencies. Once the installation is complete, you should see a new file with the extension .xcworkspace in your project folder.

Important: From now on, use this file to open your project and not the .xcodeproj file.

Setting up the Google Maps SDK 🗺

With the PodFile set up and the Google Maps SDK installed, we now need to generate our personal API key using the Google Cloud Platform. To do this, go to the Google Cloud Platform. Create a free trial account if not already done yet.

Once you logged into your Google Cloud Platform account, click on the menu button in the top left corner, select “APIs & Services” and choose “Credentials”.

In the credentials section, click on “+ Create Credentials” and select “API Keys”.

Next, select the created API key and click the Edit button.

We now need to setup the restrictions for our API key. This allows us to make calls from our SwiftUI apps using the generated API key. Select iOS apps in the restrictions list.

Then click on “Add Item” and insert the Bundle Identifier of your Xcode project. Finally, click on “Done”

Hint: You can find Bundle Identifier in the “General Tab” of your project file.

At this point, we can go back to the “Credentials” tab and copy the API key to our clipboard.

Then switch from the “Credentials” to the “Dashboard” tab .

Next, click on “Enable APIs and Services” button at the top of the API dashboard. Now the API library opens up. Select “Maps SDK for iOS” and click on the “Activate” button.

Finally, we are ready to use the Google Maps API in our SwiftUI project.

Creating a custom App Delegate 🧑🏽‍💻

Now we go back to our Xcode project and open up our SwiftUIDemoApp.swift file. Let’s insert the API key we copied to our clipboard earlier. Also make sure to import the Google Maps library at the top of the SwiftUIDemoApp.swift file.

import SwiftUI
import GoogleMaps
 

 let APIKey = "INSERT_YOUR_API_KEY_HERE"
 

 @main
 struct SwiftUIDemoApp: App {
     var body: some Scene {
         WindowGroup {
             ContentView()
         }
     }
 }

If you are still working with SwiftUI 1.0, find the didFinishingLaunchingWithOptions function in the AppDelegate class and insert the following code.

GMSServices.provideAPIKey("INSERT_YOUR_API_KEY_HERE")

Inn SwiftUI 2.0 however, apps are initialized using the @main attribute. Thus, we need to create our own, custom App Delegate. We can do this by adding a new class to our SwiftUIDemoApp.swift file that inherits from NSObject and conforms to the UIApplicationDelegate protocol. Inside this class, we implement the didFinishingLaunchingWithOptions function (don’t worry if you don’t know it, just type in “didFinishLa..” and select it in the autocomplete list), inside which we will put our API keys.

class AppDelegate: NSObject, UIApplicationDelegate    {
     func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
         GMSServices.provideAPIKey(APIKey)
         return true
     }
 }

Next, we need to initialize our custom AppDelegate at the app’s entry point. We do this by adding a UIApplicationDelegateAdaptor property to our @main struct and passing our AppDelegate class.

@main
 struct SwiftUIDemoApp: App {
     
     @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
     
     var body: some Scene {
         WindowGroup {
             ContentView()
         }
     }
 }

Awesome, we are now all set to create our actual Google Maps view.

Creating the MapView 🧭

Let’s start by creating a new SwiftUI View file and naming it appropriately, for example GoogleMapsView. Again, make sure to import the GoogleMaps library.

import SwiftUI
import GoogleMaps
 

 struct GoogleMapsView: View {
     var body: some View {
         Text("Hello, World!")
     }
 }
 

 struct GoogleMapsView_Previews: PreviewProvider {
     static var previews: some View {
         GoogleMapsView()
     }
 }

The struct that Xcode gives us is a SwiftUI View. However, Google Maps views cannot be inserted into SwiftUI directly. Therefore we need a workaround using the UIViewRepresentable protocol.

Thus, we remove the body of our GoogleMapsView and replace the View conformance with UIViewRepresentable. At this point, you can also delete the GoogleMapsView_Previews struct.

struct GoogleMapsView: UIViewRepresentable {
     
 }

Inside this struct, we need to implement the makeUIView and updateUIView functions to conform to the UIViewRepresentable protocol.

Hint: The makeUIView struct is used to initialise and return the specific UIView. The updateUIView updates the UIView every time it gets called . If you want to dig deeper into the UIViewRepresentable protocol, make sure to check out this tutorial as well.

struct GoogleMapsView: UIViewRepresentable {
     
     func makeUIView(context: Context) -> GMSMapView {
         
     }
     
     func updateUIView(_ uiView: GMSMapView, context: Context) {
         
     }
 }

The updateUIView function doesn’t need to do anything for now, so you can leave that empty. The makeUIView function however, needs to return a GMSMapView instance.

func makeUIView(context: Context) -> GMSMapView {
         let mapView = GMSMapView(frame: CGRect.zero)
         
         return mapView
     }

Next, we need to provide a camera position and the amount of zoom we want the view to show. The camera position is basically the location we want to show in latitude and longitude, and the zoom level sets the span that the display width will show.

For example, we can create an extension on GMSCameraPosition that adds the location for London.

extension GMSCameraPosition  {
     static var london = GMSCameraPosition.camera(withLatitude: 51.507, longitude: 0, zoom: 10)
 }

Finally, use this extension to set the camera in our makeUIView function and pass it to mapView using the camera argument:

 func makeUIView(context: Context) -> GMSMapView {
         let camera = GMSCameraPosition.london
         
         let mapView = GMSMapView(frame: CGRect.zero, camera: camera)
         
         return mapView
     }

We can treat the created GoogleMapsView just like a normal SwiftUI view. For instance, let’s insert GoogleMapsView instance into our ContentView. By using the .edgesIgnoringSafeArea modifier we make sure that the GoogleMapsView covers the whole screen of the device the app runs on.

struct ContentView: View {
     var body: some View {
         GoogleMapsView()
             .edgesIgnoringSafeArea(.all)
     }
 }

Once you’re finished, we can launch our app or start a live preview of our ContentView containing the GoogleMapsView.

Conclusion 🎊

Awesome. You now know how to integrate Google Maps into your SwiftUI app using CocoaPods, the Google Maps SDK and the UIViewRepresentable protocol.

We’ve uploaded the source code for the app to GitHub.

If you want to learn how to use native Apple Maps in SwiftUI check out our Interactive Mastering SwiftUI Book. Here you’ll learn how to interact with Apple Maps, implement location functionality and retrieve images via the Flickr API depending on the user’s location.