[SWIFT] I tried to summarize the points to consider when acquiring location information with the iOS application ②

Continuation of the last time ↓ I tried to summarize the points to consider when acquiring location information with the iOS app ①

Introduction

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.

Synopsis up to the last time

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.

Check when returning from the background state (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.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 stateezgif.com-gif-maker.gif 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.

Check for the location information service of 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.

Screen transition 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. ezgif.com-gif-maker2.gif

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 ↓

Source code

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

I tried to summarize the points to consider when acquiring location information with the iOS application ③
I tried to summarize the points to consider when acquiring location information with the iOS application ①
I tried to summarize the points to consider when acquiring location information with the iOS application ②
I tried to summarize iOS 14 support
I tried to summarize the methods used
I tried to summarize the Stream API
[iOS] I tried to make a processing application like Instagram with Swift
I tried to summarize the key points of gRPC design and development
I tried to manage login information with JMX
[JavaScript] The strongest case when I tried to summarize the parts I do not understand
I tried to summarize the state transition of docker
I tried to modernize a Java EE application with OpenShift.
I tried to increase the processing speed with spiritual engineering
I tried to summarize the basics of kotlin and java
I tried to summarize the basic grammar of Ruby briefly
I tried upgrading from CentOS 6.5 to CentOS 7 with the upgrade tool
When I tried to scroll automatically with JScrollBar, the event handler was drawn only once.
I tried to solve the problem of "multi-stage selection" with Ruby
I tried to summarize the words that I often see in docker-compose.yml
I tried to summarize what was asked at the site-java edition-
[Ruby] Tonight, I tried to summarize the loop processing [times, break ...]
I tried to implement the image preview function with Rails / jQuery
Special Lecture on Multi-Scale Simulation: I tried to summarize the 5th
I tried to interact with Java
I tried to explain the method
[Rails] I tried deleting the application
Special Lecture on Multi-Scale Simulation: I tried to summarize the 8th
I tried to make an Android application with MVC now (Java)
I tried to check the operation of gRPC server with grpcurl
I tried to summarize the methods of Java String and StringBuilder
I tried to summarize Java learning (1)
I tried to summarize Java 8 now
Special Lecture on Multi-Scale Simulation: I tried to summarize the 7th
I tried to figure out the flow when performing image analysis with Vision Framework and Core ML
[IOS] What to do when the image is filled with one color
I summarized the points to note when using resources and resources in combination
Problems I was addicted to when building the digdag environment with docker
[Ruby] I tried to diet the if statement code with the ternary operator
I tried to build a Firebase application development environment with Docker in 2020
I tried to solve the tribonacci sequence problem in Ruby, with recursion.
I tried to visualize the access of Lambda → Athena with AWS X-Ray
[After learning Progate] I tried to summarize form_with while comparing with form_tag
[Ruby] I tried to summarize the methods that frequently appear in paiza
[Ruby] I tried to summarize the methods that frequently appear in paiza ②
I tried to measure and compare the speed of GraalVM with JMH
I tried to publish the reflex measurement application on the Google Play store
I tried to summarize Java lambda expressions
I tried to get started with WebAssembly
I tried to implement the Iterator pattern
What is Docker? I tried to summarize
I tried to implement ModanShogi with Kinx
I tried to make a machine learning application with Dash (+ Docker) part3 ~ Practice ~
What I tried when I wanted to get all the fields of a bean
Points I stumbled upon when creating an Android application [Updated from time to time]
I tried to compare the infrastructure technology of engineers these days with cooking.
I tried to get the distance from the address string to the nearest station with ruby
I tried to summarize again the devise that was difficult at first sight
[Rails] When transitioning to a page with link_to, move to the specified location on the page
I tried to clone a web application full of bugs with Spring Boot
When I tried to use a Wacom tablet with ubuntu 20.04, I didn't recognize it.
I tried to summarize about JVM / garbage collection