iOS 使用 CoreLocation 进行地理围栏
iOS Geofencing with CoreLocation
我想知道用户何时在我家附近。
我正在使用 CoreLocation,并且希望始终知道用户是否在我家附近(大约 100m),即使应用已关闭。
为此,我在我的代码中成功地知道用户是否在 100 米左右(CLRegionStateInside
)。 DidEnterRegion
和 DidExitRegion
也可以正常工作。我正在使用 kCLAuthorizationStatusAuthorizedAlways
来本地化用户。
我想节省电池寿命,所以我添加了 self.locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
以在用户移动 3 公里后更新位置。
告诉我如何才能节省更多电池寿命,以及如何在应用程序处于 background/closed 时更新位置(也许我必须更改我的 AppDelegate 中的某些内容)?
我想知道我的代码是否能满足我的需要?
这是我的代码:
#import "ViewController.h"
@import UserNotifications;
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
// Request Notification
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert)
completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (!error) {
NSLog(@"request authorization succeeded!");
}
}];
}
- (void)setUpGeofences {
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(49.451096,
1.095425);
CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:center
radius:100.0
identifier:@"Home"];
[self.locationManager startMonitoringForRegion:region];
self.locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
self.locationManager.allowsBackgroundLocationUpdates = YES;
}
- (void)showSorryAlert {
UIAlertController *alert = [UIAlertController
alertControllerWithTitle:@"Info"
message:@"You are using UIAlertController"
preferredStyle:UIAlertControllerStyleAlert];
[self presentViewController:alert animated:YES completion:nil];
}
- (void)locationManager:(CLLocationManager *)manager
didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
switch (status) {
case kCLAuthorizationStatusNotDetermined:
[self.locationManager requestAlwaysAuthorization];
break;
case kCLAuthorizationStatusAuthorizedWhenInUse:
[self.locationManager startUpdatingLocation];
[self setUpGeofences];
break;
case kCLAuthorizationStatusAuthorizedAlways:
[self.locationManager startUpdatingLocation];
[self setUpGeofences];
break;
case kCLAuthorizationStatusRestricted:
// restricted by e.g. parental controls. User can't enable Location Services
break;
case kCLAuthorizationStatusDenied:
// user denied your app access to Location Services, but can grant access from Settings.app
break;
default:
break;
}
}
- (void)locationManager:(CLLocationManager *)manager
didEnterRegion:(CLRegion *)region {
NSLog(@"didEnter : %@", region);
[self displayNotif:@"Bienvenue !" withBody:@"Passez nous voir !"];
}
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
[self displayNotif:@"Au revoir !" withBody:@"A bientôt !"];
}
- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
NSLog(@"Start monitoring for region: %@", region.identifier);
[self.locationManager requestStateForRegion:region];
}
- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error {
NSLog(@"Error: %@", error);
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
NSLog(@"NEW LOCATION");
// Stop location updates when they aren't needed anymore
[self.locationManager stopUpdatingLocation];
// Disable background location updates when they aren't needed anymore
self.locationManager.allowsBackgroundLocationUpdates = NO;
}
- (void)locationManager:(CLLocationManager *)manager
didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region {
// When regions are initialized, see if we are already within the geofence.
switch (state) {
case CLRegionStateInside: [self displayNotif:@"Bienvenue" withBody:@"Passez nous voir !"];
break;
case CLRegionStateUnknown: NSLog(@"Unknown");
case CLRegionStateOutside: NSLog(@"Outside");
default: break;
}
}
- (void)displayNotif:(NSString *)title withBody:(NSString *)body {
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
content.title = [NSString localizedUserNotificationStringForKey:title arguments:nil];
content.body = [NSString localizedUserNotificationStringForKey:body
arguments:nil];
content.sound = [UNNotificationSound defaultSound];
/// 4. update application icon badge number
content.badge = @([[UIApplication sharedApplication] applicationIconBadgeNumber] + 1);
// Deliver the notification in five seconds.
UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger
triggerWithTimeInterval:1.f repeats:NO];
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"OneSecond"
content:content trigger:trigger];
/// 3. schedule localNotification
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
if (!error) {
NSLog(@"add NotificationRequest succeeded!");
}
}];
}
@end
关于后台监控的问题,请参考苹果的文档,说明如下:
If a region boundary is crossed while an app isn’t running, that app is relaunched into the background to handle the event. Similarly, if the app is suspended when the event occurs, it’s woken up and given a short amount of time (around 10 seconds) to handle the event.
这意味着,只要您的 authorizationStatus 设置为 .authorizedAlways,其余的将自动处理。
我想知道用户何时在我家附近。 我正在使用 CoreLocation,并且希望始终知道用户是否在我家附近(大约 100m),即使应用已关闭。
为此,我在我的代码中成功地知道用户是否在 100 米左右(CLRegionStateInside
)。 DidEnterRegion
和 DidExitRegion
也可以正常工作。我正在使用 kCLAuthorizationStatusAuthorizedAlways
来本地化用户。
我想节省电池寿命,所以我添加了 self.locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
以在用户移动 3 公里后更新位置。
告诉我如何才能节省更多电池寿命,以及如何在应用程序处于 background/closed 时更新位置(也许我必须更改我的 AppDelegate 中的某些内容)?
我想知道我的代码是否能满足我的需要?
这是我的代码:
#import "ViewController.h"
@import UserNotifications;
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
// Request Notification
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert)
completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (!error) {
NSLog(@"request authorization succeeded!");
}
}];
}
- (void)setUpGeofences {
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(49.451096,
1.095425);
CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:center
radius:100.0
identifier:@"Home"];
[self.locationManager startMonitoringForRegion:region];
self.locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
self.locationManager.allowsBackgroundLocationUpdates = YES;
}
- (void)showSorryAlert {
UIAlertController *alert = [UIAlertController
alertControllerWithTitle:@"Info"
message:@"You are using UIAlertController"
preferredStyle:UIAlertControllerStyleAlert];
[self presentViewController:alert animated:YES completion:nil];
}
- (void)locationManager:(CLLocationManager *)manager
didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
switch (status) {
case kCLAuthorizationStatusNotDetermined:
[self.locationManager requestAlwaysAuthorization];
break;
case kCLAuthorizationStatusAuthorizedWhenInUse:
[self.locationManager startUpdatingLocation];
[self setUpGeofences];
break;
case kCLAuthorizationStatusAuthorizedAlways:
[self.locationManager startUpdatingLocation];
[self setUpGeofences];
break;
case kCLAuthorizationStatusRestricted:
// restricted by e.g. parental controls. User can't enable Location Services
break;
case kCLAuthorizationStatusDenied:
// user denied your app access to Location Services, but can grant access from Settings.app
break;
default:
break;
}
}
- (void)locationManager:(CLLocationManager *)manager
didEnterRegion:(CLRegion *)region {
NSLog(@"didEnter : %@", region);
[self displayNotif:@"Bienvenue !" withBody:@"Passez nous voir !"];
}
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
[self displayNotif:@"Au revoir !" withBody:@"A bientôt !"];
}
- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
NSLog(@"Start monitoring for region: %@", region.identifier);
[self.locationManager requestStateForRegion:region];
}
- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error {
NSLog(@"Error: %@", error);
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
NSLog(@"NEW LOCATION");
// Stop location updates when they aren't needed anymore
[self.locationManager stopUpdatingLocation];
// Disable background location updates when they aren't needed anymore
self.locationManager.allowsBackgroundLocationUpdates = NO;
}
- (void)locationManager:(CLLocationManager *)manager
didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region {
// When regions are initialized, see if we are already within the geofence.
switch (state) {
case CLRegionStateInside: [self displayNotif:@"Bienvenue" withBody:@"Passez nous voir !"];
break;
case CLRegionStateUnknown: NSLog(@"Unknown");
case CLRegionStateOutside: NSLog(@"Outside");
default: break;
}
}
- (void)displayNotif:(NSString *)title withBody:(NSString *)body {
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
content.title = [NSString localizedUserNotificationStringForKey:title arguments:nil];
content.body = [NSString localizedUserNotificationStringForKey:body
arguments:nil];
content.sound = [UNNotificationSound defaultSound];
/// 4. update application icon badge number
content.badge = @([[UIApplication sharedApplication] applicationIconBadgeNumber] + 1);
// Deliver the notification in five seconds.
UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger
triggerWithTimeInterval:1.f repeats:NO];
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"OneSecond"
content:content trigger:trigger];
/// 3. schedule localNotification
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
if (!error) {
NSLog(@"add NotificationRequest succeeded!");
}
}];
}
@end
关于后台监控的问题,请参考苹果的文档,说明如下:
If a region boundary is crossed while an app isn’t running, that app is relaunched into the background to handle the event. Similarly, if the app is suspended when the event occurs, it’s woken up and given a short amount of time (around 10 seconds) to handle the event.
这意味着,只要您的 authorizationStatus 设置为 .authorizedAlways,其余的将自动处理。