Getting Started with the Places SDK for iOS

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.

Your API Key will give you access to the Places API. You can get this by visiting the Get Started with Google Maps Platform page. You will have to do the following:

  1. Go to the Google Cloud Platform Console.
  2. Create a new project.

f2a353c3301dc649.png56a42dfa7ac27a35.png

Enable Billing

When you create a new project, you're prompted to choose which of your billing accounts you want to link to the project. If you have a billing account, that account is automatically linked. If you don't have a billing account, you must create one and enable billing for your project before you can use many Google Cloud Platform features.

To create a new billing account:

  1. Open the Google Cloud Platform Console navigation menu and select Billing.
  2. Click Add billing account. (If this is your first billing account, click Create account.)
  3. Enter the name of the billing account and enter your billing information. The options you see depend on the country of your billing address.
  1. Click Submit and enable billing.

Get an API key

Follow these steps to enable the APIs used in this lab and get an API key:

  1. From the Navigation menu, select APIs & Services > Library.
  2. Click the Places API tile, then click Enable.
  3. From the Navigation menu, select APIs & Services > Credentials.
  4. Click Create Credentials and choose API key.
  5. Copy the API key displayed.

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

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.

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.

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

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

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

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

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!

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.