iOS开发 程序后台上传位置CLLocationManager

之前开发一款配送员用的APP时,用到了在程序在后台时,可以不断上传位置的功能,今天略微整理了一下,

主要用到系统的CoreLocation

代码:

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

@interface XSDLocationTools : NSObject
+ (XSDLocationTools *)shareInstance;
// 开启定位
- (void)startLocationService;
@end

.m

//
//  XGLocationTool.m
//  XGPayDemo
//
//  Created by 小广 on 16/4/25.
//  Copyright © 2016年 小广. All rights reserved.
//

#import "XSDLocationTools.h"
#import <CoreLocation/CoreLocation.h>
//#import "WGS84ToGCJ02.h"
#import "BaiduMapDefine.h"
#import "XSDBaiduMapTools.h"

#define LAST_LONG  @"last_longitude"  // 上次上传位置的经度
#define LAST_LATI  @"last_latitude"  // 上次上传位置的纬度


@interface XSDLocationTools ()<CLLocationManagerDelegate>
{
    //dispatch_source_t _timer;
    CLLocationCoordinate2D _newCoor;
}
// 1.设置位置管理者属性
@property (nonatomic, strong) CLLocationManager *lcManager;
//@property (nonatomic, assign) BOOL isRequest;
@property (nonatomic, strong) NSTimer *uploadTimer;

@end

@implementation XSDLocationTools

+ (XSDLocationTools *)shareInstance {
    static XSDLocationTools *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[XSDLocationTools alloc] init];
        [instance p_addNSNotificationObserver];
    });
    
    return instance;
}

// 开启定位
- (void)startLocationService {
    if ([CLLocationManager locationServicesEnabled]) {
        // 创建位置管理者对象
        self.lcManager = [[CLLocationManager alloc] init];
        self.lcManager.delegate = self; // 设置代理
        // 设置定位距离过滤参数 (当本次定位和上次定位之间的距离大于或等于这个值时,调用代理方法)
        self.lcManager.distanceFilter = 50;
        self.lcManager.desiredAccuracy = kCLLocationAccuracyBest; // 设置定位精度(精度越高越耗电)
        
        // 2、在Info.plist文件中添加如下配置:
        //(1)NSLocationAlwaysUsageDescription 授权使应用在前台后台都能使用定位服务
        //(2)NSLocationWhenInUseUsageDescription 授权使应用只能在前台使用定位服务
        // 两者也可以都写
        
        if ([[UIDevice currentDevice].systemVersion floatValue] >=8.0 ) {
            // iOS0.0:如果当前的授权状态是使用是授权,那么App退到后台后,将不能获取用户位置,即使勾选后台模式:location
            [self.lcManager requestAlwaysAuthorization];
            [self.lcManager requestWhenInUseAuthorization];
        }
        
        // iOS9.0+ 要想继续获取位置,需要使用以下属性进行设置(注意勾选后台模式:location)但会出现蓝条
        if ([self.lcManager respondsToSelector:@selector(allowsBackgroundLocationUpdates)]) {
            //
            self.lcManager.allowsBackgroundLocationUpdates = YES;
        }
        
        [self.lcManager startUpdatingLocation]; // 开始更新位置
        [self.uploadTimer setFireDate:[NSDate distantPast]]; // 开启定时器
    }
}


/** 获取到新的位置信息时调用*/
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
    CLLocation *tempLocation = locations[0];
    // 将坐标转化为百度坐标 方法来源于百度sdk
    NSDictionary *temp = BMKConvertBaiduCoorFrom(tempLocation.coordinate, BMK_COORDTYPE_GPS);
    CLLocationCoordinate2D nowLocation = BMKCoorDictionaryDecode(temp);
    //if (self.isRequest) return;
    //self.isRequest = YES;
    //[self uploadUserLocationHandle:nowLocation];
    //[self uploadLocationTimer:nowLocation];
    _newCoor = nowLocation;
}
/** 不能获取位置信息时调用*/
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
    NSLog(@"获取定位失败");
}

/** 定位服务状态改变时调用*/
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
    switch (status) {
        case kCLAuthorizationStatusNotDetermined:
        {
            NSLog(@"用户还未决定授权");
            break;
        }
        case kCLAuthorizationStatusRestricted:
        {
            NSLog(@"访问受限");
            break;
        }
        case kCLAuthorizationStatusDenied:
        {
            // 类方法,判断是否开启定位服务
            if ([CLLocationManager locationServicesEnabled]) {
                NSLog(@"定位服务开启,被拒绝");
            } else {
                NSLog(@"定位服务关闭,不可用");
            }
            break;
        }
        case kCLAuthorizationStatusAuthorizedAlways:
        {
            NSLog(@"获得前后台授权");
            break;
        }
        case kCLAuthorizationStatusAuthorizedWhenInUse:
        {
            NSLog(@"获得前台授权");
            break;
        }
        default:
            break;
    }
}


// 直接上传用户位置
static NSInteger uploadCount = 1;
- (void)uploadUserLocationHandle:(CLLocationCoordinate2D)coor {
    
    NSDictionary *dic = @{@"longitude":@(coor.longitude),
                          @"latitude":@(coor.latitude)};
    __weak typeof(self)weakSelf = self;
    [[UserManager shareInstance] uploadUserLocation:dic block:^(BOOL success) {
        if (!success) {
            if (uploadCount > 3) return ;
            uploadCount ++;
            [weakSelf uploadUserLocationHandle:coor];
            XSDLog(@"上传位置不ok");
            return;
        }
        // 
        if (uploadCount != 1) uploadCount = 1;
        XSDLog(@"上传位置ok");
    }];
   
}

// 定时上传位置
- (void)uploadLocationTimer {
    
    BOOL canUpload = [self isCanUpload:_newCoor];
    if (canUpload) {
        NSDictionary *dic = @{@"longitude":@(_newCoor.longitude),
                              @"latitude":@(_newCoor.latitude)};
        __weak typeof(self)weakSelf = self;
        // 和后台服务器进行交互 上传位置
        [[UserManager shareInstance] uploadUserLocation:dic block:^(BOOL success) {
            
            if (success) {
                XSDLog(@"上传位置ok");
                return ;
            }
            XSDLog(@"上传位置不ok");
            [weakSelf uploadUserLocationHandle:_newCoor];
        }];
    }
    
}

// 监听用户登录的通知
- (void)p_addNSNotificationObserver {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(p_loginNotification) name:kLoginNotification object:nil];
}

- (void)p_loginNotification {
    // 用户登录, 就开始上传位置
    NSString *latitude = [XSDTools objectForKey:TCPFLocationlatitude];
    NSString *longitude = [XSDTools objectForKey:TCPFLocationlongitude];
    if (!latitude || !longitude) return;
    
    // 读取本地的经纬度
    CLLocationCoordinate2D location = CLLocationCoordinate2DMake(latitude.doubleValue, longitude.doubleValue);
    [self uploadUserLocationHandle:location];
}

// 是否达到条件(判断距离 大于一定距离)上传位置
- (BOOL)isCanUpload:(CLLocationCoordinate2D)coor {
    
    //  下面代码相当于 NSUserDefaults 存取数据
    NSString *latitude = [XSDTools objectForKey:LAST_LATI];
    NSString *longitude = [XSDTools objectForKey:LAST_LONG];
    
    if (!latitude || !longitude) {
        //  下面代码相当于 NSUserDefaults 存取数据
        [XSDTools setValue:[NSString stringWithFormat:@"%f",coor.latitude] forKey:LAST_LATI];
        [XSDTools setValue:[NSString stringWithFormat:@"%f",coor.longitude] forKey:LAST_LONG];
        return YES;
    }
    
    //  下面代码来源于百度sdk 计算两点间的距离 
    NSNumber *distence = [XSDBaiduMapTools calculateTwoPointLongWithStart:CLLocationCoordinate2DMake(latitude.doubleValue, longitude.doubleValue) end:coor];
    
    if (distence.integerValue >= 100) {
         //  下面代码相当于 NSUserDefaults 存取数据
        [XSDTools setValue:[NSString stringWithFormat:@"%f",coor.latitude] forKey:LAST_LATI];
        [XSDTools setValue:[NSString stringWithFormat:@"%f",coor.longitude] forKey:LAST_LONG];
        return YES;
    }
    return NO;
}

// 懒加载
- (NSTimer *)uploadTimer {
    if (!_uploadTimer) {
        _uploadTimer = [NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:@selector(uploadLocationTimer) userInfo:nil repeats:YES];
    }
    return _uploadTimer;
}



@end
里面用到了一些自定义的类,不过不影响,各位可以根据需求修改,挺简单的;

在AppDelegate的- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions 方法里

直接调用即可:[[XSDLocationTools shareInstance] startLocationService];

还有,是必须在如图所示,勾选location updates;

图:


最后,审核的时候,一定要说明清楚,为啥要用这个后台上传位置功能;这个审核被拒概率很大,也没有好的解决方法;

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值