2

I want to make an iOS7 devise to upload its locations to server from background using 3G/4G/LTE(NOT WiFi) frequently like less than every 5 to 10 mins or when it's location changed.

What I already have tried is like these:

1.Background Fetch

- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler is called so irregularly and not controllable.

2.Remote Notification(NOT silent push)

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler is called only in WiFi connection.

3.CLLocationManager

I put uploader in - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation but it is called when on WiFi only.

I want to realize an application like "Find Your Friends" which is the Apple native application in iOS8. Are there any ideas?

Thank you for your help.

UPDATE

I tried NSURLSession upload triggered by CLLocationManager didUpdateToLocation like below, but still it uploads only on WiFi.

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{

[[NSUserDefaults standardUserDefaults] setFloat:newLocation.coordinate.latitude forKey:@"lat"];
[[NSUserDefaults standardUserDefaults] setFloat:newLocation.coordinate.longitude forKey:@"lon"];
[[NSUserDefaults standardUserDefaults] synchronize];

[self update];

}

- (void)update
{

NSURL *url = [NSURL URLWithString:@"http://.../updater.php"];
NSString *identifier = [NSDate date].description;
NSURLSessionConfiguration *configration = [NSURLSessionConfiguration backgroundSessionConfiguration:identifier];
configuration.networkServiceType = NSURLNetworkServiceTypeBackground;
configuration.discretionary = NO;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"PUT";
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
                                                      delegate:self
                                                 delegateQueue:[NSOperationQueue mainQueue]];

float lat = [[NSUserDefaults standardUserDefaults] floatForKey:@"lat"];
float lon = [[NSUserDefaults standardUserDefaults] floatForKey:@"lon"];

NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
                            [NSNumber numberWithFloat:lat], @"lat",
                            [NSNumber numberWithFloat:lon], @"lon", nil];

NSData *data = [NSJSONSerialization dataWithJSONObject:dictionary options:NSJSONWritingPrettyPrinted error:nil];

NSString *path = [[self applicationDocumentsDirectory].path stringByAppendingPathComponent:@"json.data"];
[data writeToFile:path atomically:YES];

NSURLSessionUploadTask *task = [session uploadTaskWithRequest:request fromFile:[NSURL fileURLWithPath:path]];

[task resume];

}

- (NSURL *)applicationDocumentsDirectory
{

// The directory the application uses to store the Core Data store file. This code uses a directory named "jp.skyElements.NNZ" in the application's documents directory.
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];

}

1 Answers1

0

You have background location updates mode which allows your app to get notified about location changes. Read more on this in Background Modes section in Xcode documentation for iOS.

Now I never tried to do any network requests during background location updates but what I would try is the following:

NSURLSession with background configuration. POST to server and delegate all burden of this to iOS itself. QoS, network throttling, power efficiency and other benefits come out of this.

pronebird
  • 12,068
  • 5
  • 54
  • 82
  • Thnaks, Andy. I tried what you told me, but still works in only WiFi. Please refer what I re-edited on question section. Please tell me how can I delegate all burden to iOS? What and Where should I delegate to? – skyElements Dec 14 '14 at 23:31
  • @skyElements your code looks good to me. You would probably like to set parameters on network configuration such as `networkServiceType` or maybe play with `discretionary` if you really want to force request ASAP. The other thing you could do is to setup a delegate for background `NSURLSession` and see if you get errors for background uploads or successes. Even if your app gets suspended it will start your app in background and call delegate methods when some network activity happens. – pronebird Dec 15 '14 at 00:00
  • When debugging background transfers, you could simply use NSLog in app, hook up device console and monitor. From my experience, on my device, background upload could even drop speed to 20Kb/s and keep it going this way for hours. I used to upload 300M files to S3. Background transfers seem to be pretty restrictive. Also, check iOS settings and make sure you allow cellular use for your app. – pronebird Dec 15 '14 at 00:05
  • I newly put `configuration.networkServiceType = NSURLNetworkServiceTypeBackground;` and `configuration.discretionary = NO;` but nothing changed. I modified NSURLSession with delegate:self and monitored `- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error` but never called when it failed on 4G/LTE connection. – skyElements Dec 15 '14 at 02:36
  • I hope you restore your session in app delegate `handleEventsForBackgroundURLSession`. Example was at the end of article http://www.objc.io/issue-5/multitasking.html – pronebird Dec 15 '14 at 10:07