my viewController looks like following
import CoreLocation
class MyViewController: UIViewController {
let locationManager = CLLocationManager()
override func viewDidAppear(animated: Bool) {
if #available(iOS 8.0, *) {
self.locationManager.requestWhenInUseAuthorization()
} else {
// Fallback on earlier versions
}
if (CLLocationManager.locationServicesEnabled()) {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
let lon = locationManager.location!.coordinate.longitude
let lat = locationManager.location!.coordinate.latitude
print("lat = \(lat) and long = \(lon)")
}
}
}
// MARK: - CLLocationManagerDelegate
extension MyViewController : CLLocationManagerDelegate {
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
self.locationManager.stopUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print("\(error.localizedDescription)")
}
}
When I execute my program, it prompts a message like
Allow application to access your location while you use the app?
But the Don't Allow and Allow buttons are disabled.
Can someone guide me on where I am going wrong and what I should be doing.
I can manually allow my application to access location services by going to settings. But I would like to know why the buttons are disabled and what should I do to enable it.
note: I have added NSLocationWhenInUseUsageDescription to my info.plist file.
Thanks.
Dt: 29Oct2015
EDIT:
Uninstalled the app and installed again and tried. Now I am able to access the buttons.
Also, I noticed that sometimes the screen goes unresponsive i.e., screen cannot take any input from user. I noticed it today with a textbox. I am not able to get the cursor to the text box.
Is it something to do with IOS update? is anyone else experiencing this type of weird behaviour. Is there any workaround for the same?
Any help is highly appreciated.
Thanks.
Related
I am new to iOS development and struggling with many of the interactions between my program and the device hardware so please excuse my very minimal knowledge.
I am trying to build into my app the ability to run code when a beacon is detected. Ultimately I need this to happen in the background as well but for now I am just working on getting it to work in the foreground.
With the code that I currently have, the print message located within the callback function is never called even with the beacon about two feet from the phone. I have double checked with an android device that the UUID broadcasted by the beacon and the UUID that iOS is searching for is one and the same.
This is the class that I created to manage the location aspects.
import CoreLocation
class LocationManager: NSObject, CLLocationManagerDelegate {
var locationManager: CLLocationManager!
override init() {
super.init()
locationManager = CLLocationManager()
locationManager.delegate = self
}
func locationPermission() {
locationManager.requestAlwaysAuthorization()
}
func startScanning() {
let beaconRegion = CLBeaconRegion(uuid: Beacon.beaconUUID!, identifier: "CarBeacon")
print(Beacon.beaconUUID!)
locationManager.startMonitoring(for: beaconRegion)
locationManager.startRangingBeacons(in: beaconRegion)
}
func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) {
if let beacon = beacons.first {
print(beacon.uuid)
}
}
}
This is called from a SwiftUI View with me creating the object in the beginning:
let locationManager = LocationManager()
with this in the view:
.onAppear() {
locationManager.locationPermission()
locationManager.startScanning()
}
Additionally, the UUID is from a separate file
enum Beacon {
static let beaconUUID = UUID(uuidString: "1810C112-B26E-49EB-8EB0-B8DB2DDF2DFB")
}
I also tried replacing the startScanning() function with startMonitoring():
func startMonitoring() {
let beaconRegion = CLBeaconRegion(uuid: Beacon.beaconUUID!, identifier: "CarBeacon")
locationManager.startMonitoring(for: beaconRegion)
}
and adding a new callback function:
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
if let beaconRegion = region as? CLBeaconRegion, beaconRegion.uuid == Beacon.beaconUUID {
print("Hello There")
}
}
Which led to the same results of having no console output.
Many of the tutorials that I found seemed to be outdated or not written in swift and I know that the startRangingBeacons() function is already depreciated so I struggled to put random bits of information together. I would appreciate any help that you could give me.
A few things to check:
Use an off the shelf beacon scanner like Locate Beacon to confirm it can detect your transmitter. Be sure to configure your UUID with the iOS scanner app.
Go to settings -> apps -> your app -> permissions and confirm location permission is granted
Add debug lines or print statements when you start ranging and make sure you see them.
My App relies on checking user location upon start.
On iOS 16, when the user enables the Developer Mode on Privacy Settings they can simulate any location on the device using a GPX file.
The device actually changes the location of the device and most apps that I use actually think my location is the one on the GPX file.
Is there a way to make sure the location is the actual user location or a simulated one ?
Is there a public API to check if Developer Mode is enabled ?
Is there a way to tell the location comes from the GPX file ?
Even if the Developer mode is turned off it takes restarting the device to pick up the actual location again , so not sure if there is a different and better solution to this.
Thank you.
Apple provides sourceInformation on each CLLocation object returned. Checking the isSimulatedBySoftware parameter will give a boolean response.
Core Location sets isSimulatedBySoftware to true if the system generated the location using on-device software simulation. You can simulate locations by loading GPX files using the Xcode debugger. The default value is false.
The code below is a full functioning example that will turn the screen red if a simulated location is detected. I have confirmed that toggling simulated locations on/off in Xcode will make the screen turn from green to red and back again.
import UIKit
import CoreLocation
class ViewController: UIViewController {
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
// setup location monitoring
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
}
}
extension ViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// list of locations that are simulated
let simulatedLocations = locations.filter { $0.sourceInformation?.isSimulatedBySoftware == true }
view.backgroundColor = simulatedLocations.count > 0 ? .red : .green
}
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
guard manager.authorizationStatus == .authorizedAlways || manager.authorizationStatus == .authorizedWhenInUse else { return }
locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print(error.localizedDescription)
}
}
SITUATION:
I followed the following tutorial:
https://www.raywenderlich.com/95014/geofencing-ios-swift
PROBLEM:
The following functions never get triggered:
AppDelegate.swift
func locationManager(manager: CLLocationManager, didEnterRegion region: CLRegion) {
if region is CLCircularRegion {
handleRegionEvent(region)
}
}
func locationManager(manager: CLLocationManager, didExitRegion region: CLRegion) {
if region is CLCircularRegion {
handleRegionEvent(region)
}
}
func handleRegionEvent(region: CLRegion!) {
print("Geofence triggered!")
// Show an alert if application is active
if UIApplication.sharedApplication().applicationState == .Active {
if let message = notefromRegionIdentifier(region.identifier) {
if let viewController = window?.rootViewController {
showSimpleAlertWithTitle("Congratulations", message: "You just found: " + message , viewController: viewController)
}
}
} else {
// Otherwise present a local notification
let notification = UILocalNotification()
notification.alertBody = "You just found: " + notefromRegionIdentifier(region.identifier)!
notification.soundName = "Default";
UIApplication.sharedApplication().presentLocalNotificationNow(notification)
}
}
QUESTION:
The tutorial was written for iOS 8. I am currently on iOS 9.3. What caused this issue in your opinion and how do I fix it ?
You didn't show the code that you use to set up CL - which is probably where your problem lies.
Did you edit info.plist?
Are you requesting permission?
Did you call one of the start functions on the CL manager?
Make sure of two things :-
1.) You have added These to your viewDidLoad() :-
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.requestWhenInUseAuthorization()
locationManager.startMonitoringSignificantLocationChanges()
locationManager.startUpdatingLocation()
Another alternative to requestWhenInUseAuthorization() and startUpdatingLocation() initialisation in specific to Swift 2.2, since in Swift 2.2 the string literals for selectors is deprecated, and instead there this new operator #selector that you need to be using. :-
you can also use :-
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.startMonitoringSignificantLocationChanges()
if locationManager.respondsToSelector(#selector(locationManager.requestWhenInUseAuthorization)) {
locationManager.requestWhenInUseAuthorization()
}
else {
locationManager.startUpdatingLocation()
}
//Prefer the FIRST ONE.
2.) You have updated your info.plist with :-
NSLocationAlwaysUsageDescription : String :-> I need location.
NSLocationWhenInUseUsageDescription: String :-> I need location.
privacy - location usage description: String :-> I need location.
Edit I need location according to the app's need
PS :- If it still not calls your locationManager functions
Simulator :- look for location settings of your app in your simulator settings.
Device: - Go in settings > Privacy > Location services > Your app > Always.
you also might find this explanation useful : - https://stackoverflow.com/a/26090094/6297658
initialize your location manager in app delegate on did finish launching
Yeah ! My CoreLocation working now ! So i have a problem to store latitude and longitude and stopping locating.
I have a Sign In page (my MainVC)
before user sign in i need to get and store current device location and stop locating (now it's working with help of Alexander see under).
in my MainVC.swift i have this 2 global variables
var locationManager:CLLocationManager!
var myLocations = [CLLocation]()
in my viewDidLoad() i have this :
//Setup our Location Manager
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
For operate locationManager i have this 2 functions :
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("locations = \(locations)")
errorMsgIfInternetNotAvailable.text = "GPS success"
myLocations.append(locations.last!)
locationManager.stopUpdatingLocation()
}
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
errorMsgIfInternetNotAvailable.text = "Error while updating location " + error.localizedDescription
}
When i build my app, all working, if not autorise my device to get GPS informations i have the locationManager function error working.
If i autorise it
in console, the location update every second and don't stop it with the .stopUpdatingLocation() command
First, it is always good to provide the build error output. It's hard enough to guess which error you're getting.
It seems like you defined, but not initialized myLocations property. You have to do it like this:
var myLocations = [CLLocation]()
Notice the brackets () in initialization.
And then you have to add object to your array:
myLocations.append(locations.last)
or, if you want to store only one object in your array, do it like:
myLocations = [locations.last]
When implementing a CLLocationManager I came across a problem. Sometimes, when launching the app in the iPhone Simulator, it just doesn't fetch the current locations. But when I restart the app or it then suddenly works after 1-3 restarts. Restarting Xcode works too... Here's my code:
private var lat = 0.0;
private var long = 0.0;
private var didFindLocation = false
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if (status == .AuthorizedAlways) || (status == .AuthorizedWhenInUse) {
didFindLocation = false
locationManager.startUpdatingLocation()
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.last! as CLLocation
self.lat = location.coordinate.latitude
self.long = location.coordinate.longitude
if !didFindLocation {
print("\(self.lat) - \(self.long)")
didFindLocation = true
locationManager.stopUpdatingLocation()
}
}
As you can see, I've created a bool didFindLocation that allows me to fetch the location only once. I've put some breakpoints to see what's going on, and when the location doesn't get fetched, func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) doesn't even get called.
Thanks
iOS Simulator do not contains sensors like accelerometer, gyrometer etc, so we should not expect to work them on simulators. Besides this, for fetching a location, perhaps, it is using your system's internet.
So for a fair result it is advisable to use a real device for such cases.
From coding perspective, you can check for locationServicesEnabled property of CCLocationManager to see if this service is enabled or not.
This can happen on a simulator, but do add this method so that you get an error message of why it´s not working even though it´s on a simulator
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print(error.localizedDescription)
}
When you check location in simulator then first you need to point your simulator at some location.
Why?
Because simulator is not real time device first you need to point it at some position or location.
How you can do it?
There are two ways to do it.
1) select the simulator -> Goto debug -> select location -> select apple location.
Your location method called
Noto : if you select custom location from menu and enter your custom location then you need to restart your simulator (some time multiple times)
2) Goto xcode -> run your project -> in debug panel you find one location icon -> click on it -> it display location name -> select any place name
Note : Not necessary it worked all the times.