|
- #import "LocationPlugin.h"
-
- #ifdef COCOAPODS
- @import CoreLocation;
- #else
- #import <CoreLocation/CoreLocation.h>
- #endif
-
- @interface LocationPlugin() <FlutterStreamHandler, CLLocationManagerDelegate>
- @property (strong, nonatomic) CLLocationManager *clLocationManager;
- @property (copy, nonatomic) FlutterResult flutterResult;
- @property (assign, nonatomic) BOOL locationWanted;
- @property (assign, nonatomic) BOOL permissionWanted;
-
- @property (copy, nonatomic) FlutterEventSink flutterEventSink;
- @property (assign, nonatomic) BOOL flutterListening;
- @property (assign, nonatomic) BOOL hasInit;
- @end
-
- @implementation LocationPlugin
-
- +(void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
- FlutterMethodChannel *channel =
- [FlutterMethodChannel methodChannelWithName:@"lyokone/location"
- binaryMessenger:registrar.messenger];
- FlutterEventChannel *stream =
- [FlutterEventChannel eventChannelWithName:@"lyokone/locationstream"
- binaryMessenger:registrar.messenger];
-
- LocationPlugin *instance = [[LocationPlugin alloc] init];
- [registrar addMethodCallDelegate:instance channel:channel];
- [stream setStreamHandler:instance];
- }
-
- -(instancetype)init {
- self = [super init];
-
- if (self) {
- self.locationWanted = NO;
- self.permissionWanted = NO;
- self.flutterListening = NO;
- self.hasInit = NO;
- }
- return self;
- }
-
- -(void)initLocation {
- if (!(self.hasInit)) {
- self.hasInit = YES;
-
- if ([CLLocationManager locationServicesEnabled]) {
- self.clLocationManager = [[CLLocationManager alloc] init];
- self.clLocationManager.delegate = self;
- self.clLocationManager.desiredAccuracy = kCLLocationAccuracyBest;
- }
- }
- }
-
- -(void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
- [self initLocation];
- if ([call.method isEqualToString:@"changeSettings"]) {
- if ([CLLocationManager locationServicesEnabled]) {
- NSDictionary *dictionary = @{
- @"0" : @(kCLLocationAccuracyKilometer),
- @"1" : @(kCLLocationAccuracyHundredMeters),
- @"2" : @(kCLLocationAccuracyNearestTenMeters),
- @"3" : @(kCLLocationAccuracyBest),
- @"4" : @(kCLLocationAccuracyBestForNavigation)
- };
-
- self.clLocationManager.desiredAccuracy =
- [dictionary[call.arguments[@"accuracy"]] doubleValue];
- double distanceFilter = [call.arguments[@"distanceFilter"] doubleValue];
- if (distanceFilter == 0){
- distanceFilter = kCLDistanceFilterNone;
- }
- self.clLocationManager.distanceFilter = distanceFilter;
- result(@1);
- }
- } else if ([call.method isEqualToString:@"getLocation"]) {
- if (![CLLocationManager locationServicesEnabled]) {
- result([FlutterError errorWithCode:@"SERVICE_STATUS_DISABLED" message:@"Failed to get location. Location services disabled" details:nil]);
- return;
- }
- if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) {
- // Location services are requested but user has denied
- NSString *message = @"The user explicitly denied the use of location services for this "
- "app or location services are currently disabled in Settings.";
- result([FlutterError errorWithCode:@"PERMISSION_DENIED"
- message:message
- details:nil]);
- return;
- }
-
- self.flutterResult = result;
- self.locationWanted = YES;
-
- if ([self isPermissionGranted]) {
- [self.clLocationManager startUpdatingLocation];
- } else {
- [self requestPermission];
- if ([self isPermissionGranted]) {
- [self.clLocationManager startUpdatingLocation];
- }
- }
- } else if ([call.method isEqualToString:@"hasPermission"]) {
- if ([self isPermissionGranted]) {
- result(@1);
- } else {
- result(@0);
- }
- } else if ([call.method isEqualToString:@"requestPermission"]) {
- if ([self isPermissionGranted]) {
- result(@1);
- } else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
- self.flutterResult = result;
- self.permissionWanted = YES;
- [self requestPermission];
- } else {
- result(@2);
- }
- } else if ([call.method isEqualToString:@"serviceEnabled"]) {
- if ([CLLocationManager locationServicesEnabled]) {
- result(@1);
- } else {
- result(@0);
- }
- } else if ([call.method isEqualToString:@"requestService"]) {
- if ([CLLocationManager locationServicesEnabled]) {
- result(@1);
- } else {
- #if TARGET_OS_OSX
- NSAlert *alert = [[NSAlert alloc] init];
- [alert setMessageText:@"Location is Disabled"];
- [alert setInformativeText:@"To use location, go to your System Preferences > Security & Privacy > Privacy > Location Services."];
- [alert addButtonWithTitle:@"Open"];
- [alert addButtonWithTitle:@"Cancel"];
- [alert beginSheetModalForWindow:NSApplication.sharedApplication.mainWindow
- completionHandler:^(NSModalResponse returnCode) {
- if (returnCode == NSAlertFirstButtonReturn) {
- NSString *urlString = @"x-apple.systempreferences:com.apple.preference.security?Privacy_LocationServices";
- [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:urlString]];
- } else {
- NSLog(@"Cancel");
- }
- }];
- #else
- UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Location is Disabled"
- message:@"To use location, go to your Settings App > Privacy > Location Services."
- delegate:self
- cancelButtonTitle:@"Cancel"
- otherButtonTitles:nil];
- [alert show];
- #endif
- result(@0);
- }
- } else {
- result(FlutterMethodNotImplemented);
- }
- }
-
-
- -(void) requestPermission {
- #if TARGET_OS_OSX
- if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"] != nil) {
- if (@available(macOS 10.15, *)) {
- [self.clLocationManager requestAlwaysAuthorization];
- }
- }
- #else
- if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"] != nil) {
- [self.clLocationManager requestWhenInUseAuthorization];
- }
- else if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"] != nil) {
- [self.clLocationManager requestAlwaysAuthorization];
- }
- #endif
- else {
- [NSException raise:NSInternalInconsistencyException format:
- @"To use location in iOS8 and above you need to define either "
- "NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription in the app "
- "bundle's Info.plist file"];
- }
- }
-
- -(BOOL) isPermissionGranted {
- BOOL isPermissionGranted = NO;
- CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
-
- #if TARGET_OS_OSX
- if (status == kCLAuthorizationStatusAuthorized) {
- // Location services are available
- isPermissionGranted = YES;
- } else if (@available(macOS 10.12, *)) {
- if (status == kCLAuthorizationStatusAuthorizedAlways) {
- // Location services are available
- isPermissionGranted = YES;
- }
- }
- #else //if TARGET_OS_IOS
- if (status == kCLAuthorizationStatusAuthorizedWhenInUse ||
- status == kCLAuthorizationStatusAuthorizedAlways) {
- // Location services are available
- isPermissionGranted = YES;
- }
- #endif
- else if (status == kCLAuthorizationStatusDenied ||
- status == kCLAuthorizationStatusRestricted) {
- // Location services are requested but user has denied / the app is restricted from
- // getting location
- isPermissionGranted = NO;
- } else if (status == kCLAuthorizationStatusNotDetermined) {
- // Location services never requested / the user still haven't decide
- isPermissionGranted = NO;
- } else {
- isPermissionGranted = NO;
- }
-
- return isPermissionGranted;
- }
-
- -(FlutterError*)onListenWithArguments:(id)arguments eventSink:(FlutterEventSink)events {
- self.flutterEventSink = events;
- self.flutterListening = YES;
-
- if ([self isPermissionGranted]) {
- [self.clLocationManager startUpdatingLocation];
- } else {
- [self requestPermission];
- }
-
- return nil;
- }
-
- -(FlutterError*)onCancelWithArguments:(id)arguments {
- self.flutterListening = NO;
- [self.clLocationManager stopUpdatingLocation];
- return nil;
- }
-
- #pragma mark - CLLocationManagerDelegate Methods
-
- -(void)locationManager:(CLLocationManager*)manager
- didUpdateLocations:(NSArray<CLLocation*>*)locations {
- CLLocation *location = locations.firstObject;
- NSTimeInterval timeInSeconds = [location.timestamp timeIntervalSince1970];
- NSDictionary<NSString*,NSNumber*>* coordinatesDict =
- @{
- @"latitude": @(location.coordinate.latitude),
- @"longitude": @(location.coordinate.longitude),
- @"accuracy": @(location.horizontalAccuracy),
- @"altitude": @(location.altitude),
- @"speed": @(location.speed),
- @"speed_accuracy": @0.0,
- @"heading": @(location.course),
- @"time": @(((double) timeInSeconds) * 1000.0) // in milliseconds since the epoch
- };
-
- if (self.locationWanted) {
- self.locationWanted = NO;
- self.flutterResult(coordinatesDict);
- }
- if (self.flutterListening) {
- self.flutterEventSink(coordinatesDict);
- } else {
- [self.clLocationManager stopUpdatingLocation];
- }
- }
-
- - (void)locationManager:(CLLocationManager *)manager
- didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
- if (status == kCLAuthorizationStatusDenied) {
- // The user denied authorization
- NSLog(@"User denied permissions");
- if (self.permissionWanted) {
- self.permissionWanted = NO;
- self.flutterResult(@0);
- }
- }
- #if TARGET_OS_OSX
- else if (status == kCLAuthorizationStatusAuthorized) {
- NSLog(@"User granted permissions");
- if (self.permissionWanted) {
- self.permissionWanted = NO;
- self.flutterResult(@1);
- }
-
- if (self.locationWanted || self.flutterListening) {
- [self.clLocationManager startUpdatingLocation];
- }
- } else if (@available(macOS 10.12, *)) {
- if (status == kCLAuthorizationStatusAuthorizedAlways) {
- NSLog(@"User granted permissions");
- if (self.permissionWanted) {
- self.permissionWanted = NO;
- self.flutterResult(@1);
- }
-
- if (self.locationWanted || self.flutterListening) {
- [self.clLocationManager startUpdatingLocation];
- }
- }
- }
- #else //if TARGET_OS_IOS
- else if (status == kCLAuthorizationStatusAuthorizedWhenInUse ||
- status == kCLAuthorizationStatusAuthorizedAlways) {
- NSLog(@"User granted permissions");
- if (self.permissionWanted) {
- self.permissionWanted = NO;
- self.flutterResult(@1);
- }
-
- if (self.locationWanted || self.flutterListening) {
- [self.clLocationManager startUpdatingLocation];
- }
- }
- #endif
- }
-
-
- @end
|