Report a driver's current location to a server

In this example, we are continuously monitoring the driver's location as they follow turn-by-turn directions. We report the location to the server at regular intervals. Specifically, any time the driver moves more than 100 meters from the last report, or when 60 seconds has elapsed since the last report.

You will need to provide your own server for this. The data in our example is sent to the server with a PUT request in JSON format. Modify the URL and other aspects of the URLRequest as necessary to suit your server.

Before you do this:

In order to see results, first make sure you have turn-by-turn navigation up and running in your app. If you haven't done this yet, here's how .

In order to see a successful connection, you will also need a server that can accept the data. We provide a reference server that you can use for testing this.

After you present the turn-by-turn UI, you can register to be notified when the driver's location changes. (If you don't want to leave your desk to test this, it also works with our driving simulator , of course!)

NotificationCenter.default.addObserver(forName: NSNotification.Name.TGTelemetryCurrentPointChange, object: nil, queue: nil) { (notification) in
    guard let newPoint = notification.userInfo?[TGTelemetryUserInfo.toPoint] as? TGPoint else {
        return
    }

    self.reportLocation(newPoint)
}
[NSNotificationCenter.defaultCenter addObserverForName:TGTelemetryCurrentPointChangeNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull notification) {
    TGPoint *newPoint = notification.userInfo[TGTelemetryUserInfoToPoint];
    if (newPoint == nil) {
        return;
    }
    
    [self reportLocation:newPoint];
}];

Once we've done that, let's write a method to report that data to our server.

// You can change these configuration values to suit your needs.
let reportLocationPointTrigger: CLLocationDistance = 100
let reportLocationTimeTrigger: TimeInterval = 60
let reportLocationURL = URL(string: "http://localhost:3200/drivers/current_location")!
let reportLocationMethod = "PUT"

// Keep track of when and what we last reported.
var lastReportedLocationPoint: TGPoint?
var lastReportedLocationTime: Date?

func reportLocation(_ point: TGPoint) {
    // We should only continue if we haven't reported yet, or if one of our triggers has been satisfied.
    guard (lastReportedLocationPoint == nil ||
        lastReportedLocationTime == nil ||
        TGLocationCoordinateDistanceFromCoordinate(lastReportedLocationPoint!.coordinate, point.coordinate) > reportLocationPointTrigger ||
        Date().timeIntervalSince(lastReportedLocationTime!) > reportLocationTimeTrigger) else {
        
        return
    }
    
    // Collect the data we want to send
    let requestData = [
        "latitude": point.coordinate.latitude,
        "longitude": point.coordinate.longitude,
    ]
    
    // Configure the request
    var request = URLRequest(url: reportLocationURL)
    request.httpMethod = reportLocationMethod
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    
    // Optional: send an ID for this session, so the server can tell different drivers apart
    //request.setValue(temporaryID, forHTTPHeaderField: "X-Temporary-ID")
    
    request.httpBody = try! JSONEncoder().encode(requestData)
    
    // Send the request
    let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
        if let error = error {
            NSLog("Error reporting current location: \(error)")
            
        } else {
            // Optionally, you can do something with the successful response here.
        }
    }
    task.resume()
    
    // Remember that we did this
    lastReportedLocationPoint = point
    lastReportedLocationTime = Date()
}
// Put these inside your @interface
// Keep track of when and what we last reported.
@property (nonatomic, nullable) TGPoint *lastReportedLocationPoint;
@property (nonatomic, nullable) NSDate *lastReportedLocationTime;

// Put these inside your @implementation
// You can change these configuration values to suit your needs.
static CLLocationDistance const reportLocationPointTrigger = 100;
static NSTimeInterval const reportLocationTimeTrigger = 60;
static NSString *const reportLocationURL = @"http://localhost:3200/drivers/current_location";
static NSString *const reportLocationMethod = @"PUT";

- (void)reportLocation:(nonnull TGPoint *)point {
    // We should only continue if we haven't reported yet, or if one of our triggers has been satisfied.
    if (self.lastReportedLocationPoint != nil &&
        self.lastReportedLocationTime != nil &&
        TGLocationCoordinateDistanceFromCoordinate(self.lastReportedLocationPoint.coordinate, point.coordinate) <= reportLocationPointTrigger &&
        [NSDate.date timeIntervalSinceDate:self.lastReportedLocationTime] <= reportLocationTimeTrigger) {
        
        return;
    }
    
    // Collect the data we want to send
    NSDictionary *requestData = @{
        @"latitude": @(point.coordinate.latitude),
        @"longitude": @(point.coordinate.longitude),
    };
    
    // Configure the request
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:reportLocationURL]];
    request.HTTPMethod = reportLocationMethod;
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    
    // Optional: send an ID for this session, so the server can tell different drivers apart
    //[request setValue:self.temporaryID forHTTPHeaderField:@"X-Temporary-ID"];
    
    NSError *error = nil;
    NSData *encodedData = [NSJSONSerialization dataWithJSONObject:requestData options:0 error:&error];
    if (encodedData != nil) {
        request.HTTPBody = encodedData;
        
    } else {
        @throw error;
    }
    
    // Send the request
    NSURLSessionDataTask *task = [NSURLSession.sharedSession dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        if (error != nil) {
            NSLog(@"Error reporting current location: %@", error.userInfo);
            
        } else {
            // Optionally, you can do something with the successful response here.
        }
    }];
    [task resume];
    
    // Remember that we did this
    self.lastReportedLocationPoint = point;
    self.lastReportedLocationTime = NSDate.date;
}
Check out the iOS Reference App to see this example in action.

Look for example 401 in the app.