Hello Developers, let me share something exciting about Geofence Location of a particular user. In this blog, we are going to discuss Geofence implementation using Core location and set the virtual boundaries in Apple map.

What is a Geofence?

A  Geofence is a technology that defines a virtual region around a real-world geographical area. Whenever the user enters or exits the region of a certain geofence, actions can be triggered in a device in which we set location enabled and for a region you need to define centre latitude and longitude and set the radius for the boundary of a geofence. See below image which you can get an idea!

ios geofence

Usually, the user will receive a notification with certain information based on its location in real time. The main advantage of this technology is that it creates a fusion between

the virtual world and the real one. We make use of Geofencing in several industry verticals like transport industry, health industry, security industry, child tracking, marketing industry.

How to create a demo using core location :

Step 1:  Create Xcode project and integrate with map view using apple Mapkit.

Map view

Step 2: Setting Up a Location Manager and Permissions using info.plist file

First, we have to import CoreLocation framework and create an object for location manager.

var locationManager: CLLocationManager!

After that, we have to set permission for user current location

permission for user current location

locationManager.desiredAccuracy = kCLLocationAccuracyBest
        if CLLocationManager.authorizationStatus() == .notDetermined {
            if (Always Permission) {
                //ERROR: add NSLocationAlwaysUsageDescription in plist file
                locationManager.requestAlwaysAuthorization()
 // add in plist NSLocationAlwaysUsageDescription
            }
            else {
                //ERROR: add NSLocationWhenInUseUsageDescription in plist file
                locationManager.requestWhenInUseAuthorization()
 // add in plist NSLocationWhenInUseUsageDescription
            }
        }

mapview

After that set LocationManager Delegate for get current location of Device.

locationManager.delegate = self

these are the delegate method for getting location when location update in a device.

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])

func locationManager(_ manager: CLLocationManager, didFailWithError error: Error)

Using this delegate method, we get the current location of the device.

Now we need to set one layer to set GeoFence Boundary, for that we need to add one circle layer in map view defined on bellow code,

if let arr = mapView.layer.sublayers?.filter({$0.name == "circle"}), arr.isEmpty {
            mapView.layer.addSublayer(circle())
        }

func circle() -> CAShapeLayer {
        
        let circlePath = UIBezierPath(arcCenter: CGPoint(x: self.view.center.x, y: self.view.center.y-32), radius: CGFloat((UIScreen.width/2)-50), startAngle: CGFloat(0), endAngle:CGFloat(Double.pi * 2), clockwise: true)
        
        let shapeLayer = CAShapeLayer()
        shapeLayer.path = circlePath.cgPath
        shapeLayer.name = "circle"
        //change the fill color
        shapeLayer.fillColor = UIColor.blue.cgColor
        shapeLayer.opacity = 0.4
        //you can change the stroke color
        shapeLayer.strokeColor = UIColor.blue.cgColor
        //you can change the line width
        shapeLayer.lineWidth = 3.0
        
        return shapeLayer
    }

To get radius of that particular circle layer and end point of the region we use this kind of function

func edgePoints() -> Edges {
        let nePoint = CGPoint(x: (UIScreen.width/2)-50+self.view.center.x, y: (UIScreen.width/2)-50+self.view.center.x-32)
        let swPoint = CGPoint(x: 50, y:self.mapView.bounds.maxY/2-32)
        let neCoord = self.mapView.convert(nePoint, toCoordinateFrom: self.mapView)
        let swCoord = self.mapView.convert(swPoint, toCoordinateFrom: self.mapView)
        return (ne: neCoord, sw: swCoord)
    }   
   
 func currentRedius() -> Double {
        let diststant = CLLocation(latitude: edgePoints().ne.latitude, longitude: edgePoints().ne.longitude).distance(from: CLLocation(latitude: edgePoints().sw.latitude, longitude: edgePoints().sw.longitude))
        return diststant/2
    }

For setting up a region, we use below delegate method:

func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool)

In which we set the region like :

let region = CLCircularRegion(center:mapView.centerCoordinate, radius: currentRedius()-50, identifier: "title")
        locationManager.startMonitoring(for: region)

Now there are some delegate method for region updates like;

func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion)
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion)

When user update location of the device like move for one place the another place when user enter and exit from the boundary the delegate methods call.

iOS geofence

 

out of geofence

For that, we need to set Code in AppDelegate.swift

import UIKit
import CoreLocation

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {

    var window: UIWindow?
    var locationManager: CLLocationManager!
    var lat = 0.0
    var long = 0.0

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        locationManager = CLLocationManager()
        locationManager.delegate = self
        // locationManager.locationServicesEnabled
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        if CLLocationManager.authorizationStatus() == .notDetermined {
             locationManager.requestAlwaysAuthorization()
        }
        locationManager.startUpdatingLocation()
       
        
        // Override point for customization after application launch.
        return true
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        let arrayOfLocation = locations as NSArray
        let location = arrayOfLocation.lastObject as! CLLocation
        let coordLatLon = location.coordinate
        lat  = coordLatLon.latitude
        long = coordLatLon.longitude
         NotificationCenter.default.post(name: NSNotification.Name(rawValue: "didupdate"), object: nil)
    }
    
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        print(error)
    }
    
}


In ViewController.swift   where we set Region and Radius


import UIKit
import MapKit
import CoreLocation

let appDelegate = UIApplication.shared.delegate as! AppDelegate

class ViewController: UIViewController,CLLocationManagerDelegate {
    
    @IBOutlet weak var lblRadius: UILabel!
    @IBOutlet weak var mapView: MKMapView!
    var annotation : MKPointAnnotation?
    let locationManager = CLLocationManager()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        NotificationCenter.default.addObserver(self, selector: #selector(updateLolcation), name: NSNotification.Name(rawValue: "didupdate"), object: nil)
        if let arr = mapView.layer.sublayers?.filter({$0.name == "circle"}), arr.isEmpty {
            mapView.layer.addSublayer(circle())
        }
        
        mapView.showsUserLocation = true
        mapView.delegate = self
        mapView.userTrackingMode = .follow
    
        locationManager.delegate = self;
        locationManager.distanceFilter = kCLLocationAccuracyNearestTenMeters;
        locationManager.desiredAccuracy = kCLLocationAccuracyBest;
        
        // Do any additional setup after loading the view, typically from a nib.
    }

    var flag = true
    func updateLolcation() {
        if flag {
            flag = false
            annotation = MKPointAnnotation()
            annotation?.coordinate = CLLocationCoordinate2D(latitude: appDelegate.lat, longitude: appDelegate.long)
            annotation?.title = "User Current Location"
            mapView.addAnnotation(annotation!)
            
            
            var span: MKCoordinateSpan = MKCoordinateSpan()
            span.latitudeDelta = 1/300
            span.longitudeDelta = 1/300
            var coordinateRegion = MKCoordinateRegion()
            coordinateRegion.span = span
            coordinateRegion.center = annotation!.coordinate
            mapView.setRegion(coordinateRegion, animated: true)
            
        }
        else {
            annotation?.coordinate = CLLocationCoordinate2D(latitude: appDelegate.lat, longitude: appDelegate.long)
        }
        
        
       
    }
    
    func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
       appDelegate.window!.makeToast(message: "Enter in Region" , duration: 2, position: HRToastPositionCenter as AnyObject )
    }
    
    func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
       appDelegate.window!.makeToast(message: "Exit from Region" , duration: 2, position: HRToastPositionCenter as AnyObject )
    }
    
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func circle() -> CAShapeLayer {
        
        let circlePath = UIBezierPath(arcCenter: CGPoint(x: self.view.center.x, y: self.view.center.y-32), radius: CGFloat((UIScreen.width/2)-50), startAngle: CGFloat(0), endAngle:CGFloat(Double.pi * 2), clockwise: true)
        
        let shapeLayer = CAShapeLayer()
        shapeLayer.path = circlePath.cgPath
        shapeLayer.name = "circle"
        //change the fill color
        shapeLayer.fillColor = UIColor.blue.cgColor
        shapeLayer.opacity = 0.4
        //you can change the stroke color
        shapeLayer.strokeColor = UIColor.blue.cgColor
        //you can change the line width
        shapeLayer.lineWidth = 3.0
        
        return shapeLayer
    }

}

extension ViewController : MKMapViewDelegate {
    func mapViewDidFinishLoadingMap(_ mapView: MKMapView) {
        
    }
    
    func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
        lblRadius.text = String(format: "%.2f meter",currentRedius()) 
        if annotation == nil {
            annotation = MKPointAnnotation()
            annotation?.coordinate = CLLocationCoordinate2D(latitude: appDelegate.lat, longitude: appDelegate.long)
            annotation?.title = "User Current Location"
        }
        mapView.removeAnnotations(self.mapView.annotations)
        mapView.addAnnotation(annotation!)
        
        
        let an1 = MKPointAnnotation()
        an1.coordinate =  edgePoints().ne
        
        let an2 = MKPointAnnotation()
        an2.coordinate =  edgePoints().sw
        mapView.addAnnotation(an1)
        mapView.addAnnotation(an2)
        
        let region = CLCircularRegion(center:mapView.centerCoordinate, radius: currentRedius()-50, identifier: "title")
        locationManager.startMonitoring(for: region)
        
    }
   
    typealias Edges = (ne: CLLocationCoordinate2D, sw: CLLocationCoordinate2D)
    
    func edgePoints() -> Edges {
        let nePoint = CGPoint(x: (UIScreen.width/2)-50+self.view.center.x, y: (UIScreen.width/2)-50+self.view.center.x-32)
        let swPoint = CGPoint(x: 50, y:self.mapView.bounds.maxY/2-32)
        let neCoord = self.mapView.convert(nePoint, toCoordinateFrom: self.mapView)
        let swCoord = self.mapView.convert(swPoint, toCoordinateFrom: self.mapView)
        return (ne: neCoord, sw: swCoord)
    }
    
    func currentRedius() -> Double {
        let diststant = CLLocation(latitude: edgePoints().ne.latitude, longitude: edgePoints().ne.longitude).distance(from: CLLocation(latitude: edgePoints().sw.latitude, longitude: edgePoints().sw.longitude))
        return diststant/2
    }
}

That’s it. Enjoy your own code fetching Geofence Core Location.

How Let’s Nurture helps for Geolocation App Development?

Let’s Nurture, a leading IT company known for custom mobile app development in India has got the expertise in providing many solutions based on Geolocation leveraging Geolocation based mobile app development and IoT Solutions. Based on Geolocation app development, we at Let’s Nurture can provide solutions for Elder Care Management, Child Tracking Solutions for Hotels and Resorts, Fleet Tracking using IoT solutions.

If you want to know more about Geolocation app development or want to implement this technology in your existing mobile app, get a free consultation from our experts at Let’s Nurture.

 

Want to work with us? We're hiring!