Getting Started with the Places SDK for iOS (Objective-C)

1. Before you begin

Before you begin coding, there are a few prerequisites that you'll need to set up.

Xcode

This tutorial uses Apple's Xcode tool, along with the Objective-C language to create a simple iOS application that runs in an emulator. You don't need a physical device. You can get Xcode at https://developer.apple.com/xcode/

CocoaPods

The Places SDK for iOS is available as a CocoaPods pod. CocoaPods is an open source dependency management tool for Swift and Objective-C projects. If you don't have this tool already, you'll need to install it before going any further. It can be installed from the terminal like this:

sudo gem install cocoapods

For more details on CocoaPods, see the CocoaPods Getting Started guide.

Installing the SDK

To install the SDK you need to create a Podfile in your project directory that CocoaPods will use to download and configure the requisite dependencies. The easiest way to do this is to create a new Project in Xcode, add a Podfile to that, and install the pods there.

Open Xcode and you'll see the ‘Welcome to Xcode' screen. On here, select ‘Create a new Xcode project'

4f1ecee473937c7b.png

On the next screen you'll be asked for a template for your new project. Select ‘Single View Application' for iOS, and press ‘Next'

When asked for the Product Name, you can choose anything you like, but be sure to note the Bundle Identifier that is generated for you. You'll need that later.

72fbf25cb2db22ad.png

Press ‘Next' and the project will be created for you. Take a note of the directory where it is created. Close Xcode and using Terminal, navigate to that directory.

Using Terminal, enter the following command:

pod init

A file called Podfile will be created for you. Edit it to add a pod for GoogleMaps like this:

target '{YOUR APP NAME}' do
pod 'GoogleMaps'
end

Save it, and close Xcode. Be sure to close it, because in the next step you are going to edit the underlying project. You'll be opening a different project file once it's done, and it's pretty common for a developer to get confused as to where everything is if they didn't previously close Xcode! Now, in a terminal, go to your project directory and run ‘pod install' like this:

789c5bc62817f68a.png

Once you're done, the pods will be installed and a new .xcworkspace file will be created. Use this for the project from now on. But, before coding, the next thing you'll need is an API key.

2. Get your API Key

For the following enablement step, enable Maps SDK for iOS.

Set up Google Maps Platform

If you do not already have a Google Cloud Platform account and a project with billing enabled, please see the Getting Started with Google Maps Platform guide to create a billing account and a project.

  1. In the Cloud Console, click the project drop-down menu and select the project that you want to use for this codelab.

  1. Enable the Google Maps Platform APIs and SDKs required for this codelab in the Google Cloud Marketplace. To do so, follow the steps in this video or this documentation.
  2. Generate an API key in the Credentials page of Cloud Console. You can follow the steps in this video or this documentation. All requests to Google Maps Platform require an API key.

3. Creating the Places API App

Now that you've created a console project, and activated the Places API on it, obtaining an API key, you're ready to begin coding your first Places API app.

Earlier when you installed the pod files, a new .xcworkspace file was created for you. Open this by double-clicking on it.

19d62f34c08e645c.png

You'll notice in your Project Explorer that you now have a new folder called ‘Pods'. If this worked successfully, you'll see a GoogleMaps folder in there containing the frameworks.

8844d861f64c61aa.png

4. Edit the Info.plist file.

When you first run the application, iOS will give you a dialog asking the user to give permission to access the location services. This dialog will give a string that you define, and you put it in the Info.plist file. If this string isn't present, the dialog won't show, and your app won't work.

You can find the Info.plist file in the project explorer here:

c224c920ab3f1ef.png

Select it, and you'll see the plist editor.

859ca56f3b19da5.png

Hover the mouse over any of the elements, and you'll see a ‘+' icon appears. Press it, and you'll see a new entry appears. Enter the value ‘NSLocationAlwaysUsageDescription' in this box.

9fb225d6f5508794.png

Press Enter to add the new key. Then double click the Value column for this key, and add a string:

5aefeb184187aa58.png

To learn more about this string, see the apple developer documentation here.

5. Edit your App Delegate

In the project explorer, find and open AppDelegate.m. You'll use this to add your API Key.

At the top of the file, add this immediately below the #import line:

@import GoogleMaps;

Then, in the didFinishLaunchingWithOptions: function add the following just about the ‘return YES' line:

[GMSServices provideAPIKey:@"<Add your API Key>"];

Be sure to use the API Key that you generated earlier.

6. Edit your Storyboard File

In the project explorer, open the Main.storyboard file. Make sure the side bar is active by pressing the sidebar button in the top right hand corner.

352af28b970d9e2.png

Then, at the bottom of the sidebar, find the Label Control by making sure the Object Library is selected.

adec7051ae949531.png

In the View Controller Scene on the left hand side, make sure the ‘View' is selected:

e4827b92b5861e3e.png

Then drag and drop 7 labels onto the view. Arrange them as shown here. Be sure to drag their sizes to match what's shown. You can edit the text in the label by double clicking on it and typing the required value:

f8a9457772358069.png

For the bottom most label (the really large one), go to the properties editor and ensure that it is set to have 0 lines (It defaults to 1). This will allow it to render multiple lines.

a4abacf00d8888fe.png

7. Create Outlets for the Values

For the 3 ‘value' labels, you'll need to create an outlet. This will allow you to change their values using code. To do this, you'll first need to activate the assistant editor. To do this, first close the properties sidebar by clicking on its button to remove it. (This button was shown in the previous step)

Then, select the assistant button – it's the double circle one shown here:

e92dcc4ceea20a51.png

Make sure that it's rendering the ViewController.h file. If not, you can change it to do so using the editor at the top of the assistant window:

d42f0fcc18b84703.png

Then, when holding the CONTROL key, drag each label and drop it below the @interface line in the ViewController.h file in the assistant. A dialog will pop up asking what type of connection you want to make:

a44b7888ed0f62b.png

Make sure that the settings are as shown (Connection: Outlet; Type: UILabel; Storage: Weak), and then give each a name. For the purposes of this codelab, I called the Longitude, Latitude and Altitude labels lblLongitude, lblLatitude and lblAltidude respectively. Also drag the large label from the bottom over, and call it lblPlaces.

When you're done, your ViewController.h file should look like this:

#import <UIKit/UIKit.h>
@import GoogleMaps;

@interface ViewController : UIViewController
@property (weak, nonatomic) IBOutlet UILabel *lblLatitude;
@property (weak, nonatomic) IBOutlet UILabel *lblLongitude;
@property (weak, nonatomic) IBOutlet UILabel *lblAltitude;
@property (weak, nonatomic) IBOutlet UILabel *lblPlaces;

@end

8. Edit the Header File for Location and Google Client APIs

Before the final steps – where you build the app to use the places API you need to set up a few more variables in the header file (ViewController.h). These are the Core Location Manager and a Core Location object:

@property (strong, nonatomic) CLLocationManager *locationManager;
@property (strong, nonatomic) CLLocation *location;

You'll also need a Google API Client:

@property GMSPlacesClient *placesClient;

Finally, you'll need to update the header file so that the class implements the CLLocationManagerDelegate:

@interface ViewController : UIViewController<CLLocationManagerDelegate>

When you're done, your header file should look this this:

#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <GoogleMaps/GoogleMaps.h>


@interface ViewController : UIViewController<CLLocationManagerDelegate>
@property (strong, nonatomic) CLLocationManager *locationManager;
@property (strong, nonatomic) CLLocation *location;
@property (weak, nonatomic) IBOutlet UILabel *lblLongitude;
@property (weak, nonatomic) IBOutlet UILabel *lblLatitude;
@property (weak, nonatomic) IBOutlet UILabel *lblAltitude;
@property (weak, nonatomic) IBOutlet UILabel *lblPlaces;

@property GMSPlacesClient *placesClient;
@end

9. Edit your View Controller

The first step is to edit the viewDidLoad function to initialize the Location Manager, request the user's authorization to access location, and finally start the location manager so that it tracks the current location. You'll also initialize the Google Places API client.

- (void)viewDidLoad {
    [super viewDidLoad];
    self.locationManager = [[CLLocationManager alloc]init];
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    if([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
        [self.locationManager requestAlwaysAuthorization];
        // Or [self.locationManager requestWhenInUseAuthorization];
    }
    [self.locationManager startUpdatingLocation];
    
    self.locationManager.delegate = self;
    self.location = [[CLLocation alloc] init];
    self.placesClient = [GMSPlacesClient sharedClient];
}

10. Handle Location Updates

The location manager will call back to your View Controller with location updates by calling the didUpdateLocations function. You'll need to add this to your ViewController.m. The function looks like this:

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{
    // Enter code here
}

This function will need to do several things.

First, it will cache the location with the last received one:

self.location = locations.lastObject;

Next, the three labels for Latitude, Longitude and Altitude should be updated:

self.lblLatitude.text = [NSString stringWithFormat:@"%f", self.location.coordinate.latitude];

self.lblLongitude.text = [NSString stringWithFormat:@"%f", self.location.coordinate.longitude];

self.lblAltitude.text = [NSString stringWithFormat:@"%f", self.location.altitude];

Next you will call the Places API using the places Client. You do this by specifying the callback function, which will get the list of place likelihoods. The Places API determines the likelihood that you are in a particular place based on your location. It returns the name of likely places, along with a value between 0 and 1 containing the probability that you're in that place.

[self.placesClient currentPlaceWithCallback:^(GMSPlaceLikelihoodList *likelihoodList, NSError *error) {

Then you can implement the callback. This will iterate through the list of likelihoods, adding places and likelihoods for those places.

[self.placesClient currentPlaceWithCallback:^(GMSPlaceLikelihoodList *likelihoodList, NSError *error) {

  if (error != nil) {
    NSLog(@"Current Place error %@", [error localizedDescription]);
    return;
  }
  NSMutableString *strPlaces = [NSMutableString stringWithString:@""];

  for (GMSPlaceLikelihood *likelihood in likelihoodList.likelihoods) {
    GMSPlace* place = likelihood.place;
    NSLog(@"Current Place name %@ at likelihood %g", place.name,
            likelihood.likelihood);
    NSLog(@"Current Place address %@", place.formattedAddress);
    NSLog(@"Current Place attributions %@", place.attributions);
    NSLog(@"Current PlaceID %@", place.placeID);
    [strPlaces appendString:place.name];
    [strPlaces appendString:@" "];
    [strPlaces appendFormat:@"%g",likelihood.likelihood];
    [strPlaces appendString:@"\n"];
  }
  self.lblPlaces.text = strPlaces;
}];

When you're done, your didUpdateLocations function should look like this:

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{
    
    self.location = locations.lastObject;
    self.lblLatitude.text = [NSString stringWithFormat:@"%f", self.location.coordinate.latitude];
    self.lblLongitude.text = [NSString stringWithFormat:@"%f", self.location.coordinate.longitude];
    self.lblAltitude.text = [NSString stringWithFormat:@"%f", self.location.altitude];
    
    NSLog(@"%@", self.location.description);
    
    [self.placesClient currentPlaceWithCallback:^(GMSPlaceLikelihoodList *likelihoodList, NSError *error) {

        if (error != nil) {
            NSLog(@"Current Place error %@", [error localizedDescription]);
            return;
        }
        NSMutableString *strPlaces = [NSMutableString stringWithString:@""];
        
        for (GMSPlaceLikelihood *likelihood in likelihoodList.likelihoods)  
        {
            GMSPlace* place = likelihood.place;
            NSLog(@"Current Place name %@ at likelihood %g", place.name, likelihood.likelihood);
            NSLog(@"Current Place address %@", place.formattedAddress);
            NSLog(@"Current Place attributions %@", place.attributions);
            NSLog(@"Current PlaceID %@", place.placeID);
            [strPlaces appendString:place.name];
            [strPlaces appendString:@" "];
            [strPlaces appendFormat:@"%g",likelihood.likelihood];
            [strPlaces appendString:@"\n"];
        }
        self.lblPlaces.text = strPlaces;
    }];
}

You're now ready to run your app and test it!

11. Running the App in the Emulator

You run the app using the run button in the title bar. This also lets you select the run type, and as you can see here I'm testing on an iPhone 6, using the emulator.

bbbe0b8820c8a913.png

When you press the run button, the app will build and launch. You'll see the request to allow the app to access location, including the custom string you specified earlier.

b9bb2ace7e68f186.png

Once you do this, you'll see your Latitude and Longitude update. To change the location, select the Debug menu, and pick a location. For example, you can pick the ‘Freeway Drive'

dcb1ce091d780f56.png

When you do this, you'll see the location with its likely places updating, simulating the freeway drive.

649e3eeb2321ae03.png

And that's it! You've successfully accessed the current place details using the Google Places API on iOS.