设备上不会触发重要的位置更改

pot*_*ato 7 core-location cllocationmanager ios

我正在使用重要的位置变更监控.当我在模拟器中运行代码并检查高速公路选项时,我会定期更新位置.我抓住这些更新并将它们保存在NSUserDefaults中,然后每10秒更新一次tableview,这样我就可以看到我是否有任何更新.如果我在真实设备上运行应用程序,我会得到零更新.我把手机放在口袋里,走了80多公里,去过两个城市.零更新.不确定我是否搞砸了什么.我附上了代码.代码是复制粘贴,随意测试.只需确保在storyboard中使用TableViewController并将cell id设置为ID.我错过了什么?我在iphone 5上测试.

info.plist中:

在此输入图像描述

编辑:在Apple docs中找到它.我的locationManager创作应该不同吗?

当应用程序因位置更新而重新启动时,传递给应用程序的启动选项字典:willFinishLaunchingWithOptions:或application:didFinishLaunchingWithOptions:方法包含UIApplicationLaunchOptionsLocationKey键.该键的存在表示新位置数据正在等待传递到您的应用程序.要获取该数据,您必须创建一个新的CLLocationManager对象,并在应用程序终止之前重新启动您运行的位置服务.重新启动这些服务时,位置管理器会将所有挂起的位置更新传递给其委托.

EDIT2:

基于此,位置应至少每15分钟更新一次.我的代码中的错误已确认.

如果GPS级精度对您的应用并不重要,并且您不需要持续跟踪,则可以使用重要更改位置服务.正确使用重要更改位置服务至关重要,因为它至少每15分钟唤醒系统和您的应用程序,即使没有发生位置更改,也会持续运行直到您停止它.

edit3:将此代码添加到AppDelegate didFinishLaunchingWithOptions:以查看应用程序是否被唤醒.它没有被唤醒 - 我在表格视图中看不到200 200条目.可疑的东西正在发生.

 if let options = launchOptions {
            print("options")
            if (launchOptions![UIApplicationLaunchOptionsLocationKey] != nil){
                locationManager.startUpdatingLocation()
                self.lat.append(Double(200))
                self.lon.append(Double(200))
                self.times.append(NSDateFormatter.localizedStringFromDate(NSDate(), dateStyle: .NoStyle, timeStyle: .ShortStyle))
                NSUserDefaults.standardUserDefaults().setObject(lat, forKey: "lat")
                NSUserDefaults.standardUserDefaults().setObject(lon, forKey: "lon")
                NSUserDefaults.standardUserDefaults().setObject(times, forKey: "time")
            }
Run Code Online (Sandbox Code Playgroud)

代码:// AppDelegate:

import UIKit
import CoreLocation

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {

    var lat:[CLLocationDegrees]!
    var lon:[CLLocationDegrees]!
    var times:[String]!
    var distances: [String]!

    var window: UIWindow?
    var locationManager: CLLocationManager!


    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

        locationManager=CLLocationManager()
        locationManager.delegate=self
        locationManager.requestAlwaysAuthorization()

        let isFirstLaunch = NSUserDefaults.standardUserDefaults().objectForKey("lat")
        if isFirstLaunch == nil{
            lat = [CLLocationDegrees]()
            lon = [CLLocationDegrees]()
            times = [String]()
            NSUserDefaults.standardUserDefaults().setObject(lat, forKey: "lat")
            NSUserDefaults.standardUserDefaults().setObject(lon, forKey: "lon")
            NSUserDefaults.standardUserDefaults().setObject(times, forKey: "time")
        }else{
            lat = NSUserDefaults.standardUserDefaults().arrayForKey("lat") as! [CLLocationDegrees]
            lon = NSUserDefaults.standardUserDefaults().arrayForKey("lon") as! [CLLocationDegrees]
            times = NSUserDefaults.standardUserDefaults().objectForKey("time") as! [String]
//            distances = NSUserDefaults.standardUserDefaults().objectForKey("distance") as! [String]

        }  
        return true
    }



    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        print("location updated")

        self.lat.append(locations[0].coordinate.latitude)
        self.lon.append(locations[0].coordinate.longitude)
        self.times.append(NSDateFormatter.localizedStringFromDate(NSDate(), dateStyle: .NoStyle, timeStyle: .ShortStyle))

        NSUserDefaults.standardUserDefaults().setObject(lat, forKey: "lat")
        NSUserDefaults.standardUserDefaults().setObject(lon, forKey: "lon")
        NSUserDefaults.standardUserDefaults().setObject(times, forKey: "time")

        print("Location: \(locations[0].coordinate.latitude)   \(locations[0].coordinate.longitude)")
    }

    func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
        print("did change AS")
        switch status {
        case .AuthorizedWhenInUse:
            locationManager.startMonitoringSignificantLocationChanges()
        case .AuthorizedAlways:
            print("to always")
            locationManager.startMonitoringSignificantLocationChanges()
            if lat.count==0{
                self.lat.append((locationManager.location?.coordinate.latitude)!)
                self.lon.append((locationManager.location?.coordinate.longitude)!)

                self.times.append(NSDateFormatter.localizedStringFromDate(NSDate(), dateStyle: .NoStyle, timeStyle: .ShortStyle))

                NSUserDefaults.standardUserDefaults().setObject(lat, forKey: "lat")
                NSUserDefaults.standardUserDefaults().setObject(lon, forKey: "lon")
                NSUserDefaults.standardUserDefaults().setObject(times, forKey: "time")


            }

//            locationManager.startUpdatingLocation()
            break
        default:
            locationManager.stopMonitoringSignificantLocationChanges()
            break
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

//查看控制器

import UIKit

class TableViewController: UITableViewController {

    let appDel = UIApplication.sharedApplication().delegate as! AppDelegate

    override func viewDidLoad() {
        super.viewDidLoad()

        NSTimer.scheduledTimerWithTimeInterval(10, target: self, selector: "updateTableView", userInfo: nil, repeats: true)
    }



    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return appDel.lon.count
    }


    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("ID", forIndexPath: indexPath)
        cell.textLabel?.text = "\(appDel.lat[indexPath.row])   \(appDel.lon[indexPath.row])    \(appDel.times[indexPath.row])"
        cell.textLabel?.font = UIFont.systemFontOfSize(9)


        return cell
    }

    func updateTableView(){
    self.tableView.reloadData()
    }
}
Run Code Online (Sandbox Code Playgroud)

Bit*_*Dog 15

代码有几个问题:

  1. iOS启动应用程序时,不会启动位置更新.
  2. 不要求后台位置更新.
  3. 代码依赖于授权状态的更改来启动位置更新
  4. didChangeAuthorizationStatus方法中缺少break语句.

以下是相关文件:

第一个文档说,当iOS启动应用程序时,必须完全配置位置管理器对象,以便将位置事件传递给应用程序.

重新启动后,您仍必须配置位置管理器对象并调用此方法[startMonitoringSignificantLocationChanges]以继续接收位置事件.

这就是我通常这样做以确保位置管理器完全启动,无论它是从图标还是iOS启动(抱歉我使用ObjectiveC).

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

  NSLog(@"app launching");
  bgTask = UIBackgroundTaskInvalid;

  locationMgr = [[CLLocationManager alloc] init];
  [locationMgr setDelegate:self];
  if([locationMgr respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)])
    [locationMgr setAllowsBackgroundLocationUpdates:YES];
  CLAuthorizationStatus authorizationStatus= [CLLocationManager authorizationStatus];

  if([launchOptions valueForKey:UIApplicationLaunchOptionsLocationKey] != nil) {
    NSLog(@"relaunching because of significant location change - restarting SLC");
    [locationMgr startMonitoringSignificantLocationChanges];
  }
  else
  {
    if (authorizationStatus == kCLAuthorizationStatusAuthorizedAlways) {
        NSLog(@"launching with authorization to always use location - starting SLC");
        [locationMgr startMonitoringSignificantLocationChanges];
    }
    else
    {
        NSLog(@"launching with no authorization to always use location - requesting authorization");
        if([locationMgr respondsToSelector:@selector(requestAlwaysAuthorization)])
            [locationMgr requestAlwaysAuthorization];
    }
  }

  return YES;
}
Run Code Online (Sandbox Code Playgroud)

注意调用setAllowsBackgroundLocationUpdates.这是iOS9中的新功能,如果您希望在后台接收位置更新,则必须在应用启动时每次都执行此操作.(这就像是"我不是在开玩笑,我知道我在后台模式中要求他们,但我确实想要他们").

想要在挂起时接收位置更新的应用必须在其应用的Info.plist文件中包含UIBackgroundModes键(带位置值),并将此属性的值设置为YES.

最后,您不能依赖于调用didChangeAuthorizationStatus.如果您拥有授权kCLAuthorizationStatusAuthorizedAlways,那么调用[locationMgr requestAlwaysAuthorization]不会导致授权状态的更改,因此不会调用didChangeAuthorizationStatus.

如果在调用requestWhenInUseAuthorization或requestAlwaysAuthorization方法时已知授权状态,则位置管理器不会向此方法报告当前授权状态.