iOS區(qū)域監(jiān)控(地理圍欄)

iOS區(qū)域監(jiān)控(地理圍欄)

區(qū)域監(jiān)控,高德地圖上叫地理圍欄,兩者都是同一個意思。此功能實現(xiàn)的是:首先創(chuàng)建一個區(qū)域(圍欄),當用戶設(shè)備進入或者離開此區(qū)域時,會有相應(yīng)的代理方法響應(yīng),開發(fā)者可以做一些操作。并且最重要的一點是當開啟了區(qū)域監(jiān)控,即使用戶殺死了APP還是可以監(jiān)聽到代理方法的響應(yīng),從而做一些操作。

地理圍欄.jpg

位置權(quán)限:必須是始終運行訪問地理位置權(quán)限,這樣在殺死狀態(tài)下才能通過區(qū)域監(jiān)控喚醒APP獲取位置信息。

開始我接入的是高德SDK,但不知是何原因?qū)е挛覛⑺繟PP時地理圍欄并沒有喚醒APP。所以我換成了系統(tǒng)CoreLocation框架實現(xiàn)此功能。

一、導入框架

import CoreLocation

二、初始化CLLocationManager

locationManager = CLLocationManager()
locationManager.delegate = self
//必須滿足始終允許地理位置訪問
locationManager.requestAlwaysAuthorization()
locationManager.pausesLocationUpdatesAutomatically = false
if #available(iOS 9.0, *) {
    locationManager.allowsBackgroundLocationUpdates = true
} else {
    // Fallback on earlier versions
}

三、遵從代理CLLocationManagerDelegate

// MARK: - 區(qū)域監(jiān)控代理方法
extension AppLocationManager {
    
    /// 進入?yún)^(qū)域
    func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
        debugPrint("進入?yún)^(qū)域")
    }
    
    /// 離開區(qū)域
    func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
        debugPrint("離開區(qū)域")
    }
    
    /// 請求某個區(qū)域的狀態(tài)
    func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
        //    CLRegionStateUnknown,   未知狀態(tài)
        //    CLRegionStateInside, // 在區(qū)域內(nèi)部
        //    CLRegionStateOutside // 區(qū)域外面
        var msg = ""
        if(state == .inside)
        {
            debugPrint("在區(qū)域內(nèi)")
            msg = "在區(qū)域內(nèi)"
        }else if (state == .outside)
        {
            debugPrint("在區(qū)域外")
             msg = "在區(qū)域外"
        } else {
            debugPrint("未知區(qū)域")
             msg = "未知區(qū)域"
        }
        //發(fā)送本地推送
        LocalNotificationManager.addNotification(msg: msg)
    }
    
    /// 監(jiān)聽區(qū)域失敗
    func locationManager(_ manager: CLLocationManager, monitoringDidFailFor region: CLRegion?, withError error: Error) {
        // 經(jīng)驗: 一般在這里, 做移除最遠的區(qū)域
        //    [manager stopMonitoringForRegion:最遠區(qū)域]
        debugPrint(error)
    }
}

四、區(qū)域定位喚醒被殺死APP

當用戶設(shè)置始終允許訪問地理位置權(quán)限時,即使APP被殺死了,當進入?yún)^(qū)域或者離開區(qū)域時都能喚醒APP,這時我們就可以在AppDelegate方法中func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool判斷是否是區(qū)域定位喚醒的從而做一些操作。

/// APP被喚醒機制
    func awakeForRegion(launchOptions: [UIApplication.LaunchOptionsKey: Any]?) {
        let flag = launchOptions?.keys.contains(UIApplication.LaunchOptionsKey.location) ?? false
        if flag {
            LocalNotificationManager.addNotification(msg: "被區(qū)域定位喚醒")
        }
        let isNotification = launchOptions?.keys.contains(UIApplication.LaunchOptionsKey.remoteNotification) ?? false
        if isNotification {
            LocalNotificationManager.addNotification(msg: "被通知推送喚醒")
        }
    }

五、開啟區(qū)域監(jiān)控

做好了以上步驟就可以實現(xiàn)區(qū)域監(jiān)控代碼了,區(qū)域監(jiān)控顧名思義就是要劃定一個區(qū)域,系統(tǒng)給我們提供了好幾種劃定區(qū)域的方法,我們選擇最簡單的一種--畫圓。

/// 開啟區(qū)域定位
    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) 轉(zhuǎn)換成 世界標準地理坐標(WGS-84)
//              這里是因為我們使用的是國內(nèi)的坐標系統(tǒng),但是iOS系統(tǒng)獲取的是世界標注坐標系統(tǒng)所以我們需要轉(zhuǎn)換一下
//              如果你們后端提供的坐標也是世界標準的話就不需要轉(zhuǎn)化了
//              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
            }
                //判斷半徑是否超過系統(tǒng)的最大
            if radius > self.locationManager.maximumRegionMonitoringDistance {
                radius = self.locationManager.maximumRegionMonitoringDistance
            }
            let region = CLCircularRegion(center: center, radius: radius, identifier: "NZ")
            //監(jiān)聽進入?yún)^(qū)域
            region.notifyOnEntry = true
            //監(jiān)聽離開區(qū)域
            region.notifyOnExit = true
            //開始區(qū)域監(jiān)聽
            locationManager.startMonitoring(for: region)
            locationManager.requestState(for: region)
        }
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容