swift 2 block the running of program if location is off - ios

I want to check and see if the location is on and if it's not or user didn't give permission to use location, app quits (won't run).
Is there a way to do this as people are saying using exit(0) is not recommended and will make Apple sad. :D

you could put a view onto the screen (full width and height) with a label that tells the user that it's only possible to use the app with location services enabled. of course the user should not be possible to interact with this view in any way.
here is an example helper class:
import UIKit
import CoreLocation
class LocationHelper: NSObject, CLLocationManagerDelegate {
private static let sharedInstance = LocationHelper()
private var locationManager: CLLocationManager! {
didSet {
locationManager.delegate = self
}
}
private override init() {}
class func setup() {
sharedInstance.locationManager = CLLocationManager()
}
private func informUserToEnableLocationServices() {
let infoPopup = UIAlertController(title: "Location Services", message: "Sorry, but you have to enable location services to use the app...", preferredStyle: .Alert)
let tryAgainAction = UIAlertAction(title: "Try again", style: .Default) { (action) in
if CLLocationManager.authorizationStatus() != .AuthorizedWhenInUse {
self.informUserToEnableLocationServices()
}
}
infoPopup.addAction(tryAgainAction)
let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate
let rootViewController = appDelegate?.window?.rootViewController
rootViewController?.presentViewController(infoPopup, animated: true, completion: nil)
}
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
switch status {
case .NotDetermined:
locationManager.requestWhenInUseAuthorization()
case .AuthorizedWhenInUse:
break
default:
informUserToEnableLocationServices()
}
}
}
simply call LocationHelper.setup() after the app launched and the class should handle the rest...

Apple does not like exit(0) for a reason. I would highly recommend not terminating the app yourself. Maybe you could let the user use the app with limited features? Another option would be to make an alert with no actions, or actions that don't do anything.

Related

Check if battery charging status changes in real time Swift

I want to check if my iphone is charging or not and what percentage. Im able to get the percentage fine as well as knowing if its plugged in or not when i start the app, however im not able ot make it change status as i unplug the charger. Essentially i want to be able plug and unplug the phone and have my Charge.text field change status from "charging" to "unplugged" and vice versa.
i implemented an alert box but that also only pops up when i start the app. ive got the core location in there because ive got an idea on implementing a location feedback thing, but its not used now, please just ignore that.
when searching the forums i seemingly only get answers on on how to check it once, not continuous updates. i dont know if the "real time" description helps but i didnt really know how to describe it. please help :)
import UIKit
import CoreLocation
import Alamofire
import SwiftyJSON
class ViewController: UIViewController, CLLocationManagerDelegate {
#IBOutlet weak var Charge: UILabel!
#IBOutlet weak var resultsField: UILabel!
var chargingVar = ""
var batteryLevel: Float {
return UIDevice.current.batteryLevel
}
func batteryStatus() {
UIDevice.current.isBatteryMonitoringEnabled = true
batteryStateChanged()
switch UIDevice.current.batteryState {
case .unknown:
self.Charge.text = "BATTERY: UNKNOWN!"
case .charging:
self.Charge.text = "Charging..."
case .full:
self.Charge.text = "BATTERY full"
case .unplugged:
self.Charge.text = "unplugged"
default:
self.Charge.text = "nope"
}
}
func batteryStateChanged(){
if (UIDevice.current.batteryState == .charging) { UIApplication.shared.isIdleTimerDisabled = true
self.chargingVar = "is charging. \u{1F603}"
chargingAlaer()
}else{
self.chargingVar = "is not charging. \u{1F622} "
chargingAlaer()
}
}
func chargingAlaer(){
let alertController = UIAlertController(title: "Charging Status",
message: "Your device \(chargingVar)",
preferredStyle: UIAlertController.Style.alert)
let ok = UIAlertAction(title: "OK",
style: UIAlertAction.Style.default,
handler: {(action) -> Void in
})
alertController.addAction(ok)
self.present(alertController, animated: true, completion: nil)
}
#objc func displayBatteryCharge() {
self.resultsField.text = "\(batteryLevel * 100)%"
}
override func viewDidLoad() {
super.viewDidLoad()
UIDevice.current.isBatteryMonitoringEnabled = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func viewDidAppear(_ animated: Bool) {
displayBatteryCharge()
batteryStatus()
}
}
Basically you did everything to display the current status, now you need to add something that is notified, or checks regularly for said status.
In this case, I believe the best way would be to register to the batteryStateDidChangeNotification notification, which is only sent by the system when isBatteryMonitoringEnabled is set to true, as you did in the viewDidLoad
I think adding
NotificationCenter.default.addObserver(
self,
selector: #selector(batteryStatus),
name: UIDevice.batteryStateDidChangeNotification,
object: nil
)
Should do the trick. In the viewDidLoad for instance.

How to change location permission message for iOS?

I'm learning iOS development and faced strange problem. To get user permission for using location in viewController I'm defining location manager and requesting requestWhenInUseAuthorization().
Like this:
class ViewController: UIViewController, CLLocationManagerDelegate {
let lm = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
lm.requestWhenInUseAuthorization()
}
}
Then, in plist I'm setting proper text for permission dialog, like this:
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>We need your location</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>We need your location</string>
<key>NSLocationUsageDescription</key>
<string>We need your location</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>We need your location</string>
Everything works fine till I'm trying to change text for permission dialog. After changing it in plist I'm recompiling it but nothing changes in the app, I'm receiving dialog with old text. So my question - how can I change it?
P.S. Xcode 10.3 & iOS 12.4
Go to the ViewController.swift file and add the following line to import the CoreLocation framework.
import CoreLocation
Conform the ViewController class to the CLLocationManagerDelegate protocol. Change the class declaration line to
class ViewController: UIViewController, CLLocationManagerDelegate {
Add the following property
let locationMgr = CLLocationManager()
The CLLocationManager is the object that will give you the GPS coordinates. Next, implement the getLocation(_:) method.
#IBAction func getLocation(_ sender: Any) {
// 1
let status = CLLocationManager.authorizationStatus()
switch status {
// 1
case .notDetermined:
locationManager.requestWhenInUseAuthorization()
return
// 2
case .denied, .restricted:
let alert = UIAlertController(title: "Location Services disabled", message: "Please enable Location Services in Settings", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(okAction)
present(alert, animated: true, completion: nil)
return
case .authorizedAlways, .authorizedWhenInUse:
break
}
// 4
locationManager.delegate = self
locationManager.startUpdatingLocation()
}
The authorizationStatus returns the current authorisation status.
The when in use authorisation get location updates while the app is in the foreground
When location services is disabled, the user will be shown an alert
Send location updates to the delegate, which is the View Controller.
Next, implement the CLLocationManager delegate methods.
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let currentLocation = locations.last {
print("Current location: \(currentLocation)")
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print(error)
}
The current location is printed to the console.
An Error is generated and displayed when the location can't get updated.
To enable the permissions for location updates while the app is running a special key is needed. Open info.plist. Right-click and select Add Row. Enter the following Values.
In Info.plist
<key>NSLocationWhenInUse</key>
<string>This app needs access to your Location</string>
Build and Run the project, When the app ask for permission
Looks like I've found where problem was. But firs things first. If you are trying to localize your app - read carefully what xcode asks you. In my case it was deleting Info.plist file from root directory when I tried to localize it, then (obviously) xcode informed me that it can't make a build because of it can't find Info.plist file (which was deleted from root directory).
Solution
Move Info.plist from Base.lproj directory;
Make as written in this article;
Keys in strings file should be exactly as they are named in system. This won't work:
"SomKey" = "We need you location";
But this would:
"NSLocationWhenInUseUsageDescription" = "We need you location";

ios, displaying an alert before everything else, to inform user we'll need "some" permissions

i'm developing an app. One of the firs thing i do (in AppDelegate) is to invoke OneSignal's initwithlaunchingoptions(...)
This automatically makes my app displays "App wants to send notifications", asking for permissions.
During my app lifecycle, i'll need other permissions from user (like calendar).
I'd like to display (BEFORE all the permissions) a brief AlertView explaining what i'll ask and why.
But how can i accomplish this if i can't move the OneSignal init from AppDelegate while my "explaining alert" happens only in viewDidLoad of the Main ViewController ?
Thanks.
Victor
here is an example of UIViewController that has information about applications needs location data, when user presses UIButton, it asks for permission. you can do alike for all permissions.
class LocationRequestViewController: UIViewController, CLLocationManagerDelegate {
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager.delegate = self
}
//when user authorised or denied ->push next `UIViewController`
func locationManager(_: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedWhenInUse || status == .denied {
let destinationVC = self.storyboard!.instantiateViewController(withIdentifier: "Notifications Request")
self.navigationController?.pushViewController(destinationVC, animated: true)
}
}
#IBAction func requestLocation(_: UIButton) {
self.locationManager.requestWhenInUseAuthorization()
}
}

Calling viewdidload and viewdidappear again

My app is a geolocation based app. I've implemented to pop up a UIAlertview as soon as some users press "Don't allow location service" button to guide them to settings again to turn on the service.
The problem I'm facing is that when user finally turns on the button, the data are not being loaded to the tableview since my data calling functions are in viewdidload and viewdidappear. Is there a way to call those functions again?
I did something like below and it totally crashes my app:
extension ExploreViewController: CLLocationManagerDelegate {
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
switch status {
case .Denied:
// Changed status to denied
self.locationAlert = UIAlertView(title: "Location Services Permission Needed", message: "Location service needs to be turned on to use Peek! Please press setting button below and turn the service on!", delegate: self, cancelButtonTitle: "Settings")
locationAlert.show()
break
case .AuthorizedWhenInUse:
self.viewDidLoad()
self.viewDidAppear(true)
break
default
break
}
When I was doing this way, it was kept calling viewdidload like million times before it crashed the app. Any advices are appreciated
Simply move your data calling functions outside of viewDidLoad and viewDidAppear:
Instead of
override func viewDidLoad() {
// do some stuff
}
write
override func viewDidLoad() {
super.viewDidLoad()
doSomeStuff()
}
func doSomeStuff() {
// do some stuff
}
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
// do your current logic
doSomeStuff()
}
Never never never never call viewDidLoad or viewDidAppear (except, in the latter case, to call super). They are messages sent by the runtime to you, to report stages in the life of the view controller.
func myCodeToRun() {
//put all the code you want to run here
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
myCodeToRun()
}
extension ExploreViewController: CLLocationManagerDelegate {
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
switch status {
case .Denied:
// Changed status to denied
self.locationAlert = UIAlertView(title: "Location Services Permission Needed", message: "Location service needs to be turned on to use Peek! Please press setting button below and turn the service on!", delegate: self, cancelButtonTitle: "Settings")
locationAlert.show()
break
case .AuthorizedWhenInUse:
myCodeToRun()
break
default
break
}

CLLocationManager authorization message

Hello i am using CLLocation to my app and i have initialise my CLLocationManager like this:
func initLocationManager(){
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
let authstate = CLLocationManager.authorizationStatus()
if(authstate == CLAuthorizationStatus.NotDetermined || authstate == CLAuthorizationStatus.Denied){
println("Not Authorised")
locationManager.requestWhenInUseAuthorization()
}
locationManager.startUpdatingLocation()
}
And i have also added the NSLocationAlwaysUsageDescription and NSLocationWhenInUseUsageDescription key to my plist.
The first time i open my app i get the prompt message that my app want to access location and it has 2 buttons allow and dont allow. if i click on the dont allow button and close the app, when i opened it again i dont get the prompt message again.
How can i make this prompt message to appear each time the user opens the app? Thank you
Prompting alert each time is not a valid approach.
For an alternative you can show alert only in that case when Location Service is
disabled or "Dont Allow" initially.
Following code promt alert at first and a custom alert when Location Service is Disabled
import UIKit
import CoreLocation
class ViewController: UIViewController,CLLocationManagerDelegate {
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
initLocationManager()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func initLocationManager(){
let status = CLLocationManager.authorizationStatus()
if(status == CLAuthorizationStatus.NotDetermined) {
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
let iosVersion = NSString(string: UIDevice.currentDevice().systemVersion).doubleValue
if iosVersion >= 8.0 {
//For Foreground
locationManager.requestWhenInUseAuthorization()
}
locationManager.startUpdatingLocation()
} else {
if(status != CLAuthorizationStatus.AuthorizedWhenInUse) {
var alert = UIAlertView(title: "Location", message: "Please turn on Location Services", delegate: nil, cancelButtonTitle: "Cancel")
alert.addButtonWithTitle("Open Setting")
alert.show()
/*Add Action on Open Setting alertbutton to directly open settings in iOS 8 and later
-> UIApplication.sharedApplication().openURL(NSURL(string: UIApplicationOpenSettingsURLString)!)*/
}
}
}
}
There is no way of doing it once the user declines, you have to show a dialog explaining to the user that he/she has to go to Settings and manually allow the functionality.
This message is asking for the permission to use GPS of your device and try to getting location of the device that's why GPS is much needed on. For second you don't want to show it you can make a condition with NSUseDefaults and store a key then don't call the method locationmanager startupdatinglocation. This is the only way to don't show it again otherwise it will show everytime.

Resources