YHNaviteLBS.m 6.93 KB
//
//  YHNaviteLBS.m
//  YohoExplorerDemo
//
//  Created by gaoqiang xu on 4/10/15.
//  Copyright (c) 2015 gaoqiang xu. All rights reserved.
//

#import "YHNaviteLBS.h"
#import <CoreLocation/CoreLocation.h>

NSString * const YHNative_LBS = @"Native_LBS";

@interface YHNaviteLBS ()
<CLLocationManagerDelegate>

@property (strong, nonatomic) CLLocationManager *locationManager;
@property (nonatomic) BOOL locationStarted;
@property (strong, nonatomic) CLGeocoder *geocoder;

@end

@implementation YHNaviteLBS

- (NSString *)actionName
{
    return YHNative_LBS;
}

- (void)dealloc
{
    if (_geocoder) {
        [_geocoder cancelGeocode];
        _geocoder = nil;
    }
}

- (BOOL)isAuthorized
{
    BOOL authorizationStatusClassPropertyAvailable = [CLLocationManager respondsToSelector:@selector(authorizationStatus)]; // iOS 4.2+
    
    if (authorizationStatusClassPropertyAvailable) {
        NSUInteger authStatus = [CLLocationManager authorizationStatus];
#ifdef __IPHONE_8_0
        if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {  //iOS 8.0+
            return (authStatus == kCLAuthorizationStatusAuthorizedWhenInUse) || (authStatus == kCLAuthorizationStatusAuthorizedAlways) || (authStatus == kCLAuthorizationStatusNotDetermined);
        }
#endif
        return (authStatus == kCLAuthorizationStatusAuthorized) || (authStatus == kCLAuthorizationStatusNotDetermined);
    }
    
    // by default, assume YES (for iOS < 4.2)
    return YES;
}

- (BOOL)isLocationServicesEnabled
{
    BOOL locationServicesEnabledInstancePropertyAvailable = [self.locationManager respondsToSelector:@selector(locationServicesEnabled)]; // iOS 3.x
    BOOL locationServicesEnabledClassPropertyAvailable = [CLLocationManager respondsToSelector:@selector(locationServicesEnabled)]; // iOS 4.x
    
    if (locationServicesEnabledClassPropertyAvailable) { // iOS 4.x
        return [CLLocationManager locationServicesEnabled];
    } else if (locationServicesEnabledInstancePropertyAvailable) { // iOS 2.x, iOS 3.x
        return [(id)self.locationManager locationServicesEnabled];
    } else {
        return NO;
    }
}

- (void)startLocation:(BOOL)enableHighAccuracy
{
    if (![self isLocationServicesEnabled]) {
        self.failureCallBack(@"Location services are not enabled.");
        return;
    }
    if (![self isAuthorized]) {
        NSString* message = nil;
        BOOL authStatusAvailable = [CLLocationManager respondsToSelector:@selector(authorizationStatus)]; // iOS 4.2+
        if (authStatusAvailable) {
            NSUInteger code = [CLLocationManager authorizationStatus];
            if (code == kCLAuthorizationStatusNotDetermined) {
                // could return POSITION_UNAVAILABLE but need to coordinate with other platforms
                message = @"User undecided on application's use of location services.";
            } else if (code == kCLAuthorizationStatusRestricted) {
                message = @"Application's use of location services is restricted.";
            } else if (code == kCLAuthorizationStatusDenied) {
                message = @"Application's use of location services is denied.";
            }
        }
        // PERMISSIONDENIED is only PositionError that makes sense when authorization denied
        self.failureCallBack(message);
        return;
    }
    
#ifdef __IPHONE_8_0
    NSUInteger code = [CLLocationManager authorizationStatus];
    if (code == kCLAuthorizationStatusNotDetermined && ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)] || [self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)])) { //iOS8+
        if([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"]){
            [self.locationManager requestAlwaysAuthorization];
        } else if([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"]) {
            [self.locationManager  requestWhenInUseAuthorization];
        } else {
            NSString *message = @"[Warning] No NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription key is defined in the Info.plist file.";
            self.failureCallBack(message);
        }
        return;
    }
#endif

    [self.locationManager stopUpdatingLocation];
    [self.locationManager startUpdatingLocation];
    self.locationStarted = YES;
}

- (void)stopLocation
{
    if (self.locationStarted) {
        if (![self isLocationServicesEnabled]) {
            return;
        }
        
        [self.locationManager stopUpdatingLocation];
        self.locationStarted = NO;
    }
}

- (NSArray *)availableFunctions
{
    return @[ @"getLocation", @"getLocationDetail" ];
}

- (void)getLocation
{
    if (!_locationManager) {
        self.locationManager = [[CLLocationManager alloc] init];
        self.locationManager.delegate = self;
        self.locationManager.distanceFilter = kCLDistanceFilterNone;
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
        self.locationStarted = NO;
    }
    
    if (![self isLocationServicesEnabled]) {
        self.failureCallBack(@"Location services are disabled.");

    } else {
        
        [self startLocation:YES];
    }
}

- (void)getLocationDetail
{
    if (!_geocoder) {
        self.geocoder = [[CLGeocoder alloc] init];
    }
    [self getLocation];
}

- (void)reverseGeoCode:(CLLocation *)location
{
    __weak typeof(self)weakSelf = self;
    [self.geocoder reverseGeocodeLocation:location
                        completionHandler:^(NSArray *placemarks, NSError *error) {
                            if (error) {
                                weakSelf.failureCallBack([error description]);
                            } else {
                                CLPlacemark *pm = [placemarks lastObject];
                                weakSelf.successCallBack(pm.addressDictionary, NO);
                            }
                            weakSelf.geocoder = nil;
                        }];
}

#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager
     didUpdateLocations:(NSArray *)locations
{
    [self stopLocation];
    
    CLLocation *location = locations.lastObject;
    if (self.geocoder) {
        [self reverseGeoCode:location];
    } else {
        self.successCallBack(@{ @"latitude":@(location.coordinate.latitude),
                                @"longitude":@(location.coordinate.longitude) }, NO);
    }
}

- (void)locationManager:(CLLocationManager*)manager didFailWithError:(NSError*)error
{
    NSLog(@"locationManager::didFailWithError %@", [error localizedFailureReason]);
    
    self.failureCallBack([error localizedDescription]);
    
    if (error.code != kCLErrorLocationUnknown) {
        [self.locationManager stopUpdatingLocation];
        self.locationStarted = NO;
    }
}

//iOS8+
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
    if(!self.locationStarted){
        [self startLocation:YES];
    }
}

@end