|
@@ -0,0 +1,269 @@
|
|
|
+
|
|
|
+#import "SLLocationManager.h"
|
|
|
+#import "JZLocationConverter.h"
|
|
|
+
|
|
|
+#define authStatus(status) @"#status"
|
|
|
+
|
|
|
+@interface SLLocationManager () <CLLocationManagerDelegate>
|
|
|
+
|
|
|
+@property (nonatomic, strong) NSMutableArray *completeBlocks;
|
|
|
+@property (nonatomic, strong) CLLocationManager *locationManager;
|
|
|
+@property (nonatomic, copy) YMCurrentLocationBlock locationBlock;
|
|
|
+//持续定位
|
|
|
+@property (nonatomic, strong) CLLocationManager *holdLocationManager;
|
|
|
+@property (nonatomic, assign) BOOL holdLocating;// 持续定位:正在定位
|
|
|
+
|
|
|
+@end
|
|
|
+
|
|
|
+@implementation SLLocationManager
|
|
|
+
|
|
|
++ (instancetype)shareInstance
|
|
|
+{
|
|
|
+ static SLLocationManager *_instance = nil;
|
|
|
+ static dispatch_once_t onceToken;
|
|
|
+ dispatch_once(&onceToken, ^{
|
|
|
+ _instance = [[[self class] alloc] init];
|
|
|
+ });
|
|
|
+ return _instance;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)dealloc
|
|
|
+{
|
|
|
+ NSLog(@"释放 %s", __func__);
|
|
|
+}
|
|
|
+
|
|
|
+- (NSMutableArray *)completeBlocks
|
|
|
+{
|
|
|
+ if (!_completeBlocks) {
|
|
|
+ _completeBlocks = [NSMutableArray array];
|
|
|
+ }
|
|
|
+ return _completeBlocks;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)setCurrentLocation:(CLLocation *)currentLocation
|
|
|
+{
|
|
|
+ _currentLocation = currentLocation;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)getLocationComplete:(YMCurrentLocationBlock)completeBlock
|
|
|
+
|
|
|
+{
|
|
|
+// if (self.currentLocation) {
|
|
|
+// [self ym_reverseGeocodeLocation:self.currentLocation completionHandler:completeBlock];
|
|
|
+// return;
|
|
|
+// }
|
|
|
+ [self.completeBlocks addObject:completeBlock];
|
|
|
+ CLAuthorizationStatus authStatus = [CLLocationManager authorizationStatus];
|
|
|
+ if(authStatus == kCLAuthorizationStatusNotDetermined) {
|
|
|
+ [self.locationManager requestWhenInUseAuthorization];
|
|
|
+ } else {
|
|
|
+ [self.locationManager startUpdatingLocation];
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
++ (BOOL)locationEnabled
|
|
|
+{
|
|
|
+ if (![CLLocationManager locationServicesEnabled]) {
|
|
|
+ return NO;
|
|
|
+ }
|
|
|
+ CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
|
|
|
+ if (kCLAuthorizationStatusAuthorizedWhenInUse == status ||
|
|
|
+ kCLAuthorizationStatusAuthorizedAlways == status) {
|
|
|
+ return YES;
|
|
|
+ }
|
|
|
+ return NO;
|
|
|
+}
|
|
|
+
|
|
|
+- (CLLocation *)getCurrentLocation:(YMCurrentLocationBlock)locationBlock
|
|
|
+{
|
|
|
+ if (NSThread.currentThread.isMainThread) {
|
|
|
+ [self getCurrentLocationInMainThread:locationBlock];
|
|
|
+ } else {
|
|
|
+ dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
+ [self getCurrentLocationInMainThread:locationBlock];
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return self.currentLocation;
|
|
|
+}
|
|
|
+
|
|
|
+- (void)getCurrentLocationInMainThread:(YMCurrentLocationBlock)locationBlock
|
|
|
+{
|
|
|
+ if (!self.currentLocation &&
|
|
|
+ [SLLocationManager locationEnabled]) {
|
|
|
+ if (self.holdLocating) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ self.holdLocating = YES;
|
|
|
+ self.locationBlock = locationBlock;
|
|
|
+ [self.holdLocationManager startUpdatingLocation];
|
|
|
+ } else {
|
|
|
+ if (locationBlock) {
|
|
|
+ locationBlock(self.currentLocation);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/// 清空当前定位
|
|
|
++ (void)clearLocation
|
|
|
+{
|
|
|
+ [[SLLocationManager shareInstance] setCurrentLocation:nil];
|
|
|
+}
|
|
|
+/// 清空当前地址
|
|
|
++ (void)clearAddress
|
|
|
+{
|
|
|
+ [[SLLocationManager shareInstance] setState:@""];
|
|
|
+ [[SLLocationManager shareInstance] setProvince:@""];
|
|
|
+ [[SLLocationManager shareInstance] setCity:@""];
|
|
|
+}
|
|
|
+/// 清空全部
|
|
|
++ (void)clearAll
|
|
|
+{
|
|
|
+ [self clearLocation];
|
|
|
+ [self clearAddress];
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark - CLLocationManagerDelegate
|
|
|
+// 授权状态变更
|
|
|
+- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
|
|
|
+{
|
|
|
+ if (manager == _locationManager) {
|
|
|
+ if (CLLocationManager.authorizationStatus != kCLAuthorizationStatusNotDetermined) {
|
|
|
+ [self.locationManager startUpdatingLocation];
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+// 更新地位回调
|
|
|
+- (void)locationManager:(CLLocationManager *)manager
|
|
|
+ didUpdateLocations:(NSArray<CLLocation *> *)locations
|
|
|
+{
|
|
|
+ if (manager == _locationManager) {
|
|
|
+ if (locations.count == 0) {
|
|
|
+ for (YMCurrentLocationBlock completeBlock in self.completeBlocks) {
|
|
|
+ completeBlock(nil);
|
|
|
+ }
|
|
|
+ [self.completeBlocks removeAllObjects];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ [self.locationManager stopUpdatingLocation];
|
|
|
+
|
|
|
+ CLLocation *newLocation = [locations lastObject];
|
|
|
+ if (newLocation) {
|
|
|
+ [self ym_reverseGeocodeLocation:newLocation completionHandler:^(void) {
|
|
|
+ for (YMCurrentLocationBlock completeBlock in self.completeBlocks) {
|
|
|
+ completeBlock(newLocation);
|
|
|
+ }
|
|
|
+ [self.completeBlocks removeAllObjects];
|
|
|
+ }];
|
|
|
+ }
|
|
|
+ } else if (manager == _holdLocationManager) {
|
|
|
+ self.holdLocating = NO;
|
|
|
+ if (locations.count > 0) {
|
|
|
+ [self.holdLocationManager stopUpdatingLocation];
|
|
|
+ CLLocation *newLocation = [locations lastObject];
|
|
|
+ if (self.locationBlock) {
|
|
|
+ self.locationBlock(newLocation);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+// 定位失败回调
|
|
|
+- (void)locationManager:(CLLocationManager *)manager
|
|
|
+ didFailWithError:(NSError *)error
|
|
|
+{
|
|
|
+ if (manager == _locationManager) {
|
|
|
+ [self.locationManager stopUpdatingLocation];
|
|
|
+ if (CLLocationManager.authorizationStatus != kCLAuthorizationStatusNotDetermined) {
|
|
|
+ for (YMCurrentLocationBlock completeBlock in self.completeBlocks) {
|
|
|
+ completeBlock(manager.location);
|
|
|
+ }
|
|
|
+ [self.completeBlocks removeAllObjects];
|
|
|
+ }
|
|
|
+ } else if (manager == _holdLocationManager) {
|
|
|
+ [self.holdLocationManager stopUpdatingLocation];
|
|
|
+ self.holdLocating = NO;
|
|
|
+ if (self.locationBlock) {
|
|
|
+ self.locationBlock(nil);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 反向地址编码
|
|
|
+- (void)ym_reverseGeocodeLocation:(CLLocation *)location
|
|
|
+ completionHandler:(void(^)(void))completionHandler
|
|
|
+{
|
|
|
+ if (self.state.length && self.city.length) {
|
|
|
+ if (completionHandler) {
|
|
|
+ completionHandler();
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (@available(iOS 10.0, *)) {
|
|
|
+ NSString *countryCode = [NSLocale autoupdatingCurrentLocale].countryCode;
|
|
|
+ if ([countryCode isEqualToString:@"CN"] ||
|
|
|
+ [countryCode isEqualToString:@"HK"] ||
|
|
|
+ [countryCode isEqualToString:@"MO"] ||
|
|
|
+ [countryCode isEqualToString:@"TW"]) {
|
|
|
+ CLLocationCoordinate2D cor = [JZLocationConverter wgs84ToGcj02:location.coordinate];
|
|
|
+ location = [[CLLocation alloc] initWithLatitude:cor.latitude longitude:cor.longitude];
|
|
|
+ //YMLLog(@"转换后lat:%f", location.coordinate.latitude);
|
|
|
+ //YMLLog(@"转换后long:%f", location.coordinate.longitude);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ NSString *localeIdentifier = [NSLocale autoupdatingCurrentLocale].localeIdentifier;
|
|
|
+ if ([localeIdentifier.lowercaseString hasSuffix:@"cn"] ||
|
|
|
+ [localeIdentifier.lowercaseString hasSuffix:@"hk"] ||
|
|
|
+ [localeIdentifier.lowercaseString hasSuffix:@"mo"] ||
|
|
|
+ [localeIdentifier.lowercaseString hasSuffix:@"tw"]) {
|
|
|
+ CLLocationCoordinate2D cor = [JZLocationConverter wgs84ToGcj02:location.coordinate];
|
|
|
+ location = [[CLLocation alloc] initWithLatitude:cor.latitude longitude:cor.longitude];
|
|
|
+ //YMLLog(@"转换后lat:%f", location.coordinate.latitude);
|
|
|
+ //YMLLog(@"转换后long:%f", location.coordinate.longitude);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ CLGeocoder *geocoder = [[CLGeocoder alloc] init];
|
|
|
+ [geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
|
|
|
+ //YMLLog(@"placemarks:%@(%@)", placemarks, error);
|
|
|
+ if (placemarks.count > 0) {
|
|
|
+ CLPlacemark *first = placemarks[0];
|
|
|
+
|
|
|
+ NSString *country = first.country;
|
|
|
+ NSString *province = first.administrativeArea;
|
|
|
+ NSString *city = first.locality;
|
|
|
+
|
|
|
+ self.state = country ? : @"";
|
|
|
+ self.province = province ? : @"";
|
|
|
+ self.city = city ? : @"";
|
|
|
+ }
|
|
|
+ if (completionHandler) {
|
|
|
+ completionHandler();
|
|
|
+ }
|
|
|
+ }];
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+#pragma mark - instance
|
|
|
+- (CLLocationManager *)locationManager
|
|
|
+{
|
|
|
+ if (!_locationManager) {
|
|
|
+ _locationManager = [[CLLocationManager alloc] init];
|
|
|
+ _locationManager.delegate = self;
|
|
|
+ _locationManager.desiredAccuracy = kCLLocationAccuracyBest;
|
|
|
+ _locationManager.distanceFilter = 5.0;
|
|
|
+ }
|
|
|
+ return _locationManager;
|
|
|
+}
|
|
|
+
|
|
|
+- (CLLocationManager *)holdLocationManager
|
|
|
+{
|
|
|
+ if (!_holdLocationManager) {
|
|
|
+ _holdLocationManager = [[CLLocationManager alloc] init];
|
|
|
+ _holdLocationManager.delegate = self;
|
|
|
+ _holdLocationManager.desiredAccuracy = kCLLocationAccuracyBest;
|
|
|
+ _holdLocationManager.distanceFilter = 5.0;
|
|
|
+ }
|
|
|
+ return _holdLocationManager;
|
|
|
+}
|
|
|
+
|
|
|
+@end
|