Web service call in background mode - iOS
Asked Answered
G

1

1

I need to call a web service in every minute and parse the data when app is in background state.

Since the APP uses location service I have enabled background mode for update Location.

I tried calling location update by using a timer background task, but it not working.

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    self.bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
    NSLog(@"ending background task");
    [[UIApplication sharedApplication] endBackgroundTask:self.bgTask];
    self.bgTask = UIBackgroundTaskInvalid;
    }];


    self.timer = [NSTimer scheduledTimerWithTimeInterval:60
                                              target:self.locationManager
                                            selector:@selector(startUpdatingLocation)
                                            userInfo:nil
                                             repeats:YES];
}

Is there any way to implement this with less battery consumption.

I referred this link I'm not getting which solution is better here.

Gog answered 17/12, 2015 at 7:12 Comment(6)
do you want to upload user current location when application is in background mode?Barrault
You can't use any NSTimer based code in the background. You would need to use "always" location mode and use the call to your delegate to check whether it is time to call the server. But, while you can use location updates as an opportunity to poll your server this is not battery or data usage friendly. The more efficient way is for your server to use push notifications when it has new data.Plication
@BandishDave Yes, I need to make web service call based on user location.Gog
@Gog : i think you have to use location manager class and call your webservice inside the delegate method instead of using timer.Barrault
@BandishDave i tried the same. but didUpdateLocations is getting called every second. So i'm checking the time duration and making the web service call in each one minute inside didUpdateLocations. And it will consume more battery.Gog
@Gog call webservice only when you will get accurate result with Location.horizontalAccuracy is greater then 0 in delegate method and take one timer which is enable with some delay like 5 to 10 min so battery will not consume.Barrault
T
0

AppDelegate.h

#import <UIKit/UIKit.h>

@interface AppDelegate : NSObject  {
    // Instance member of our background task process
    UIBackgroundTaskIdentifier bgTask; 
}

@end

AppDelegate.m

- (void)applicationDidEnterBackground:(UIApplication *)application {
    NSLog(@"Application entered background state.");

    // bgTask is instance variable
    NSAssert(self->bgTask == UIBackgroundTaskInvalid, nil);

    bgTask = [application beginBackgroundTaskWithExpirationHandler: ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            [application endBackgroundTask:self->bgTask];
            self->bgTask = UIBackgroundTaskInvalid;
        });
    }];

    dispatch_async(dispatch_get_main_queue(), ^{

        if ([application backgroundTimeRemaining] > 1.0) {
            // Start background service synchronously
            [[BackgroundCleanupService getInstance] run];
        }

        [application endBackgroundTask:self->bgTask];
        self->bgTask = UIBackgroundTaskInvalid;

    });
}

There are couple key lines in the above implementation:

The first is the line bgTask = [application beginBackgroundTaskWithExpirationHandler..., which requests additional time to run clean up tasks in the background.

The second is the final code block of the delegate method beginning with dispatch_async. It's basically checking whether there's time left to run an operation via the call [application backgroundTimeRemaining]. In this example, I'm looking to run the background service once but alternatively, you can use a loop checking on the backgroundTimeRemaining on each iteration.

The line [[BackgroundCleanupService getInstance] run] will be a call to our singleton service class, which we'll build right now.

With the app delegate ready to trigger our background task, we now need a service class that will communicate with the web server. In the following example, I'm going to a post a fictitious session key and parse a JSON encoded response. Also, I'm using two helpful libraries to make the request and deserialize the returned JSON, specifically JSONKit and ASIHttpRequest.

BackgroundCleanupService.h

#import <Foundation/Foundation.h>

@interface BackgroundCleanupService : NSObject

+ (BackgroundCleanupService *)getInstance;

- (void)run;

@end

BackgroundCleanupService.m

#import "BackgroundCleanupService.h"
#import "JSONKit.h"
#import "ASIHTTPRequest.h"

@implementation BackgroundCleanupService

/*
 * The singleton instance. To get an instance, use
 * the getInstance function.
 */
static BackgroundCleanupService *instance = NULL;

/**
 * Singleton instance.
 */

+(BackgroundCleanupService *)getInstance {
    @synchronized(self) {
        if (instance == NULL) {
            instance = [[self alloc] init];
        }
    }
    return instance;
}

- (void)run {

    NSURL* URL = [NSURL URLWithString:[NSString stringWithFormat:@"http://www.example.com/user/%@/endsession", @"SESSIONKEY"]];

    __block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:URL];

    [request setTimeOutSeconds:20]; // 20 second timeout

    // Handle request response
    [request setCompletionBlock:^{
        NSDictionary *responseDictionary = [[request responseData] objectFromJSONData];

        // Assume service succeeded if JSON key "success" returned
        if([responseDictionary  objectForKey:@"success"]) {
                NSLog(@"Session ended");
        }
        else {
             NSLog(@"Error ending session");
        }
    }];

    // Handle request failure
    [request setFailedBlock:^{
        NSError *error = [request error];
        NSLog(@"Service error: %@", error.localizedDescription);
    }];

    // Start the request synchronously since the background service
    // is already running on a background thread
    [request startSynchronous];
}

@end

may be helped

Trochilus answered 17/12, 2015 at 7:25 Comment(10)
Links to external resources are encouraged, but please add context around the link so your fellow users will have some idea what it is and why it’s there. Always quote the most relevant part of an important link, in case the target site is unreachable or goes permanently offlinePlication
@Maulik how long the bgTask will run? How many times the web service will execute?Gog
everytime run when go to backgroundTrochilus
i mean, whether it will make call to server in each one minute, even the app is in background mode.Gog
Ok..So I need to specify the background mode for Location update or background fetch?Gog
This is not working for me. I doubt this will work only for few minutes. Please see developer.radiusnetworks.com/2014/11/13/…Gog
And I want the web service to run in background the whole day.Gog
apple may reject your app...becz everytime you call webservice.first decide which time you call webserviceTrochilus
Are you sure Apple will reject the app if i'm calling web service every minute when app is in background for one day?Gog
fetch user location on when app open active stateTrochilus

© 2022 - 2024 — McMap. All rights reserved.