设备上不会触发重要的位置更改 [英] significant location change does not trigger on device

查看:104
本文介绍了设备上不会触发重要的位置更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am using significant location change monitoring. When I run the code in the simulator and check Freeway option I get periodic location updates. I grab these updates and save them in NSUserDefaults and than update tableview every 10s, so I can see if I got any updates. If I run the app on a real device, I get zero updates. I kept the phone in my pocket and travelled over 80km, been in 2 cities. Zero updates. Not sure if I messed something up. I am attaching the code. The code is copy paste, feel free to test. Just make sure to use TableViewController in storyboard and set cell id to ID. What am I missing? I am testing on iphone 5.

info.plist:

info.plist:

编辑:在Apple docs中找到它。我的 locationManager 是否应该以不同的方式创建?

edit: Found this in apple docs. Should my locationManager be created differently?


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

When an app is relaunched because of a location update, the launch options dictionary passed to your application:willFinishLaunchingWithOptions: or application:didFinishLaunchingWithOptions: method contains the UIApplicationLaunchOptionsLocationKey key. The presence of that key signals that new location data is waiting to be delivered to your app. To obtain that data, you must create a new CLLocationManager object and restart the location services that you had running prior to your app’s termination. When you restart those services, the location manager delivers all pending location updates to its delegate.

edit2:

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

Based on this, the location should be updated at least every 15min. Bug in my code confirmed.


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

If GPS-level accuracy isn’t critical for your app and you don’t need continuous tracking, you can use the significant-change location service. It’s crucial that you use the significant-change location service correctly, because it wakes the system and your app at least every 15 minutes, even if no location changes have occurred, and it runs continuously until you stop it.

edit3:将此代码添加到AppDelegate didFinishLaunchingWithOptions:看看应用程序是否被唤醒。它没有被唤醒 - 我在表格视图中看不到200 200条目。有点可疑。

edit3: added this code to AppDelegate didFinishLaunchingWithOptions: to see if app gets awaken. It does not get awaken-I see no 200 200 entry in table view. Something fishy is going on.

 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")
            }

代码:
// AppDelegate:

CODE: //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
        }
    }
}

//查看控制器

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()
    }
}


推荐答案

代码有几个问题:


  1. 当iOS启动应用程序时,不会启动位置更新。

  2. 不要求后台位置更新。

  3. 代码依赖授权状态的更改来开始位置更新

  4. didChangeAuthorizationStatus 方法中缺少break语句。

  1. The location updates are not started when the app is launched by iOS.
  2. Background location updates are not requested.
  3. The code relies on changes in authorization status to start location updates
  4. There is a missing break statement in the didChangeAuthorizationStatus method.

以下是相关文件s:

  • startMonitoringSignificantLocationChanges
  • didChangeAuthorizationStatus
  • allowsBackgroundLocationUpdates

第一个文档说当iOS启动应用程序时必须完全配置位置管理器对象,因此位置事件可以是交付给应用程序。

The first document says a location manager object must be fully configured when iOS launches the app so the location event can be delivered to the app.


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

Upon relaunch, you must still configure a location manager object and call this method [startMonitoringSignificantLocationChanges] to continue receiving location events.

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

This is how I usually do it to ensure that the location manager is fully started regardless of if it was launched from the icon or by iOS (sorry I use 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;
}

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

Notice the call to setAllowsBackgroundLocationUpdates. This is new in iOS9 and must be done everytime the app starts if you want to receive locations updates in the background. (It is like a "I'm not kidding, I know I asked for them in the background modes, but I really do want them").


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

Apps that want to receive location updates when suspended must include the UIBackgroundModes key (with the location value) in their app’s Info.plist file and set the value of this property to YES.

最后,您不能依赖于 didChangeAuthorizationStatus 。如果您拥有授权 kCLAuthorizationStatusAuthorizedAlways ,则调用 [locationMgr requestAlwaysAuthorization] 不会导致授权状态发生变化,因此不会调用 didChangeAuthorizationStatus

Finally you can't rely on didChangeAuthorizationStatus being called. If you have the authorization kCLAuthorizationStatusAuthorizedAlways then calling [locationMgr requestAlwaysAuthorization] doesn't result in a change in authorization status, so didChangeAuthorizationStatus isn't called.


如果在调用requestWhenInUseAuthorization或requestAlwaysAuthorization方法时已知授权状态,则位置管理器不会将当前授权状态报告给这种方法。

If the authorization status is already known when you call the requestWhenInUseAuthorization or requestAlwaysAuthorization method, the location manager does not report the current authorization status to this method.

这篇关于设备上不会触发重要的位置更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆