'Draw route directions using Google Maps iOS

I am getting a GMSPolyline to custom location but I am not getting a route direction (GMSPolyline) from user location to some custom location.

What I have done is placed a GMSMapView and kept core location. I am updating the route in core location delegate method (locationManager: didUpdateLocations:).

I want to use Google Maps for iOS SDK since Apple Maps don't have directions in the country I need. My code is below:

- (void)viewDidLoad
{
    [super viewDidLoad];

    waypointStrings_ = [[NSMutableArray alloc]init];

    GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:self.latitude longitude:self.longitude zoom:13];
    mapView_ = [GMSMapView mapWithFrame:CGRectZero camera:camera];
    mapView_.myLocationEnabled = YES;
    self.view = mapView_;

    CLLocationManager *locManager = [[CLLocationManager alloc] init];
    if ( [CLLocationManager locationServicesEnabled] ) {
        [locManager setDelegate:self];
        [locManager setDesiredAccuracy:kCLLocationAccuracyBest];
        [locManager startUpdatingLocation];
    }
}

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    CLLocationCoordinate2D userCoordinate = [[locations lastObject] coordinate];

    GMSMarker *marker = [GMSMarker markerWithPosition:CLLocationCoordinate2DMake(self.latitude,self.longitude)];
    marker.map = mapView_;
    NSString *majlisPositionString = [[NSString alloc] initWithFormat:@"%f,%f", self.latitude,self.longitude];
    [waypointStrings_ addObject:majlisPositionString];

    GMSMarker *userMarker = [GMSMarker markerWithPosition:CLLocationCoordinate2DMake(userCoordinate.latitude, userCoordinate.longitude)];
    userMarker.map = mapView_;
    NSString *userPositionString = [[NSString alloc] initWithFormat:@"%f,%f", userCoordinate.latitude, userCoordinate.longitude];
    [waypointStrings_ addObject:userPositionString];

    NSString *sensor = @"false";
    NSArray *parameters = [NSArray arrayWithObjects:sensor, waypointStrings_, nil];
    NSArray *keys = [NSArray arrayWithObjects:@"sensor", @"waypoints", nil];
    NSDictionary *query = [NSDictionary dictionaryWithObjects:parameters forKeys:keys];
    MDDirectionService *mds=[[MDDirectionService alloc] init];
    SEL selector = @selector(addDirections:);
    [mds setDirectionsQuery:query withSelector:selector withDelegate:self];
}

- (void)addDirections:(NSDictionary *)json {

    NSDictionary *routes = [json objectForKey:@"routes"][0];

    NSDictionary *route = [routes objectForKey:@"overview_polyline"];
    NSString *overview_route = [route objectForKey:@"points"];
    GMSPath *path = [GMSPath pathFromEncodedPath:overview_route];
    GMSPolyline *polyline = [GMSPolyline polylineWithPath:path];
    polyline.map = mapView_;
}


Solution 1:[1]

-(void)LoadMapRoute:(NSString*)SourceAddress andDestinationAddress:(NSString*)DestinationAdds
{
    NSString *strUrl;
    strUrl= [NSString stringWithFormat:@"http://maps.googleapis.com/maps/api/directions/json?origin=%@&destination=%@&sensor=false",SourceAddress,DestinationAdds];
    strUrl=[strUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSData *data =[NSData dataWithContentsOfURL:[NSURL URLWithString:strUrl]];
    NSError* error;
    if (data) {
        NSDictionary* json = [NSJSONSerialization
                              JSONObjectWithData:data //1
                              options:kNilOptions
                              error:&error];
        NSArray *arrRouts=[json objectForKey:@"routes"];
        if ([arrRouts isKindOfClass:[NSArray class]]&&arrRouts.count==0) {
            [self zoomToFitMapAnnotations:self.mapView];
            return;
        }

        CLLocationCoordinate2D coordinates[2];
        coordinates[0].latitude = [[CommonUtils checkNullString:[AppDelegate getAppDelegate].strLatitude] doubleValue];Current loaction latitude.
        coordinates[0].longitude = [[CommonUtils checkNullString:[AppDelegate getAppDelegate].strLongitude] doubleValue];//Current loaction longitude.
        coordinates[1].latitude = [[CommonUtils checkNullString:latitute] doubleValue];
        coordinates[1].longitude = [[CommonUtils checkNullString:longitude] doubleValue];

        if (CLLocationCoordinate2DIsValid(coordinates[1]) && CLLocationCoordinate2DIsValid(coordinates[0]))
        {
            //NSLog(@"Coordinate valid");
            self.mapView.delegate=self;
            CLLocation *location1 = [[CLLocation alloc] initWithLatitude:coordinates[0].latitude longitude:coordinates[0].longitude];
            CLLocation *location2 = [[CLLocation alloc] initWithLatitude:coordinates[1].latitude longitude:coordinates[1].longitude];
            CLLocationDistance kilometers = [location1 distanceFromLocation:location2] / 1000;
            //NSLog(@"%f",kilometers);
            self.lblRideViewkilometer.text=[NSString stringWithFormat:@"%f KM",kilometers];
            // //NSLog(@"Distance i meters: %f", [location1 distanceFromLocation:location2]);
            //  self.polyline = [MKPolyline polylineWithCoordinates:coordinates count:2];
            //  [self.mapView setVisibleMapRect:[self.polyline boundingMapRect]];
            //
            //
            //            //If you want the route to be visible
            //            [self.mapView addOverlay:self.polyline];
        } else {
            //NSLog(@"Coordinate invalid");
        }



        NSArray* arrpolyline = [[[json valueForKeyPath:@"routes.legs.steps.polyline.points"] objectAtIndex:0] objectAtIndex:0]; //2
        double srcLat=[[[[json valueForKeyPath:@"routes.legs.start_location.lat"] objectAtIndex:0] objectAtIndex:0] doubleValue];
        double srcLong=[[[[json valueForKeyPath:@"routes.legs.start_location.lng"] objectAtIndex:0] objectAtIndex:0] doubleValue];
        double destLat=[[[[json valueForKeyPath:@"routes.legs.end_location.lat"] objectAtIndex:0] objectAtIndex:0] doubleValue];
        double destLong=[[[[json valueForKeyPath:@"routes.legs.end_location.lng"] objectAtIndex:0] objectAtIndex:0] doubleValue];
        CLLocationCoordinate2D sourceCordinate = CLLocationCoordinate2DMake(srcLat, srcLong);
        CLLocationCoordinate2D destCordinate = CLLocationCoordinate2DMake(destLat, destLong);

        [self addAnnotationSrcAndDestination:sourceCordinate :destCordinate andAdds:nil andDestinationAddress:DestinationAdds];


        //    NSArray *steps=[[aary objectAtIndex:0]valueForKey:@"steps"];
        //    replace lines with this may work
        polyLinesArray =[[NSMutableArray alloc]initWithCapacity:0];
        for (int i = 0; i < [arrpolyline count]; i++)
        {
            NSString* encodedPoints = [arrpolyline objectAtIndex:i] ;
            MKPolyline *route = [self polylineWithEncodedString:encodedPoints];
            [polyLinesArray addObject:route];
        }
        self.polyline = [MKPolyline polylineWithCoordinates:coordinates count:2];
        [self.mapView setVisibleMapRect:[self.polyline boundingMapRect]];
        [self.mapView addOverlays:polyLinesArray];

        self.mapView.delegate = self;
        [self zoomToFitMapAnnotations:self.mapView];


    }else{
        // [self.btnDirection setEnabled:NO];
        // [self ShowAlert:@"didn't find direction"];
    }

}-(void)addAnnotationSrcAndDestination :(CLLocationCoordinate2D )srcCord :(CLLocationCoordinate2D)destCord andAdds:(NSString*)SourceAddress andDestinationAddress:(NSString*)DestinationAdds
{
    MKPointAnnotation *sourceAnnotation = [[MKPointAnnotation alloc]init];
    destAnnotation = [[MKPointAnnotation alloc]init];
    sourceAnnotation.coordinate=srcCord;
    destAnnotation.coordinate=destCord;
    sourceAnnotation.title=SourceAddress;




    CLLocation *LocationAtual = [[CLLocation alloc] initWithLatitude:destCord.latitude longitude:destCord.longitude];
    CLGeocoder *geocoder = [[CLGeocoder alloc] init] ;
    [geocoder reverseGeocodeLocation:LocationAtual
                   completionHandler:^(NSArray *placemarks, NSError *error)
     {
         if (error){
             //NSLog(@"Geocode failed with error: %@", error);
             return;
         }
         CLPlacemark *placemark = [placemarks objectAtIndex:0];
         //NSLog(@"placemark.ISOcountryCode %@",placemark.ISOcountryCode);
         //NSLog(@"locality %@",placemark.subLocality);
         //NSLog(@"postalCode %@",placemark.postalCode);
         destAnnotation.title=[NSString stringWithFormat:@"%@ %@ ",placemark.name,placemark.locality];
         // [self.mapView.userLocation setTitle:[NSString stringWithFormat:@"%@ %@ ",placemark.name,placemark.locality]];

     }];











    // destAnnotation.title=DestinationAdds;
    //destAnnotation.title=[NSString stringWithFormat:@"%@,%@,%@",[self.dictRetailerInfo objectForKey:@"street_address1"],[self.dictRetailerInfo objectForKey:@"city"],[self.dictRetailerInfo objectForKey:@"country"]];
    // destAnnotation.title=nil;
    [self.mapView addAnnotation:sourceAnnotation];
    [self.mapView addAnnotation:destAnnotation];
}
- (MKPolyline *)polylineWithEncodedString:(NSString *)encodedString {
    const char *bytes = [encodedString UTF8String];
    NSUInteger length = [encodedString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
    NSUInteger idx = 0;

    NSUInteger count = length / 4;
    CLLocationCoordinate2D *coords = calloc(count, sizeof(CLLocationCoordinate2D));
    NSUInteger coordIdx = 0;

    float latitude = 0;
    float longitude = 0;
    while (idx < length) {
        char byte = 0;
        int res = 0;
        char shift = 0;

        do {
            byte = bytes[idx++] - 63;
            res |= (byte & 0x1F) << shift;
            shift += 5;
        } while (byte >= 0x20);

        float deltaLat = ((res & 1) ? ~(res >> 1) : (res >> 1));
        latitude += deltaLat;

        shift = 0;
        res = 0;

        do {
            byte = bytes[idx++] - 0x3F;
            res |= (byte & 0x1F) << shift;
            shift += 5;
        } while (byte >= 0x20);

        float deltaLon = ((res & 1) ? ~(res >> 1) : (res >> 1));
        longitude += deltaLon;

        float finalLat = latitude * 1E-5;
        float finalLon = longitude * 1E-5;

        CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(finalLat, finalLon);
        coords[coordIdx++] = coord;

        if (coordIdx == count) {
            NSUInteger newCount = count + 10;
            coords = realloc(coords, newCount * sizeof(CLLocationCoordinate2D));
            count = newCount;
        }
    }
    MKPolyline *polyline = [MKPolyline polylineWithCoordinates:coords count:coordIdx];
    free(coords);

    return polyline;
}
-(void)zoomToFitMapAnnotations:(MKMapView*)aMapView
{
    if([aMapView.annotations count] == 0)
        return;

    CLLocationCoordinate2D topLeftCoord;
    topLeftCoord.latitude = -90;
    topLeftCoord.longitude = 180;

    CLLocationCoordinate2D bottomRightCoord;
    bottomRightCoord.latitude = 90;
    bottomRightCoord.longitude = -180;

    for(MKPointAnnotation *annotation in self.mapView.annotations)
    {
        if (![[annotation class] isEqual:[MKUserLocation class]]) {
            topLeftCoord.longitude = fmin(topLeftCoord.longitude, annotation.coordinate.longitude);
            topLeftCoord.latitude = fmax(topLeftCoord.latitude, annotation.coordinate.latitude);

            bottomRightCoord.longitude = fmax(bottomRightCoord.longitude, annotation.coordinate.longitude);
            bottomRightCoord.latitude = fmin(bottomRightCoord.latitude, annotation.coordinate.latitude);
        }
    }

    MKCoordinateRegion region;
    region.center.latitude = topLeftCoord.latitude - (topLeftCoord.latitude - bottomRightCoord.latitude) * 0.5;
    region.center.longitude = topLeftCoord.longitude + (bottomRightCoord.longitude - topLeftCoord.longitude) * 0.5;
    region.span.latitudeDelta = fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 1.1; // Add a little extra space on the sides
    region.span.longitudeDelta = fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.1; // Add a little extra space on the sides

    region = [aMapView regionThatFits:region];

    [self.mapView setRegion:region animated:YES];
    mapZoom=YES;
}
//- (void)mapView:(MKMapView *)mv didAddAnnotationViews:(NSArray *)views
//{
//    MKMapRect zoomRect = MKMapRectNull;
//    for (id <MKAnnotation> annotation in mv.annotations)
//    {
//        MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
//        MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);
//        zoomRect = MKMapRectUnion(zoomRect, pointRect);
//    }
//    [mv setVisibleMapRect:zoomRect animated:YES];
//}
- (void)moveMapToLocation:(CLLocation*)tmpLocation {
    CLLocationDistance visibleDistance = 1000; // 1 kilometers
    MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(tmpLocation.coordinate, visibleDistance, visibleDistance);
    MKCoordinateRegion adjustedRegion = [self.mapView regionThatFits:viewRegion];
    [self.mapView setRegion:adjustedRegion animated:YES];
}

Solution 2:[2]

var arrayPolyline = [GMSPolyline]()
var selectedRought:String!

func LoadMapRoute1()
{
    let strUrl:String = "https://maps.googleapis.com/maps/api/directions/json?sensor=false&mode=driving&alternatives=true&origin=\(self.source.latitude),\(self.source.longitude)&destination=\(self.destination.latitude),\(self.destination.longitude)"

    let escapedString = strUrl.replacingOccurrences(of: " ", with: "")

    let url = URL(string: escapedString)
    URLSession.shared.dataTask(with: url!, completionHandler:
        {
        (data, response, error) in
        if(error != nil)
        {
            print("error")
        }
        else
        {
            do{
                let json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! [String : AnyObject]
                let arrRouts = json["routes"] as! NSArray

                for  polyline in self.arrayPolyline
                {
                    polyline.map = nil;
                }

                self.arrayPolyline.removeAll()

                let pathForRought:GMSMutablePath = GMSMutablePath()

                if (arrRouts.count == 0)
                {
                    let distance:CLLocationDistance = CLLocation.init(latitude: self.source.latitude, longitude: self.source.longitude).distance(from: CLLocation.init(latitude: self.destination.latitude, longitude: self.destination.longitude))

                    pathForRought.add(self.source)
                    pathForRought.add(self.destination)

                    let polyline = GMSPolyline.init(path: pathForRought)
                    polyline.strokeWidth = 5
                    polyline.strokeColor = UIColor.blue
                    polyline.isTappable = true

                    self.arrayPolyline.append(polyline)

                    if (distance > 8000000)
                    {
                        polyline.geodesic = false
                    }
                    else
                    {
                        polyline.geodesic = true
                    }

                    polyline.map = self.mapView;
                }
                else
                {
                    for (index, element) in arrRouts.enumerated()
                    {
                        let dicData:NSDictionary = element as! NSDictionary

                        let routeOverviewPolyline = dicData["overview_polyline"] as! NSDictionary

                        let path =  GMSPath.init(fromEncodedPath: routeOverviewPolyline["points"] as! String)

                        let polyline = GMSPolyline.init(path: path)

                        polyline.isTappable = true

                        self.arrayPolyline.append(polyline)

                        polyline.strokeWidth = 5

                        if index == 0
                        {
                            polyline.strokeColor = UIColor.blue;
                        }
                        else
                        {
                            polyline.strokeColor = UIColor.darkGray;
                        }

                        polyline.geodesic = true;
                    }

                    for po in self.arrayPolyline.reversed()
                    {
                        po.map = self.mapView;
                    }
                }

                DispatchQueue.main.asyncAfter(deadline: .now() + 0.5)
                {
                    let bounds:GMSCoordinateBounds = GMSCoordinateBounds.init(path: GMSPath.init(fromEncodedPath: self.selectedRought)!)

                    self.mapView.animate(with: GMSCameraUpdate.fit(bounds))
                }
            }
            catch let error as NSError
            {
                print("error:\(error)")
            }
        }
    }).resume()
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Deepak Saki
Solution 2 Jignesh Mayani