Fork me on GitHub

iOS tutorial 5:关于地理定位和特定区域(Swift)

用户带着iPhone进入某个区域,并在某些区域待多久在开发肯能会有很大用处。

初始化项目

  • 创建新的项目GeoTargeting,使用Single View Appliction模板
  • 添加一个Map View,大小为整个页面
  • 添加相关outlet
  • 实现两个协议

    1
    2
    3
    class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {

    @IBOutlet weak var mapView: MKMapView!
  • 设置CLLocationManagerMKMapView

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // 1
    let locationManager = CLLocationManager()

    override func viewDidLoad() {
    super.viewDidLoad()
    // 2
    locationManager.delegate = self
    locationManager.distanceFilter = kCLLocationAccuracyNearestTenMeters
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    // 3
    mapView.delegate = self
    mapView.showsUserLocation = true
    mapView.userTrackingMode = .follow

    setupData()

    }
    • 1 创建一个CLLocationManager的实例,用于检测用户的位置变化
    • 2 设置locationManager一些参数,确定精确性

viewDidAppear中核查用户授权状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

let authorizationStatus = CLLocationManager.authorizationStatus()
// 1
if authorizationStatus == .notDetermined {
locationManager.requestAlwaysAuthorization()
}
// 2
else if authorizationStatus == .denied {
showAlert("Location services ")
}
// 3
else if authorizationStatus == .authorizedAlways {
locationManager.startUpdatingLocation()
}
}

  • 1 如果用户授权状态是不确定,就检查是否是一直的状态。
  • 2 如果用户授权状态是拒绝,就用弹框显示信息给用户看。showAlert(title:)是弹框函数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    func showAlert(_ title: String) {
    print(title)

    let alertController = UIAlertController(title: title, message: nil, preferredStyle: .alert)

    let action = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
    alertController.addAction(action)

    present(alertController, animated: true, completion: nil)

    }
  • 3 如果用户授权状态是一直,就开始更新地理位置。

另外,还需要在.plist文件中添加key为NSLocationAlwaysUsageDescription的提示信息 需要一直能获取你的位置 才可以。在调用requestAlwaysAuthorization()时这个key是必须的。允许获取当前位置。

添加函数setupData()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
func setupData() {
// 1
if CLLocationManager.isMonitoringAvailable(for: CLCircularRegion.self) {

// 2
let title = "全季酒店"
let coordinate = CLLocationCoordinate2DMake(31.1849700000,121.6303200000)
let regionRadius = 300.0

// 3
let region = CLCircularRegion(center: CLLocationCoordinate2D(latitude: coordinate.latitude, longitude: coordinate.longitude), radius: regionRadius, identifier: title)
locationManager.startMonitoring(for: region)

// 4
let restaurantAnnotation = MKPointAnnotation()
restaurantAnnotation.coordinate = coordinate
restaurantAnnotation.title = title
mapView.addAnnotation(restaurantAnnotation)

// 5
let circle = MKCircle(center: coordinate, radius: regionRadius)
mapView.add(circle)

} else {
print("不能追踪区域")
}
}

// 6
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
let circleRenderer = MKCircleRenderer(overlay: overlay)
circleRenderer.strokeColor = UIColor.red
circleRenderer.lineWidth = 1.0
return circleRenderer
}

  • 1 判断是否监控区域功能是否可用。当用户拒绝状态,或用户不让app背景下刷新,或飞行模式时这个功能不可用
  • 2 随意构建一个位置(如全季酒店),经纬度可通过经纬度查询查询,并设置区域半径regionRadius,单位是米。
  • 3 初始化CLCircularRegion
  • 4 添加一个注解,类似大头针形状。
  • 5 添加区域圆圈标志。
  • 6 这是MKMapViewDelegate的方法,用户画圆

CLRegion

CLRegion就是上面标定的圆形区域。下面添加两个CLLocationManagerDelegate的回调方法,分别在是设备的定位位置进和出标定的区域时调用。

1
2
3
4
5
6
7
8
// MARK:- CLLocationManagerDelegate
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
showAlert("enter \(region.identifier)")
}

func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
showAlert("exit \(region.identifier)")
}

Xcode中的位置调试

上面设备的位置,不可能拿着手机到处跑,Xcode提高了方便的调式方式。可以建立位置文件.GPX:

xcode也提供世界上一些常用的位置文件:

点击上图调试栏最后的位置标志就可以调式了。

复杂逻辑下的位置处理

如果位置不停变化,在监控区域停留时间比较短,或者监控区域比较多是,处理位置问题就比较复杂了。更新部分代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 1
var monitoredRegions: Dictionary<String, NSDate> = [:]

func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
showAlert("enter \(region.identifier)")
// 2
monitoredRegions[region.identifier] = NSDate()
}

func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
showAlert("exit \(region.identifier)")
// 3
monitoredRegions.removeValue(forKey: region.identifier)
}
// 4
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
updateRegions()
}

  • 1 定义以字典用于存储用户进入监控区的时间。
  • 2 记录进入时间。
  • 3 删除进入时间。
  • 4 用户位置变化后调用

加入函数updateRegions()代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func updateRegions() {
// 1
let regionMaxVisiting = 10.0
var regionsToDelete: [String] = []

// 2
for regionIdentifier in monitoredRegions.keys {
// 3
if NSDate().timeIntervalSince(monitoredRegions[regionIdentifier]! as Date) > regionMaxVisiting {
showAlert("谢谢访问")

regionsToDelete.append(regionIdentifier)
}
}

// 4
for regionIdentifier in regionsToDelete {
monitoredRegions.removeValue(forKey: regionIdentifier)
}
}

  • 1 加的用户到某个区域10s,就确定用户已经到访问过这个区域。regionsToDelete用来存储即将删除的区域的identifier,也就用户待过超过10s的区域。
  • 2 遍历所有监控区域
  • 3 timeIntervalSince用来计算某个时间到当前时间的差值,单位为秒。
  • 4 删除用户待过超过regionMaxVisiting的区域。

代码

GeoTargeting

参考 Building a Geo Targeting iOS App in Swift

坚持原创技术分享,您的支持将鼓励我继续创作!
  • 本文标题: iOS tutorial 5:关于地理定位和特定区域(Swift)
  • 本文作者: AndyRon
  • 发布时间: 2017年07月16日 - 12:21
  • 最后更新: 2018年11月07日 - 19:49
  • 本文链接: http://andyron.com/2017/ios-tutorial-5.html
  • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议。转载请注明出处!