Geofencing in iOS When App is closed / Killed

2019-02-20 00:03发布

I am working on Geofencing and I want to trigger "didEnterRegion" and "didExitRegion" it is working when the app is in foreground or in background state. But I want to trigger it when the app is inactive state also. My code is follows:

GeofencingClass.h

#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>

#define IS_OS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)

@interface GeofencingClass : NSObject <UIWebViewDelegate,UIGestureRecognizerDelegate,CLLocationManagerDelegate> {

CLLocationManager *locationManager;
   NSMutableArray *geofences;
}
@property (strong, nonatomic) NSMutableArray *geofences;
@property (nonatomic,retain)CLLocationManager *locationManager;
+(void)GeofencingCoordinatesFromAPI;
+(void)StartGeoFencingWithGeoData:(NSMutableArray *)GeoDataArray;
@end

GeofencingClass.m

    #import "GeofencingClass.h"

    @implementation GeofencingClass
    @synthesize locationManager,geofences;

    +(void)GeofencingCoordinatesFromAPI {

        NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];

        NSInteger Parameter1 = [userDefaults integerForKey:@"Parameter1"];
        NSString* Parameter2 = [userDefaults objectForKey:@"Parameter2"];
        NSString* secretAgent = [userDefaults objectForKey:@"nv_secretAgent"];

        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_async(queue, ^{
            NSError *error = nil;
            NSString *urlstring = [NSString stringWithFormat:@"https://geofencingapiurl.com?parm1=%ld&parm2=%@&device=ios", (long)Parameter1, Parameter2];
            urlstring = [urlstring stringByReplacingOccurrencesOfString:@"(null)" withString:@""];
        urlstring= [urlstring stringByAddingPercentEscapesUsingEncoding:NSISOLatin1StringEncoding];
            NSURL *url = [NSURL URLWithString:urlstring];
            NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:url];
            [request setValue:secretAgent forHTTPHeaderField:@"User-Agent"];
            NSURLResponse* response = nil;
            NSData* jsonData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
            if(!error) {
                //NSData *jsonData = [json dataUsingEncoding:NSASCIIStringEncoding];
                NSMutableDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&error];

                if ([jsonDict objectForKey:@"Authentication"] && [@"success" isEqualToString:[jsonDict objectForKey:@"Authentication"]]) {
                    geofences = [[jsonDict valueForKey:@"geodata"] mutableCopy];




                    dispatch_async(dispatch_get_main_queue(), ^{

                    [self StartGeoFencingWithGeoData:geofences];
                    });





                } else {
                    NSLog(@"Invalid authentication");
                }
            }
        });
    }

    +(void)StartGeoFencingWithGeoData:(NSMutableArray *)GeoDataArray {

        locationManager = [[CLLocationManager alloc]init];
       // NSLog(@"GeoDataArray = %@",GeoDataArray);
        if(IS_OS_8_OR_LATER) {
            [locationManager requestWhenInUseAuthorization];
            [locationManager requestAlwaysAuthorization];
        }

        locationManager.delegate = self;
        [locationManager startUpdatingLocation];
        locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
        locationManager.distanceFilter = kCLLocationAccuracyBest;
        NSLog(@"latitude: %f   longitude: %f",locationManager.location.coordinate.latitude,locationManager.location.coordinate.longitude);
        NSLog(@"speed: %f  altitude: %f",locationManager.location.speed,locationManager.location.altitude);

        for (int i = 0; i < [GeoDataArray count]; i++) {
            CLLocationDegrees geo_latitude = [[[GeoDataArray objectAtIndex:i] valueForKey:@"geo_lattitude"] floatValue];
            CLLocationDegrees geo_longitude = [[[GeoDataArray objectAtIndex:i] valueForKey:@"geo_longitude"] floatValue];

            float Radius  = [[[GeoDataArray objectAtIndex:i] valueForKey:@"geo_radius"] floatValue];
            CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(geo_latitude, geo_longitude);

            CLCircularRegion *region = [[CLCircularRegion alloc]initWithCenter:coordinate radius:Radius identifier:[[GeoDataArray objectAtIndex:i] valueForKey:@"geo_id"]];
            [locationManager startMonitoringForRegion:region];
        }
    }
    -(void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {

        NSLog(@"Region Monitoring has been started%@",region.identifier);
        [locationManager performSelector:@selector(requestStateForRegion:) withObject:region afterDelay:2];
    }
    -(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
        NSLog(@"Entered in some Region %@",region.identifier);
        for (int i= 0; i <[GeoData count]; i++) {

            NSInteger geo_id =[[[GeoData objectAtIndex:i] valueForKey:@"geo_id"] integerValue];

            if ([region.identifier integerValue] == geo_id) {
                NSInteger geo_action = [[[GeoData objectAtIndex:i] valueForKey:@"geo_action"] integerValue];
                if (geo_action == 0) {
        UILocalNotification *localNotification = [[UILocalNotification alloc] init];
        localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:2];
      localNotification.alertBody = @"You are now Entered in a region";
        localNotification.timeZone = [NSTimeZone defaultTimeZone];
        localNotification.soundName = UILocalNotificationDefaultSoundName;
        NSMutableDictionary *userData = [[GeoData objectAtIndex:i] mutableCopy];
        localNotification.userInfo = userData;
     [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];  
                }
            }
        }
    }

    -(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
        NSLog(@"Exit from some Region %@",region.identifier);
        for (int i= 0; i <[GeoData count]; i++) {

            NSInteger geo_id =[[[GeoData objectAtIndex:i] valueForKey:@"geo_id"] integerValue];

            if ([region.identifier integerValue] == geo_id) {
                NSInteger geo_action = [[[GeoData objectAtIndex:i] valueForKey:@"geo_action"] integerValue];
                if (geo_action == 1) {
        UILocalNotification *localNotification = [[UILocalNotification alloc] init];
        localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:2];
      localNotification.alertBody = @"You are now Exit from region";
        localNotification.timeZone = [NSTimeZone defaultTimeZone];
        localNotification.soundName = UILocalNotificationDefaultSoundName;
        NSMutableDictionary *userData = [[GeoData objectAtIndex:i] mutableCopy];
        localNotification.userInfo = userData;
     [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
                }
            }
        }
    }
    -(void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region {

        if (state == CLRegionStateInside){

            [self AlreadyInsideRegion:region];

        } else if (state == CLRegionStateOutside){

            [self NotInRegion:region];

        } else if (state == CLRegionStateUnknown){
            NSLog(@"Unknown state for geofence: %@", region);
            return;
        }
    }
    - (void)AlreadyInsideRegion:(CLRegion *)region {
        NSLog(@"Already in a Region");
    }

    - (void)NotInRegion:(CLRegion *)region {
        NSLog(@"You are Outside from a Region");

    }
    @end

MYAppDelegate.h

#import <UIKit/UIKit.h>

@interface MYAppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end

MyAppDelegate.m

#import "MYAppDelegate.h"
#import "GeofencingClass.h"

@interface MYAppDelegate ()
@end

@implementation MYAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) {
        [GeofencingClass GeofencingCoordinatesFromAPI];
    }
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application {
}

- (void)applicationDidEnterBackground:(UIApplication *)application {

}

- (void)applicationWillEnterForeground:(UIApplication *)application {

}

- (void)applicationDidBecomeActive:(UIApplication *)application {

[GeofencingClass GeofencingCoordinatesFromAPI];
}

- (void)applicationWillTerminate:(UIApplication *)application {

}

-(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {

/// Handled Deeplinking here 
    return YES;
}
-(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
 /// Registered Push Notification Here and it is working fine
}
-(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
    NSLog(@"Error:%@",error);
}
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    /// Handled received Push Notification Here and it is working fine
}

-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
    ///Handled received local push Notification Here and it is working fine
}

The above code is working fine if the app is in background or foreground but if i double tap on Home Button and close the app from task then geofencing not working can anybody help me to achieve this goal.

Note: I am using XCode 7.3.1 and iOS 9.3 while I am testing this on iPhone 5s.

Thanks in advance !!!!!

1条回答
淡お忘
2楼-- · 2019-02-20 00:54

Sorry but is a bit different: (ADC SITE)

If you leave the significant-change location service running and your iOS app is subsequently suspended or terminated, the service automatically wakes up your app when new location data arrives. At wake-up time, the app is put into the background and you are given a small amount of time (around 10 seconds) to manually restart location services and process the location data. (You must manually restart location services in the background before any pending location updates can be delivered, as described in Knowing When to Start Location Services.)

So iOS will awake your app BUT you must: 1) instantiate a NEW CLLocationManager 2) wait 'till first call back to use geoloc

notes ADC states, you will be running in background, so or example use local notification if You need the user put it in foreground.

查看更多
登录 后发表回答