后台定时定位-Location实践经验

前言

最近接到这样一个需求,每隔固定时间采集用户的位置,然后再把这些数据上传到服务器。研究了下ios的定位功能,在后台定时遇到了一些困难。当app进入后台状态,定时器就不再运行,导致无法取到用户的位置。
在网上查了一些资料,发现有人已经实现了这个功能,它是一个Github上的第三方库,叫Location,不仅能在后台定时采集位置数据,还优化了定位方式,减少耗电。
接下来我们来看看Location是如何实现的以及它存在的问题。

代码结构

Location代码结构

BackgroundTaskManager

负责创建、管理后台任务,提供两个方法,开始和结束后台任务。它实现了后台任务的无限期运行。
@interface BackgroundTaskManager : NSObject

+(instancetype)sharedBackgroundTaskManager;

-(UIBackgroundTaskIdentifier)beginNewBackgroundTask;
-(void)endAllBackgroundTasks;

@end

LocationShareModel

包装了后台任务类,也管理定位定时器。

@interface LocationShareModel : NSObject
@property (nonatomic) NSTimer *timer;
@property (nonatomic) NSTimer * delay10Seconds;
@property (nonatomic) BackgroundTaskManager * bgTask;
@property (nonatomic) NSMutableArray *myLocationArray;
+(id)sharedModel;
@end

LocationTracker

负责管理后台定时定位的主类。
我们先看一下它提供的接口。
+ (CLLocationManager *)sharedLocationManager;

//开始追踪定位
- (BOOL)startLocationTracking;
//停止追踪定位
- (void)stopLocationTracking;
//向服务器发送已获取的设备位置数据
- (void)updateLocationToServer;

LocationTracker类的初始化
+ (CLLocationManager *)sharedLocationManager {
static CLLocationManager *_locationManager;
@synchronized(self) {
if (_locationManager == nil) {
_locationManager = [[CLLocationManager alloc] init];
//设备位置精度,这里设置为最高精度
_locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
//是否暂停更新
_locationManager.pausesLocationUpdatesAutomatically = NO;
//iOS9的新特性,打开后台位置更新,还要在plist中配置
if (IOS9ORLATER) {
_locationManager.allowsBackgroundLocationUpdates = YES;
}
}
}
return _locationManager;
}
当应用进入后台,借助BackgroundTaskManager无限延长后台任务的存活时间,进行后台采集位置信息。
- (id)init {
if (self==[super init]) {
//Get the share model and also initialize myLocationArray
self.shareModel = [LocationShareModel sharedModel];
self.shareModel.myLocationArray = [[NSMutableArray alloc]init];

        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];
    }
    return self;
}

-(void)applicationEnterBackground{
    CLLocationManager *locationManager = [LocationTracker sharedLocationManager];
    locationManager.delegate = self;
    locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
    locationManager.distanceFilter = kCLDistanceFilterNone;

    if(IOS8ORLATER) {
        [locationManager requestAlwaysAuthorization];
    }
    [locationManager startUpdatingLocation];

    //Use the BackgroundTaskManager to manage all the background Task
    self.shareModel.bgTask = [BackgroundTaskManager sharedBackgroundTaskManager];
    [self.shareModel.bgTask beginNewBackgroundTask];
}

持续获取设备的位置,是个特别耗电的任务。为了减少耗电,定时关闭位置服务。在接收到位置信息10秒后,关闭位置服务,一分钟后再重新打开位置服务,这样就达到减少耗电的目的。我们看代码的实现

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{

    ......

    self.shareModel.bgTask = [BackgroundTaskManager sharedBackgroundTaskManager];
    [self.shareModel.bgTask beginNewBackgroundTask];

    //Restart the locationMaanger after 1 minute
    self.shareModel.timer = [NSTimer scheduledTimerWithTimeInterval:60 target:self
                                                           selector:@selector(restartLocationUpdates)
                                                           userInfo:nil
                                                            repeats:NO];

    //Will only stop the locationManager after 10 seconds, so that we can get some accurate locations
    //The location manager will only operate for 10 seconds to save battery
    if (self.shareModel.delay10Seconds) {
        [self.shareModel.delay10Seconds invalidate];
        self.shareModel.delay10Seconds = nil;
    }

    self.shareModel.delay10Seconds = [NSTimer scheduledTimerWithTimeInterval:10 target:self
                                                                    selector:@selector(stopLocationDelayBy10Seconds)
                                                                    userInfo:nil
                                                                     repeats:NO];

}

重启位置服务
- (void) restartLocationUpdates
{
if (self.shareModel.timer) {
[self.shareModel.timer invalidate];
self.shareModel.timer = nil;
}

    CLLocationManager *locationManager = [LocationTracker sharedLocationManager];
    locationManager.delegate = self;
    locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
    locationManager.distanceFilter = kCLDistanceFilterNone;

    if(IOS8ORLATER) {
        [locationManager requestAlwaysAuthorization];
    }
    [locationManager startUpdatingLocation];
}

按照Location库的设计,在updateLocationToServer方法中,处理向服务器发送信息。
- (void)updateLocationToServer {

    .........

    //TODO: 在这里插入你的代码,处理向服务器发送位置信息


    ........

}

实践

这个类库解决了后台定时定位的问题,使用也很简单,而且还处理了定位耗电的问题,使耗电量降低到每小时5%左右。但在实践的过程中发现它存在一些问题。

  1. 发送数据到服务器方法的定时器,最大支持3分钟;
  2. 发送数据到服务器方法的定时器,在运行2小时后就停止了;
  3. 发送数据到服务器方法的定时器,不准确;

经过一些尝试,废弃了updateLocationToServer方法,将发送数据的代码移到locationManager中,才解决了这几个问题。具体解决方法如下:
首先为LocationTracker类添加一个私有的属性,记录上次执行发送数据的时间。

@interface LocationTracker ()
@property (nonatomic, strong) NSDate *lastSendDate;
@end

在locationManager回调方法中添加自己的代码。

    .......
//Select only valid location and also location with good accuracy
        if(newLocation!=nil&&theAccuracy>0
           &&theAccuracy<2000
           &&(!(theLocation.latitude==0.0&&theLocation.longitude==0.0))){

            self.myLastLocation = theLocation;
            self.myLastLocationAccuracy= theAccuracy;

            NSMutableDictionary * dict = [[NSMutableDictionary alloc]init];
            [dict setObject:[NSNumber numberWithFloat:theLocation.latitude] forKey:@"latitude"];
            [dict setObject:[NSNumber numberWithFloat:theLocation.longitude] forKey:@"longitude"];
            [dict setObject:[NSNumber numberWithFloat:theAccuracy] forKey:@"theAccuracy"];

            //Add the vallid location with good accuracy into an array
            //Every 1 minute, I will select the best location based on accuracy and send to server
            [self.shareModel.myLocationArray addObject:dict];

            //这里插入代码,处理发送位置数据到服务器
                if (!self.lastSendDate || [[self.lastSendDate dateByAddingHours:1] compare:[NSDate date]] <= 0) {
                    self.lastSendDate = [NSDate date];
                    }
            }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,849评论 6 13
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,169评论 11 349
  • 昨夜下了一晚的雨风也不停的推着阳台的玻璃早晨起来天还阴沉着脸可是看到土著认真的大快朵颐心里一下子就晴了 听说叉烧酥...
    哈哈同学阅读 194评论 0 0
  • 这么漂亮的一个园艺店,里面铺满了各式各样适合秋季种植的种球。 为何说是一个难点呢? 因为同样的散货模式,放到我们大...
    楠飞阅读 145评论 0 0