iOS区域监控(地理围栏)
区域监控,高德地图上叫地理围栏,两者都是同一个意思。此功能实现的是:首先创建一个区域(围栏),当用户设备进入或者离开此区域时,会有相应的代理方法响应,开发者可以做一些操作。并且最重要的一点是当开启了区域监控,即使用户杀死了APP还是可以监听到代理方法的响应,从而做一些操作。
地理围栏.jpg
位置权限:必须是始终运行访问地理位置权限,这样在杀死状态下才能通过区域监控唤醒APP获取位置信息。
开始我接入的是高德SDK,但不知是何原因导致我杀死APP时地理围栏并没有唤醒APP。所以我换成了系统CoreLocation框架实现此功能。
一、导入框架
代码语言:javascript复制import CoreLocation
二、初始化CLLocationManager
代码语言:javascript复制locationManager = CLLocationManager()
locationManager.delegate = self
//必须满足始终允许地理位置访问
locationManager.requestAlwaysAuthorization()
locationManager.pausesLocationUpdatesAutomatically = false
if #available(iOS 9.0, *) {
locationManager.allowsBackgroundLocationUpdates = true
} else {
// Fallback on earlier versions
}
三、遵从代理CLLocationManagerDelegate
代码语言:javascript复制// MARK: - 区域监控代理方法
extension AppLocationManager {
/// 进入区域
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
debugPrint("进入区域")
}
/// 离开区域
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
debugPrint("离开区域")
}
/// 请求某个区域的状态
func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
// CLRegionStateUnknown, 未知状态
// CLRegionStateInside, // 在区域内部
// CLRegionStateOutside // 区域外面
var msg = ""
if(state == .inside)
{
debugPrint("在区域内")
msg = "在区域内"
}else if (state == .outside)
{
debugPrint("在区域外")
msg = "在区域外"
} else {
debugPrint("未知区域")
msg = "未知区域"
}
//发送本地推送
LocalNotificationManager.addNotification(msg: msg)
}
/// 监听区域失败
func locationManager(_ manager: CLLocationManager, monitoringDidFailFor region: CLRegion?, withError error: Error) {
// 经验: 一般在这里, 做移除最远的区域
// [manager stopMonitoringForRegion:最远区域]
debugPrint(error)
}
}
四、区域定位唤醒被杀死APP
当用户设置始终允许访问地理位置权限时,即使APP被杀死了,当进入区域或者离开区域时都能唤醒APP,这时我们就可以在AppDelegate方法中func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
判断是否是区域定位唤醒的从而做一些操作。
/// APP被唤醒机制
func awakeForRegion(launchOptions: [UIApplication.LaunchOptionsKey: Any]?) {
let flag = launchOptions?.keys.contains(UIApplication.LaunchOptionsKey.location) ?? false
if flag {
LocalNotificationManager.addNotification(msg: "被区域定位唤醒")
}
let isNotification = launchOptions?.keys.contains(UIApplication.LaunchOptionsKey.remoteNotification) ?? false
if isNotification {
LocalNotificationManager.addNotification(msg: "被通知推送唤醒")
}
}
五、开启区域监控
做好了以上步骤就可以实现区域监控代码了,区域监控顾名思义就是要划定一个区域,系统给我们提供了好几种划定区域的方法,我们选择最简单的一种--画圆。
代码语言:javascript复制/// 开启区域定位
func regionWatch() {
if CLLocationManager.isMonitoringAvailable(for: CLCircularRegion.self) {
guard let lat = AppLoginUserManager.default.dormLat, let lng = AppLoginUserManager.default.dormLng else {
return
}
guard lat > 0 && lng > 0 else { return }
var center = CLLocationCoordinate2DMake(lat, lng)
// 中国国测局地理坐标(GCJ-02) 转换成 世界标准地理坐标(WGS-84)
// 这里是因为我们使用的是国内的坐标系统,但是iOS系统获取的是世界标注坐标系统所以我们需要转换一下
// 如果你们后端提供的坐标也是世界标准的话就不需要转化了
// JZLocationConverter是一个第三方库:https://github.com/JackZhouCn/JZLocationConverter
center = JZLocationConverter.gcj02(toWgs84: center)
var radius: Double = 20
if let r = AppLoginUserManager.default.locationRadius, r > 0 {
radius = r
}
//判断半径是否超过系统的最大
if radius > self.locationManager.maximumRegionMonitoringDistance {
radius = self.locationManager.maximumRegionMonitoringDistance
}
let region = CLCircularRegion(center: center, radius: radius, identifier: "NZ")
//监听进入区域
region.notifyOnEntry = true
//监听离开区域
region.notifyOnExit = true
//开始区域监听
locationManager.startMonitoring(for: region)
locationManager.requestState(for: region)
}
}