iOS swift4 使用者定位權限,設定心得與討論

本篇分享關於iOS開發中,定位功能的一些心得。

版本:swift 4

介面:Xcode 9

希望提示出現的時機有:

  1. 使用者下載完,第一次打開 app
  2. 或是在之前已經拒絕被追蹤的情況下,整個app關掉重新打開的時候
    • 跳出 alert ,詢問是否接受追蹤他的位置。
      • 接受:取得定位,開始提供服務。
      • 不接受:跳出 alert 告訴使用者這樣無法得到最好的服務。

這一段的程式碼寫在 AppDelegate.swift 檔案的 didFinishLaunchingWithOptions 區塊內。

這個區塊內的動作,是在使用者下載後第一次打開 app,或是把 app 整個關掉,再重新打開的時候執行。如果只是放到background中,再打開,是不會執行這一段。

所以在這邊會有三種情況,分別是:

  1. 從未指定權限(下載後初次打開):CLLocationManager.authorizationStatus() == .notDetermine
  2. 設定為拒絕,或是整機的定位都被關掉:CLLocationManager.authorizationStatus() == .denied || CLLocationManager.authorizationStatus() == .restricted
  3. 設定為接受:CLLocationManager.authorizationStatus() == .authorizedWhenInUse

在三種情況下,可以再添加你想要執行的內容。

例如在 .notDetermine 的情況下,我們可能會想問他,是否願意接受我們得到你的位置呢?就用 CLLocationManager().requestWhenInUseAuthorization()。

程式碼如下:

*也許你會注意到,這一段程式碼中,我們沒有寫到任何關於跳出警告的部分,事實上這一段我們只要寫在我們的 root.ViewController 裡面就好了,因為無論如何,lunch 之後一定會進入 view。(應該是吧,心虛)


import UIKit
import CoreLocation
import MapKit
//記得要import CoreLocation跟Mapkit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {
var window: UIWindow?
var myLocationManager : CLLocationManager = CLLocationManager()
var myUserDefaults : UserDefaults!
let userLocationAuth : String = "locationAuth"
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
self.myUserDefaults = UserDefaults.standard
myLocationManager.delegate = self
myLocationManager.distanceFilter = kCLLocationAccuracyNearestTenMeters
myLocationManager.desiredAccuracy = kCLLocationAccuracyBest
myLocationManager.activityType = .automotiveNavigation
myLocationManager.startUpdatingHeading()
if CLLocationManager.authorizationStatus() == .notDetermined{
myLocationManager.requestWhenInUseAuthorization()
}//if
else if CLLocationManager.authorizationStatus() == .denied || CLLocationManager.authorizationStatus() == .restricted {
self.myUserDefaults.set(false, forKey: userLocationAuth)
self.myUserDefaults.synchronize()
//這邊可以設定你想要執行的功能,例如這邊我想要紀錄使用者的權限狀況,所以用了userDefaults的功能。
//如果你沒有想要執行任何功能,else if 這一段這一段可以完全不寫。
}//else if
else if CLLocationManager.authorizationStatus() == .authorizedWhenInUse{
self.myUserDefaults.set(true, forKey: userLocationAuth)
self.myUserDefaults.synchronize()
//這一段同上,如果你沒有想要執行任何功能,這一段可以不寫
//
}//else if
return true
}//didFinishLaunchingWithOptions
}//class
//在大引號後面加上它來自哪個開頭是我的習慣,不然我很容易找不到而森77

另一種情況是,把 app 放到 background 之後,再開回來,這時候會發生的情況有 :

  1. 原本就接受定位:直接開始服務。
  2. 原本接受定位,放到background後,到「設定」中取消:這時候我們會希望跳出 alert 告訴使用者這樣無法取得最好的服務。
  3. 原本不接受定位,放到background後,到「設定」中改為接受:開始提供服務。

這邊要注意的是:

  1. 我把 CLLocationManager.authorizationStatus() == .denied ,放在 viewDidLoad 。因為如果你的 app 不只有一個 scene,你把這一段放在 viewDidAppear,每次跳回 root view 的時候,viewDidAppear 都會執行一次,就會再次跳出警告,這樣會讓人覺得很煩。
  2. CLLocationManager.authorizationStatus() == .authorizedWhenInUse 就可以要放在viewDidAppear裡面,並且後面加上 CLLocationManager().startUpdatingLocation() ,這樣就會在使用者接受的情況下,每次畫面被打開之後就開始記錄使用者定位。
  3. 這邊再繼續囉說一下關於 CLLocationManager.authorizationStatus() == .authorizedWhenInUse ,我看到有些開發者會放在  ViewDidLoad裡面,這也不是不行,但我有被害妄想症XD,我想說如果使用者一開始拒絕,然後把 app 放到background,再去打開定位權限,想要開始用的時候。這時候viewDidLoad不會被執行,那就會造成誤會了。
  4. 最後還要加入 func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) ,如果使用者修改了定位權限。例如原本拒絕,後來接受,就要讓 app 開始記錄定位,又或是他在 app lunch 的時候選擇 not allow的話,就會跳出警告。

以下為程式碼:


//
// ViewController.swift
// myNavegationLayoutAndToolBar
//
// Created by Chang Shu Hao on 2018/5/5.
// Copyright © 2018年 Gary. All rights reserved.
//
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
var myLocationManager : CLLocationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
myLocationManager.delegate = self
myLocationManager.distanceFilter = kCLLocationAccuracyNearestTenMeters
myLocationManager.desiredAccuracy = kCLLocationAccuracyBest
if CLLocationManager.authorizationStatus() == .denied {
DispatchQueue.main.async(){
let alertController = UIAlertController(title: "定位權限已關閉", message: "如要變更權限,請至 設定 > 隱私權 > 定位服務 開啟", preferredStyle: .alert)
let okAction = UIAlertAction(title: "ok", style: .default, handler: nil)
alertController.addAction(okAction)
self.present(alertController, animated: true, completion: nil)
}//DispatchQueue
}
}//ViewDidLoad
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if CLLocationManager.authorizationStatus() == .authorizedWhenInUse{
myLocationManager.startUpdatingLocation()
}//else if
}//ViewDidAppear
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
myLocationManager.stopUpdatingLocation()
}//viewDidDisappear
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}//didReceiveMemoryWarning
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == CLAuthorizationStatus.denied{
let alertController = UIAlertController(title: "定位權限已關閉", message: "如要取得咖啡館資訊,請至 設定 > 隱私權 > 定位服務 開啟定位功能", preferredStyle: .alert)
let okAction = UIAlertAction(title: "ok", style: .default, handler: nil)
alertController.addAction(okAction)
self.present(alertController, animated: true, completion: nil)
}//if
else if status == CLAuthorizationStatus.authorizedWhenInUse{
myLocationManager.startUpdatingLocation()
}//else if
}//func didChangeAuthorization
}//class

ViewDidLoad做一些基本的設定:

  • distanceFileter:官方文件的說明是,你水平移動多少距離會更新一次定位,默認設定是所有移動都會被回報。
  • desiredAccuracy:官方文件的說明是,定位的精準度,默認設定是最精準,但有提到越精準需要越多時間以及電力。

ViewDidDisappear:這邊就用 stopUpdatingLocation() 設定離開畫面之後就不再追蹤。

  • 不過我覺得有沒有設定好像都沒差,因為上面用的是 requestWhenInUseAuthorization() 詢問,不是always追蹤,所以理當在退出 app 之後就停止追蹤了,設個心安吧 XD 。

重要:執行之前一定要到到Plist 裡面加入 Key: When in Use Usage Description,說明的部分可以留白。

以上是我對於使用者定位權限設定,還有修改設定之後的動作的心得。

若有錯誤的地方,請不吝賜教,有用詞錯誤或不專業的地方也請見諒。

官方說明:
https://developer.apple.com/documentation/corelocation/cllocationmanager/1620562-requestwheninuseauthorization
https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s