Continuation of the last time ↓ I tried to summarize the points to consider when acquiring location information with the iOS app ①
For those who haven't read the previous article, to briefly explain, when getting location information with the iOS app It is a summary of points to consider.
Last time, the check for location information service of the terminal
was done.
I wrote that only first launch
after installing the app is done.
If the location information service is off
at the first startup, this alert will be displayed ↓
This check is only for the first start
, so it has been modified to display an alert when starting the second and subsequent times ↓
This time, even when switching the app from background state
to foreground state
Let's check the location information service of the terminal
.
When the app switches from background state
to foreground state
To process to check the presence or absence of location-based services on the terminal
Use applicationWillEnterForeground (_ application: UIApplication) of AppDelegate
.
AppDelegate
is called is posted because this article was very easy to understand.
IOS App Life CycleAppDelegate.swift
//A method called when the app is about to enter the foreground state
func applicationWillEnterForeground(_ application: UIApplication)
However, I want to display an alert, so I want to process it in the view controller class.
Detecting that the state of the app has changed other than AppDelegate
If you want to do something, use the Notification Center (https://developer.apple.com/documentation/foundation/notificationcenter).
And this time as well, the alert will be displayed in this way ↓ Implement UIAlertController with separate files
ViewController
//Method called for background return, tab switching, etc. in addition to the initial display
//Avoid computationally expensive processing as the view is not yet visible
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//Notifications from iOS(UIApplication.willEnterForegroundNotification)Method received and registered(willEnterForeground)Call
NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
}
//Method called just before the screen disappears
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
//Classes that are constantly monitored(Common to apps, same feeling as UserDefault)So every time I call it, I delete it(Because it is prone to bugs)
//For example, using NavigationController to viewController1> 2 >Suppose that the screen transitions to 3 and all view controllers call NotificationCenter and write the willEnterForegroundNotification method.
//ViewController 1 even if the screen changes,2,3 does not disappear(Remains in memory)So
//When returning to the background in the screen of ViewController3, another ViewController1,2 also reacts, so you have to delete it every time
NotificationCenter.default.removeObserver(self, name: UIApplication.willEnterForegroundNotification, object: nil)
}
//Method called when returning from background state(Make it yourself)
@objc private func willEnterForeground() {
//When the location information service of the terminal is off when returning from the background state
if !CLLocationManager.locationServicesEnabled() {
//Alert display
Alert.okAlert(vc: self, title: "Location-based services\n Please turn it on", message: "You can turn it on from the "Settings" app ⇒ "Privacy" ⇒ "Location services"")
}
}
When I try to build it, an alert is displayed even when I return from the background state
↓
With this, the presence or absence of the location information service of the terminal is set to at startup
and when returning from the background state
You started to check.
After that, what you have to check is whether or not there is a location information service for the app
.
When you get the location information, you can't get it without getting permission from the user.
So the app will display an alert like this and ask the user for permission ↓
But what if the user chooses not allowed
?
For apps that require location information, you'll be in trouble if you don't get permission.
So if the user selects Do not allow
, an alert etc. will be displayed
You must prompt for permission to get the location information of the app
.
Let's take the previous source code as an example.
ViewController
import UIKit
import CoreLocation
private var locationManager: CLLocationManager = {
var locationManager = CLLocationManager()
locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
locationManager.distanceFilter = 5
return locationManager
}()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.requestWhenInUseAuthorization()
locationManager.delegate = self
}
extension ViewController: CLLocationManagerDelegate {
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
if CLlocationManager.locationServicesEnabled() {
let status = manager.authorizationStatus
switch status {
case .authorizedAlways, .authorizedWhenInUse:
manager.startUpdatingLocation()
case .notDetermined:
manager.requestWhenInUseAuthorization()
//If not allowed
case .denied:
//Show alerts to encourage you to turn on your app's location services
Alert.okAlert(vc: self, title: "The location information service of the app\n Please turn it on", message: "")
case .restricted:
break
default:
break
}
}else {
Alert.okAlert(vc: self, title: "Location-based services\n Please turn it on", message: "You can turn it on from the "Settings" app ⇒ "Privacy" ⇒ "Location services"")
}
}
}
If you select Do not allow
, the alert is displayed properly.
Even with this, I'm still urging the user to permit the location information of the app
.
Here, with a little more consideration, let's select the alert OK
and then move to the Settings app
.
As a merit of screen transition to the setting application
, permission to acquire the location information of the application
becomes smooth.
It saves the user the trouble.
The method of screen transition is posted because this article was easy to understand ↓ How to move to the setting screen with URL scheme using Swift5
Using this method, we will add it to the source code.
ViewController
import UIKit
import CoreLocation
private var locationManager: CLLocationManager = {
var locationManager = CLLocationManager()
locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
locationManager.distanceFilter = 5
return locationManager
}()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.requestWhenInUseAuthorization()
locationManager.delegate = self
}
extension ViewController: CLLocationManagerDelegate {
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
if CLLocationManager.locationServicesEnabled() {
let status = manager.authorizationStatus
switch status {
case .authorizedAlways, .authorizedWhenInUse:
manager.startUpdatingLocation()
case .notDetermined:
manager.requestWhenInUseAuthorization()
//If not allowed
case .denied:
//Show alerts to encourage you to turn on your app's location services
//In a message to make it easier for the user to understand, tell the setting app that the screen will change when you select OK.
Alert.okAlert(vc: self, title: "The location information service of the app\n Please turn it on", message: "Tap OK to go to the settings app") { (_) in
//After selecting OK, the screen transitions to the settings app
UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!, options: [:], completionHandler: nil)
}
case .restricted:
break
default:
break
}
}else {
Alert.okAlert(vc: self, title: "Location-based services\n Please turn it on", message: "You can turn it on from the "Settings" app ⇒ "Privacy" ⇒ "Location services"")
}
}
}
When I built this, the screen transitioned to the setting app
properly.
However, there are pitfalls here as well.
It's nice to go to the settings app this way Let's say you return without permission to get the location information of the app.
At this rate, the app will not check anything.
Again, when the app returns from the background state
You have to check whether or not the location information of the app is acquired
.
The article is going to be long again, so this time it ends here. I'm wrong here! If you have any questions, please feel free to comment.
Thank you for reading to the end! The source code so far is listed below ↓
ViewController
import UIKit
import CoreLocation
final class ViewController: UIViewController {
private var locationManager: CLLocationManager = {
var locationManager = CLLocationManager()
locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
locationManager.distanceFilter = 5
return locationManager
}()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.requestWhenInUseAuthorization()
locationManager.delegate = self
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self, name: UIApplication.willEnterForegroundNotification, object: nil)
}
@objc private func willEnterForeground() {
if !CLLocationManager.locationServicesEnabled() {
Alert.okAlert(vc: self, title: "Location-based services\n Please turn it on", message: "You can turn it on from the "Settings" app ⇒ "Privacy" ⇒ "Location services"")
}
}
}
extension ViewController: CLLocationManagerDelegate {
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
if CLLocationManager.locationServicesEnabled() {
let status = manager.authorizationStatus
switch status {
case .authorizedAlways, .authorizedWhenInUse:
manager.startUpdatingLocation()
case .notDetermined:
manager.requestWhenInUseAuthorization()
case .denied:
Alert.okAlert(vc: self, title: "The location information service of the app\n Please turn it on", message: "Tap OK to go to the settings app") { (_) in
UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!, options: [:], completionHandler: nil)
}
case .restricted:
break
default:
break
}
}else {
Alert.okAlert(vc: self, title: "Location-based services\n Please turn it on", message: "You can turn it on from the "Settings" app ⇒ "Privacy" ⇒ "Location services"")
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let gps = manager.location?.coordinate else {
return
}
manager.stopUpdatingLocation()
let lat = gps.latitude
let lng = gps.longitude
print("longitude:\(String(describing: lat)),latitude:\(String(describing: lng))")
}
}
Alert
import UIKit
final class Alert {
static func okAlert(vc: UIViewController,title: String, message: String, handler: ((UIAlertAction) -> Void)? = nil) {
let okAlertVC = UIAlertController(title: title, message: message, preferredStyle: .alert)
okAlertVC.addAction(UIAlertAction(title: "OK", style: .default, handler: handler))
vc.present(okAlertVC, animated: true, completion: nil)
}
}
Recommended Posts