iOS区域监控(地理围栏)

2019-08-23 17:42:11 浏览数 (4)

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判断是否是区域定位唤醒的从而做一些操作。

代码语言:javascript复制
/// 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)
        }
    }

0 人点赞