Search Posts in my Blog

Friday 2 March 2012

Working with Google Places API



In this post I will demonstrate how to work with google places API. Also i would request you to go through this link before continuing with this tutorial as their is a bug with the places api as you cannot find some of the places from india.

What is Google Places API:
The Google Places API is a service that returns information about Places — defined within this API as establishments, geographic locations, or prominent points of interest.
How to work with google api: The google api works some what like this you supply in the coordinates of a specific place and it will give you the output either in xml or json format, but in order to get that output you must have the API key with you and that key is provided by google, so how to get that API key well if you follow the instructions given in this link then its quite easy.
Design Phase: The flow of the entire demo is like this
a.     I will be displaying the entire bank list by supplying the coordinates of the Los Angeles and will be displaying the entire bank list in the table view. I will be parsing the places api xml output for this by using GData Parser (If you want to know how does the Gdata parser works then please refer to one of my previous blogs post that I wrote on GData).
b.  The Places Api XML output will also have the latitude and longitude for the banks so I will be making the use of the MapKit Framework to display the location of those banks with Pin Annotation.
c.  I will be using the Navigation Controller to display the table view containing the bank list and then when the user selects an appropriate bank name then with the help of the navigation controller he/she will be traversed to the next view, which would be our map view.
d. You can not only search for banks with the help of google places api but also lots of other stuff as well here’s a link to the items that you can search with the help of the places api. 

here’s a view at the final output


Step 1: Open Xcode and create a windows based application and give it a name GooglePlacesDemo or any name of your choice will also do, Add the UITableViewController subclass file to the project with the name PlacesTableViewController, that will result in adding of two new files into your project that would be PlacesTableViewController.h and PlacesTableViewController.m. Now here’s what we are going to do next we are going to get our places API key by referring the steps given in thegoogle link.
Step 2: By now I feel you must be having your API key that would be required by you to get the data from the places API. Once this is done the next step is to get the GData parser which you can get from here and if you are new to GDataXML Parser well here’s a tutorial that I wrote earlier, please perform the setting part only for the GData parser.
Once this is done I would request you to add a new file of the UIViewController subclass and this file would be for the map view, so add a new file and give it the name MapViewController, so now their will be two more new files into your project (MapViewController.h and MapViewController.m). Guys I want you to follow my annotation post and be ready with the annotation coding part because we will be needing it.
Step 3: The structure of the XML file that we will be parsing would look some what like this so please have a close look at the xml file

The logic to parse the names and the destination of the banks are given below and this method is used inside the PlacesTableViewController.m file and make sure that you call this method inside the init method of the PlacesTableViewController


-(void)ParseXML_of_Google_PlacesAPI

{

    NSURL *googlePlacesURL = [NSURL URLWithString:PlacesURL];

    NSData *xmlData = [NSData dataWithContentsOfURL:googlePlacesURL];

    xmlDocument = [[GDataXMLDocument alloc]initWithData:xmlDataoptions:0 error:nil];

    NSArray *arr = [xmlDocument.rootElementelementsForName:@"result"];

    for(GDataXMLElement *e in arr )

    {

        [placesOutputArray addObject:e];

    }

    
}
Code Explanation: I don’t think that I should explain the above code in detail because they are self explanatory, you tell the GDataXMLDocument whats the structure of your xml file is and then apply a for loop for adding the entire element of the XML file inside a mutable array. Now what you can do is use this mutable array to display the name of the banks present in the XML file in your table and you do that like this. The PlacesURL is a macro that i am using, and it contains the entire link to the API including the coordinates and the place that you want to get like banks, atms, schools etc here's the view to that
#define PlacesURL @"https://maps.googleapis.com/maps/api/place/search/xml?location=34.0522222,-118.2427778&radius=500&types=bank&sensor=false&key=TheAPIKey_You_Got

NOTE: ADD the API key you got in the above URL ...

 Given below is the code that will display the xml data from the mutable array to the table, so inside the cellForRowAtIndexPath method of the table add this piece of code.



- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
   
    UITableViewCell *cell = [tableViewdequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]autorelease];
    }
   
    // Configure the cell...
    cell.textLabel.text = [[[placesOutputArray objectAtIndex:indexPath.row]childAtIndex:0stringValue];
    cell.detailTextLabel.text = [[[placesOutputArrayobjectAtIndex:indexPath.rowchildAtIndex:1stringValue];


    return cell;
}


Similarly you may use the above code if you are parsing the XML file for atms, schools etc and for that just change the text from the PlaceURL macro from banks to atms or schools or what ever place you want and all you have to do is change the text from the PlacesURL macro from bank to school.



Step 4: I would request you to take your time and read the above code do your part of the research and then start reading the step 4 as it is involved with the map part.
Now half of the application has been completed, now the only thing remaining is to show the annotation part inside the map (if you don’t know how to add annotation then please read this post), select the NSObject class that you must have used to display the annotation in the map and create your own init method because we will get the latitude, longitude and the name of the bank from the PlacesTableViewController file.
This is how the init method will look like in the .h file


-(id)initWithName:(NSString*)_placeName andCoordinates:(CLLocationCoordinate2D)_coordinates; 

And this is how it will be implemented in the .m file
-(id)initWithName:(NSString*)_placeName andCoordinates:(CLLocationCoordinate2D)_coordinates
{

    pinTitle = _placeName;
    _theCords = _coordinates;

    return self;
}

The pinTitle is a object of the NSString class declared in the .h file of the NSObject class that you will be using to display the annotation and the _theCords is the variable of the structure of the CLLocationCoordinate2D.


The code for adding the annotation looks like this in the NSObject class for the annotation
-(CLLocationCoordinate2D)coordinate
{

   CLLocationCoordinate2D cords = {_theCords.latitude,_theCords.longitude};
    return cords;

}




Step 5:  yes i forgot to mention you have to make your own init method inside the MapViewController class here's the view to that and why are we doing this you will come to know this when we proceed with the tutorial
 - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil bankName:(NSString*)_name andCoordinates:(CLLocationCoordinate2D)bankcords;



Please select the PlacesTableViewController.m file and please traverse through tableView:didselect row method and modify this code as per your project

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

{

    //storing the title inside the str variable

    NSString *str = [[[placesOutputArray objectAtIndex:indexPath.row]childAtIndex:0stringValue];

   

    //parsing for latitude

   

    double lat = [[[[[[[[placesOutputArrayobjectAtIndex:indexPath.row]elementsForName:@"geometry"]objectAtIndex:0elementsForName:@"location"objectAtIndex:0]childAtIndex:0]stringValue]doubleValue];

   

    //parsing for longitude

    double lng = [[[[[[[[placesOutputArrayobjectAtIndex:indexPath.row]elementsForName:@"geometry"]objectAtIndex:0elementsForName:@"location"objectAtIndex:0]childAtIndex:1stringValuedoubleValue];

   

    //adding the new latitude and longitude inside the CLLocationCordinate2D variable

    CLLocationCoordinate2D _cords = {lat,lng};

   

    //supplying the bank title and the bank coordinates to the MapViewController class so that it we can use them inside the MapViewController to display the annotation with the title...

    mapViewC = [[MapViewController alloc]initWithNibName:nil bundle:nilbankName:str andCoordinates:_cords];


    [self.navigationController pushViewController:mapViewC animated:YES];

   

}

  
Code Explanation:  The str is a NSString variable which contains the name of the bank, the lat and lng are double variables which contains the parsed coordinates value from the xml file and since we want to supply these values to the NSObject class then I thought of creating own init method inside the MapViewController class so that the data can flow from the PlacesTableView to the MapView and from their to the NSObject class.
Inside the MapViewController.m file here's how i make use of this data and
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil bankName:(NSString*)_name andCoordinates:(CLLocationCoordinate2D)bankcords
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
        bankName = _name;
        globalCords = bankcords;
    }
    return self;
}

Code Explanation: bankName is the object of the NSString class declared in the .h file of the MapViewController and globalCords is the variable of the CLLocationCordinate2D.

Select the loadView method of the MapViewController class and add the following code.

- (void)loadView
{
    [super loadView];
    //allocating memory for the mapview
    mpView = [[MKMapView alloc]initWithFrame:self.view.bounds];
   
    //allocating memory for the NSObject class used to display the mapannotation
    mapAnnotObject = [[MyMapAnnot alloc]initWithName:bankNameandCoordinates:globalCords];
   
    //showing a particular region on the map
    CLLocationCoordinate2D cord = {globalCords.latitude,globalCords.longitude};
    MKCoordinateSpan spn = {0.01,0.01};
    MKCoordinateRegion reg = {cord,spn};
    [mpView setRegion:reg];
   
    //adding the annotation on the map view
    [mpView addAnnotation:mapAnnotObject];
   
    //adding the mapview to the view
    [self.view addSubview:mpView];
   
}


Now select the app delegate .m file and add the placesTableViewCOntroller to the UINavigationController object and add the navigation controller object to the iPhone window 


#import "GooglePlacesAPIDemoAppDelegate.h"
#import "PlacesTableViewController.h"

@implementation GooglePlacesAPIDemoAppDelegate

@synthesize window=_window;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    PlacesTableViewController *obj = [[PlacesTableViewController alloc]init];

    UINavigationController *navC = [[UINavigationControlleralloc]initWithRootViewController:obj];
    [self.window addSubview:navC.view];
    [self.window makeKeyAndVisible];
    return YES;
}

Run the application you will get the following output
Banks of the LA




Map View

So if you even change the string from the PlacesURL macro to atm or school the above code will work fine, here's how to perform the first change inside the PlacesURL macro
#define PlacesURL @"https://maps.googleapis.com/maps/api/place/search/xml?location=34.0522222,-118.2427778&radius=500&types=school&sensor=false&key=YourAPI_Key”




NOTE: ADD the API key you got in the above URL ...
Now after making the above change from banks to schools the output will be not for banks but for schools.

Schools List





Download source code here.


If you want your app to detect your current place and then find your nearby places then download from here
I hope that this post helped you

No comments:

Post a Comment