2016年3月6日 星期日

GPS在背景執行時持續記錄位置


需要讓APP像Nike+或RunKeeper那樣,就算將APP退到背景,也會持續記錄GPS位置。
但是不知道為什麼在背景執行了20分鐘就停止了。研究後發現原來少了一行關鍵程式。

locationManager.pausesLocationUpdatesAutomatically = false
是否讓位置更新自動停止 ,預設為true
時間到了20分鐘左右,就會自動停止

完整範例下載

以下簡介一下程式的內容,完整程式請直接下載範例

設定APP權限
Capabilities->Background Modes 選擇 ON
勾選 Location updates


加入GPS相關函式庫
General->Linked Frameworks and Libraries
點選 + ,加入 CoreLocation.framework


因為是Swift的關係,需要加入Header File



檔案的內容加上
#import <CoreLocation/CoreLocation.h>


建立Header檔案的關聯
Build Settings-> Swift Compiler-Code Generation
->Objective-C Bridging Header 填入 LocationTrack/Header.h
LocationTrack為專案資料夾
Header.h是剛剛建立的Header File


編輯請求權限時的說明文字
編輯Info.plist
加入  NSLocationAlwaysUsageDescription
裡面的文字,是APP請求相關權限時,向使用者說明的文字內容

以下兩個選擇其中一個填入,差別在於,一個是向使用者請求APP使用期間時,才使用GPS;一個是不管是不是APP使用期間,都可以使用GPS
NSLocationWhenInUseUsageDescription APP使用期間才使用GPS的文字說明
NSLocationAlwaysUsageDescription 任何時間都可以使用GPS的文字說明


向使用者請求權限的畫面


權限的差別
設定->隱私權->定位服務
可以看到兩個權限的差別


當APP的權限是選擇"使用App期間"才可以使用GPS時
將APP退到背景時,會顯示正在使用您的位置
像Nike+和RunKeeper


在程式中,要求請求權限的部份,以下選擇一個就可以了
//在APP使用期間才能使用GPS
locationManager.requestWhenInUseAuthorization()
//隨時都可以使用GPS
locationManager.requestAlwaysAuthorization()

範例APP簡介
這個APP在點選"START開始記錄座標"按鈕時,會開始記錄GPS
把GPS資料寫入GPSRecord.plist檔案裡
在開啟APP時,會先讀取GPSRecord.plist檔案的內容
使用iTools等工具就可以將這個記錄檔案取出


初始化
在ViewController當中先定義一些變數
並加上CLLocationManagerDelegate


初始化CLLocationManager
@IBAction func btnStartGPS(sender: UIButton) {
        let btnStartGPSLabel: String = btnStartGPS.titleLabel!.text!
        if((btnStartGPSLabel).rangeOfString("START")?.startIndex == (btnStartGPSLabel).startIndex){
            //簡易的判斷現在是要停止或是開始
            

            btnStartGPS.setTitle("STOP停止記錄座標", forState: UIControlState.Normal)
            //初始化變數
            locationManager = CLLocationManager()
            locationManager.delegate = self
            //設定精確度
            locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
            
            //相當重要的一行
            //如果不加的話,會在背景執行20分鐘左右,就停止記錄了
            locationManager.pausesLocationUpdatesAutomatically = false
            
            if #available(iOS 9.0, *){
                locationManager.allowsBackgroundLocationUpdates = true
            }
            
            //---請求權限---
            //在APP使用期間才能使用GPS
            //locationManager.requestWhenInUseAuthorization()

           //隨時都可以使用GPS
           locationManager.requestAlwaysAuthorization()
           //----------
            
            //設置距離篩選器,表示設備至少移動?米,才通知委託更新
            locationManager.distanceFilter = 10
            locationManager.startUpdatingLocation()
            
        }else{
            btnStartGPS.setTitle("START開始記錄座標", forState: UIControlState.Normal)
            locationManager = nil
            
        }
      
        
    }

座標更新的事件
//座標有更新時會呼叫這裡
    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        //經緯度
        var userLocationLat: String = String(locations[0].coordinate.latitude)
        var userLocationLon: String = String(locations[0].coordinate.longitude)
        
        var GPSText = getNowTime() + "=>" + userLocationLat + "," + userLocationLon
        textGPS.text = GPSText + "\n" + textGPS.text
        
        setPlistContent(GPSText)

    }
需要設定BackgroundTask,才可以在背景執行
override func viewWillAppear(animated: Bool) {
        myTimer.invalidate()
        
        //停止背景執行
        backgroundTask = UIBackgroundTaskInvalid
    }
    
    override func viewWillDisappear(animated: Bool) {
        //當程式進入背景時,執行這段
        //這段是測試用,可以不用有這段
        //監控APP是否還有在執行
        myTimer.invalidate()
        myTimer = NSTimer.scheduledTimerWithTimeInterval(1.0,
            target: self,
            selector: "timerMethod:",
            userInfo: nil,
            repeats: true)
        
        //加這個,才會在背景執行
        //時間到了會執行這裡
        backgroundTask = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler {
            [unowned self] in
         
        }
        assert(backgroundTask != UIBackgroundTaskInvalid)
    }


完整範例下載



------------
iOS后台持续定位并定时上传