app 后台持續定位


現在幾乎所有的app都會使用GPS 定位,但是只有少數的app 會要求在應用退到后台以后,還要求持續定時定位的,此類app一般只有導航類app才會使用,且審核不會被拒!

當然,以上問題都可以和蘋果官方進行溝通解決。

現在對定位的代碼進行說明:

info文件中要增加以下字段:

NSLocationAlwaysUsageDescription

此key配合權限獲取

[self.locationManager requestAlwaysAuthorization];

以上兩行必不可少 ,否則會出現應用退到后台以后,只有定時器在執行 ,定位獲取不到的問題(既不走成功,也不走失敗的回調)

以下為定位的代碼:此類中包含了定時器

//
//  AutoLocatedModel.m
//  JHAutoLocated
//
//  Created by pk on 2016/11/2.
//  Copyright © 2016年 pk. All rights reserved.
//

#import "AutoLocatedModel.h"

#import <UIKit/UIKit.h>

@interface AutoLocatedModel ()<CLLocationManagerDelegate>



@property (nonatomic, strong) NSTimer *timer;

@end

@implementation AutoLocatedModel

+ (instancetype)shareInstance{
    static dispatch_once_t onceToken;
    static AutoLocatedModel * model = nil;
    dispatch_once(&onceToken, ^{
        model = [[AutoLocatedModel alloc] init];
        model.locationManager = [[CLLocationManager alloc] init];
        model.locationManager.delegate = model;
        
        model.locationManager.desiredAccuracy=kCLLocationAccuracyBest;//定位精確度
        model.locationManager.distanceFilter = kCLDistanceFilterNone;//任何運動均接受,任何運動將會觸發定位更新
        if ([UIDevice currentDevice].systemVersion.floatValue >= 9.0) {
            model.locationManager.allowsBackgroundLocationUpdates = YES;
        }

        [model createTimer];
        [model startLocated];
    });
    return model;
}

#pragma mark - 定時器相關
- (void)createTimer{
    //觸發計時器
    [self deleteTimer];
    self.timer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(startLocated) userInfo:nil repeats:YES];
}

- (void)deleteTimer{
    if ([self.timer isValid]) {
        [self.timer invalidate];
        self.timer =nil;
    }
}

- (void)startLocated{
    
    [self.locationManager requestAlwaysAuthorization];
    [self.locationManager requestWhenInUseAuthorization];
    self.locationManager.pausesLocationUpdatesAutomatically = NO;
    // 判斷定位操作是否被允許
    if([CLLocationManager locationServicesEnabled]) {
        // 開始定位
        [self.locationManager stopUpdatingLocation];
        [self.locationManager startUpdatingLocation];
        NSLog(@"開始執行定位");
        NSLog(@"locationManager = %@",self.locationManager);
    }else {
        //提示用戶無法進行定位操作
        NSLog(@"定位關閉");
    }
    
}

- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status{
    if (status == kCLAuthorizationStatusNotDetermined || status == kCLAuthorizationStatusDenied) {
        NSLog(@"暫未獲取到權限");
    }else{
        [manager startUpdatingLocation];
    }
}

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
    [manager stopUpdatingLocation];
    //此處locations存儲了持續更新的位置坐標值,取最后一個值為最新位置,如果不想讓其持續更新位置,則在此方法中獲取到一個值之后讓locationManager stopUpdatingLocation
    CLLocation *currentLocation = [locations lastObject];
    
    CLLocationCoordinate2D coor = currentLocation.coordinate;

    NSLog(@"經緯度 = latitude: %f longitude:%f ",coor.latitude,coor.longitude);
//    [self.locationManager stopUpdatingLocation];
    
    [self createTimer];
    
    //反向地理編碼
//    CLGeocoder *clGeoCoder = [[CLGeocoder alloc] init];
//    CLLocation *cl = [[CLLocation alloc] initWithLatitude:coor.latitude longitude:coor.longitude];
//    
//    [clGeoCoder reverseGeocodeLocation:cl completionHandler: ^(NSArray *placemarks,NSError *error) {
//             for (CLPlacemark *placeMark in placemarks) {
//                NSDictionary *addressDic = placeMark.addressDictionary;
//                NSString *state=[addressDic objectForKey:@"State"];
//                NSString *city=[addressDic objectForKey:@"City"];
//                NSString *subLocality=[addressDic objectForKey:@"SubLocality"];
//                NSString *street=[addressDic objectForKey:@"Street"];
//
//                NSLog(@"所在城市====%@ %@ %@ %@", state, city, subLocality, street);
//                 break;
//             }
//     
//    }];
}

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
    NSLog(@"獲取地址失敗 = %@",error);
    if (error.code == kCLErrorDenied) {
        // 提示用戶出錯原因,可按住Option鍵點擊 KCLErrorDenied的查看更多出錯信息,可打印error.code值查找原因所在
    }
}



@end

另外我們在要appdelegate 中編寫進入后台的方法

//
//  AppDelegate.m
//  JHAutoLocated
//
//  Created by pk on 2016/11/2.
//  Copyright © 2016年 pk. All rights reserved.
//

#import "AppDelegate.h"
#import "AutoLocatedModel.h"

@interface AppDelegate ()
{
    UIBackgroundTaskIdentifier backgroundTaskIdentifier;
    UIBackgroundTaskIdentifier oldBackgroundTaskIdentifier;

}

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application {
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    
    NSLog(@"進入后台,要開始后台任務");
    
    [application endBackgroundTask:oldBackgroundTaskIdentifier];
    oldBackgroundTaskIdentifier = backgroundTaskIdentifier;
    
    if ([[UIDevice currentDevice] isMultitaskingSupported] == YES) {
        //TODO: 缺少用戶登錄判斷
        backgroundTaskIdentifier = [application beginBackgroundTaskWithExpirationHandler:^{
            AutoLocatedModel * autoLocate = [AutoLocatedModel shareInstance];
            if([CLLocationManager significantLocationChangeMonitoringAvailable]) {
                 [autoLocate.locationManager startMonitoringSignificantLocationChanges];
            }
            [autoLocate startLocated];
            
        }];
    }
   
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
    
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    NSLog(@"被激活了");
    //TODO: 缺少用戶登錄判斷
    AutoLocatedModel * autoLocate = [AutoLocatedModel shareInstance];
    [autoLocate startLocated];
    
    
}

- (void)applicationWillTerminate:(UIApplication *)application {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

@end

獲取到定位以后,可以將位置上傳到服務器 ,此處還有很多可以優化的地方 ,例如:可以利用兩次定位的距離來判斷 只有距離大於多少時進行上傳 ,已保證服務器減少垃圾數據等


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM