Creating custom CLRegions for monitoring - ios

I'm building an app that uses geofencing but I realised that CLRegion has many limitations, for example:
that location authorizationStatus must be .authorizedAlways in order for region monitoring to work.
only circular regions can be monitored
This limits the functionality that can be applied using region monitoring. However after doing some research i found out that there are ways to change this behaviour by creating a custom class of CLRegion.
To be honest I have no idea how to do this or where to start. Does anyone have any suggestions as to how such a custom CLRegion class could allow customised geo-fencing?
There is a tutorial on appcoda that talked about this briefly, but it wasn't in depth at all, you can find it here:
https://www.appcoda.com/geo-targeting-ios/
There they suggest starting with protocols such as:
protocol RegionProtocol {
var coordinate: CLLocation {get}
var radius: CLLocationDistance {get}
var identifier: String {get}
func updateRegion()
}
protocol RegionDelegateProtocol {
func didEnterRegion()
func didExitRegion()
}
And from these one can create custom functionality for CLRegions, such as monitoring polygons etc.
How should one get started on implementing custom regions?
Thanks!

Related

When to use MKMapView's MKUserTrackingMode vs Location Manager's start updating location?

I'm making an app that tracks a user's location and currently I'm doing this (once user has authorized tracking of their location) with the following code:
override func viewDidLoad() {
super.viewDidLoad()
// set map View delegate
mapView.delegate = self
// turn on user tracking mode to follow user
if tracking == true {
mapView.userTrackingMode = MKUserTrackingMode.follow
} else {
mapView.userTrackingMode = MKUserTrackingMode.none
}
}
This seems to work fine for tracking the user's location and I was wondering when I would use this and when I would use locationManager.startUpdatingLocation() or stopUpdatingLocation().
You'd use userTrackingMode when your sole purpose is to update a map. But sometimes we want the user location for other purposes (e.g. to log it in some database, to use it to see what stores and or location-based special deals we might offer, etc.). In fact, we might use CLLocationManager when a map might not be shown at all, or not yet, at least.
So, if you only care about updating a map, then you can use userTrackingMode. But if you care about location independent of any visual map, use CLLocationManager.

Using swift and Mapkit, display route between user's current location to a specific location

Upon the app opening, I'd like to draw a route between user's current location to a specific location using MapKit in Swift.
I know how to request/get a hold of the users current location:
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
originalTopMargin = topMarginConstraint.constant
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
locationManager.requestLocation()
}
}
What I don't know is, where does the code to actually calculate and display the route belong? Would it be in this function?
func locationManager(manager:CLLocationManager, didUpdateLocations locations:[AnyObject])
I've read the Ray Wenderlich Mapkit tutorials and many, many other sites, I'm having a tough time finding an answer to my specific question. Everything I've found so far has useful information, but doesn't quite have what I'm looking for.
I haven't done this in a long time - but what you want to do is use the MKDirections API.
Basically you create an MKDirectionsRequest object and you can use this to eventually get a list of steps to reach your destination. You can also use this to get an MKPolyLine object to render this on your map etc.
Here is a link to a tutorial. It is in objective-C but it should be relatively easy to translate the code.http://www.devfright.com/mkdirections-tutorial/

Estimote indoor location list can't work

I use Estimote indoor location example to make the location list. But the location list is null. I think the problem that is the App can't find my estimote cloud. Please tell me how to solve the problem.
Code:
weak var weakSelf:ListViewController? = self
let onSuccess:(AnyObject!) -> (Void) =
{ (locations:AnyObject!) in
weakSelf!.ownLocationsArray = locations as! NSMutableArray
weakSelf!.tableView.reloadData()
weakSelf!.hadError = false;
self.finishedSectionRefresh()
}
self.manager.fetchUserLocationsWithSuccess(onSuccess, failure: onFailure)
In order for the app to "find" your Estimote Cloud account, you need to use ESTConfig's setupAppID:andAppToken: method. You can generate the token on:
https://cloud.estimote.com/#/apps/add/your-own-app
Since you're writing in Swift, you might have to add #import <EstimoteSDK/EstimoteSDK.h> to your Objective-C Bridging Header, so that your app gains access to the ESTConfig class.

Create local location based notifications in swift

I'm a relatively new swift developer and I've heard in iOS 8 you can send local notifications based on a users Location. I have had a look at some code, particularly this one to create simple time based local notifications.
var leftNotification1:UILocalNotification = UILocalNotification()
leftNotification1.alertBody = "NotidicationA"
leftNotification1.repeatInterval = NSCalendarUnit.CalendarUnitHour
leftNotification1.fireDate = NSDate(timeIntervalSinceNow: 900)
UIApplication.sharedApplication().scheduleLocalNotification(leftNotification1)
I have also seen that you can replace fireDate with a location trigger like something like this:
var localNotification:UILocalNotification = UILocalNotification()
localNotification.regionTriggersOnce = true
localNotification.region = CLCircularRegion(circularRegionWithCenter: CLLocationCoordinate2D(latitude: 37.33233141, longitude: -122.03121860), radius: 50.0, identifier: "Location1")
UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
I know with locations you need permission from the user and poll for locations and that. I am not aware of how to do that sort of thing and link it with that code. When I just enter this code into my ViewDidLoad like I do for the top one it doesn't work for obvious reasons, the CoreLocation isn't registered and its not polling for locations. If someone could inform me about how to get this code working or even better give me an example code to take a look at that'll be great. Thanks.
I found a few guides that had different ways of approaching this, you need to import CoreLocation then you'll want to register the CLLocationManagerDelegate in the ViewController function in ViewController.swift.
You'll need to get permission for using the location with
locationManager.delegate = self
locationManager.requestAlwaysAuthorization()
UIApplication.sharedApplication().cancelAllLocalNotifications()
If you use the requestWhenInUseAuthorization instead it won't display the notifications as they only are displayed when you are not in the app. In iOS 8 it requires you to declare NSLocationAlwaysUsageDescription in the info.plist file you'll just enter some text to appear when location access is requested.
Once you've done all of that you can start creating your notifications, you can use the following code to do that
let locattionnotification = UILocalNotification()
locattionnotification.alertBody = "You have entered a high risk zone (Crown Range Road) , proceed with caution"
locattionnotification.regionTriggersOnce = false
locattionnotification.region = CLCircularRegion(circularRegionWithCenter: CLLocationCoordinate2D(latitude:
37.33182, longitude: -122.03118), radius: 100.0, identifier: "Location1")
UIApplication.sharedApplication().scheduleLocalNotification(locattionnotification)
The regionTriggersOnce option allows you to turn on and off if you get multiple messages when you enter and exit the zone or only one when you first enter the area.
You can change the latitude, longitude and radius (in meters) values to what you want and when you get within the radius of the point you will be alerted with the contents of the message.
For more details about the different options have a look at https://developer.apple.com/library/ios/documentation/iPhone/Reference/UILocalNotification_Class/
The SetSDK allows you to set this up really really simply now. Basically, just a few lines of code.
SetSDK.instance.onDeparture(from: .any) { departed in
/* do your Swift things here */
let departureCoordinates = departed.location
// keep going
}
SetSDK.instance.onArrival(to: .any) { arrived in
/* do your Swift things here */
let arrivalCoordinates = arrived.location
// keep going
}
The SDK handles doing the persistent location collection without killing your battery and the locations that it sends notifications for are continuously being learned, so no manual entry of geofences or anything like that. Just start it and go.

CLFloor returning nil in iOS 8

So I am trying to get CLFloor in Core Location to give me data instead of returning nil in Swift, but I have not been able to. I have tried my own code and the following from NSHipster:
import CoreLocation
class LocationManagerDelegate: NSObject, CLLocationManagerDelegate {
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: AnyObject[]!) {
let location: CLLocation? = locations[0] as? CLLocation
if let floor: CLFloor? = location?.floor {
println("Current Floor: \(floor?.level)")
}
}
}
let manager = CLLocationManager()
manager.delegate = LocationManagerDelegate()
manager.startUpdatingLocation()
Does anybody know how to make this work on a device or in the simulator, I'm sure the answer would benefit a lot of people. If anyone knows of any good resources on this or CLVisit, that would also be helpful.
As far as I understand what was said in WWDC session 708 - Taking Core Location Indoors, You need to manually register and set up the particular venue on the new Apple's Maps Connect page in order to get the floor information in iOS.
Therefore, it seems there is no way that the floor info is provided automatically (e.g. based altitude information from on GPS) for an arbitrary venue.
based on these 2 links from Apple's website
CLFloor Ref
CLLoaction Class Ref
Discussion
If floor information is not available for the current location, the value of this property is nil.
I'm not expert in swift but i think
returns nil possibly means that there is no floor information at that location.
I don't think iOS will magically tell you the floor level from what I understand https://developer.apple.com/videos/wwdc/2014/?id=708. You need to somehow get that number in another way. E.g. you may capture some iBeacon signal and from that download the floor level number, or swipe on your screen to find the correct floor map you are on?

Resources