Держите таймер и местоположение в фоновом режиме Swift - PullRequest
1 голос
/ 18 июня 2020

Я пытаюсь обновлять таймер и местоположение, пока приложение работает в фоновом режиме / телефон заблокирован.

Я пробовал несколько онлайн-решений, но пока ничего не помогло.

Мой код ниже:

class NewRunViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {

    let locationManager = CLLocationManager()
    let regionInMeters : Double = 200
    private var seconds = 0
    private var timer: Timer?
    private var distance = Measurement(value: 0, unit: UnitLength.meters)
    private var locationList: [CLLocation] = []
    var polyLine: MKPolyline = MKPolyline()

    @IBOutlet weak var MapView: MKMapView!
    @IBOutlet weak var DistanceLabel: UILabel!
    @IBOutlet weak var PaceLabel: UILabel!
    @IBOutlet weak var TimeLabel: UILabel!
    @IBOutlet weak var StartButtonLabel: UIButton!
    @IBOutlet weak var ResetButtonOutlet: UIButton!
    @IBOutlet weak var StopPauseButtonLabel: UIButton!
    @IBOutlet weak var bannerView4: GADBannerView!

    @IBAction func StartButton(_ sender: UIButton) {

        ResetButtonOutlet.isHidden = true
        StopPauseButtonLabel.isHidden = false
        StartButtonLabel.isHidden = true
        updateDisplay()
        timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in
          self.eachSecond()
        }
        startLocationUpdates()

        if CLLocationManager.authorizationStatus() == .authorizedAlways {
            MapView.showsUserLocation = true
        }

        else if CLLocationManager.authorizationStatus() == .authorizedWhenInUse {
            MapView.showsUserLocation = true
        }

        else {
           let alertController = UIAlertController(title: "Just to let you know...", message:
               "Your location services are not enabled, you can still use the timer but the distance and pace won't show without your location. You can enable location services in your device settings.", preferredStyle: .alert)
           alertController.addAction(UIAlertAction(title: "Dismiss", style: .default))

           self.present(alertController, animated: true, completion: nil)
        }

    }


    @IBAction func StopButtonLabel(_ sender: UIButton) {

        StopPauseButtonLabel.isHidden = true
        ResetButtonOutlet.isHidden = false
        locationManager.stopUpdatingLocation()
        StartButtonLabel.isHidden = false
        timer?.invalidate()
    }


    @IBAction func ResetButton(_ sender: UIButton) {

        StartButtonLabel.isHidden = false
        seconds = 0
        distance = Measurement(value: 0, unit: UnitLength.meters)
        locationList.removeAll()
        timer?.invalidate()
        updateDisplay()
        MapView.removeOverlays(MapView.overlays)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        checkLocationServices()
        timer?.invalidate()
        locationManager.stopUpdatingLocation()
        StopPauseButtonLabel.titleLabel?.adjustsFontSizeToFitWidth = true

        bannerView4.adUnitID = "ca-app-pub-6331942799423798/9472120281"
        bannerView4.rootViewController = self
        bannerView4.load(GADRequest())
        MapView.delegate = self
    }

    func setUpLocationManager() {
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
    }

    func centreViewOnUserLocation() {
        if let location = locationManager.location?.coordinate {
            let region = MKCoordinateRegion.init(center: location, latitudinalMeters: regionInMeters, longitudinalMeters: regionInMeters)
            MapView.setRegion(region, animated: true)
        }
    }

    func checkLocationServices() {
        if CLLocationManager.locationServicesEnabled() {
            setUpLocationManager()
            checkLocationAuthorisation()
        }

        else {
        let alertController = UIAlertController(title: "Just so you know...", message:
            "Sadly, your location services aren't enabled, change them in your settings to track your pace and distance.", preferredStyle: .alert)
        alertController.addAction(UIAlertAction(title: "Dismiss", style: .default))

        self.present(alertController, animated: true, completion: nil)
        }
    }

    func checkLocationAuthorisation() {
        switch CLLocationManager.authorizationStatus() {
        case.authorizedWhenInUse:
            MapView.showsUserLocation = true
            centreViewOnUserLocation()
            locationManager.startUpdatingLocation()
            break

        case.denied:
            let alertController = UIAlertController(title: "Just to let you know...", message:
                "Your location services are not enabled, you can still run but without your distance and pace. If you change your mind later you can enable location services in your device settings.", preferredStyle: .alert)
            alertController.addAction(UIAlertAction(title: "Dismiss", style: .default))
            self.present(alertController, animated: true, completion: nil)
            break

        case.notDetermined:
            locationManager.requestWhenInUseAuthorization()
            break

        case.restricted:
            let alertController = UIAlertController(title: "Just to let you know...", message:
                "Your location services are restricted, check your device settings.", preferredStyle: .alert)
            alertController.addAction(UIAlertAction(title: "Dismiss", style: .default))
            self.present(alertController, animated: true, completion: nil)
            break

        case.authorizedAlways:
            MapView.showsUserLocation = true
            centreViewOnUserLocation()
            locationManager.startUpdatingLocation()

        @unknown default:
            break
        }
      }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let location = locations.last else { return }
        let centre = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
        let region = MKCoordinateRegion.init(center: centre, latitudinalMeters: regionInMeters, longitudinalMeters: regionInMeters)
        MapView.setRegion(region, animated: true)

          for newLocation in locations {
            let howRecent = newLocation.timestamp.timeIntervalSinceNow
            guard newLocation.horizontalAccuracy < 20 && abs(howRecent) < 10 else { continue }

            if let lastLocation = locationList.last {
              let delta = newLocation.distance(from: lastLocation)
              distance = distance + Measurement(value: delta, unit: UnitLength.meters)

              let coordinates = [lastLocation.coordinate, newLocation.coordinate]
              MapView.addOverlay(MKPolyline(coordinates: coordinates, count: 2))
              let region = MKCoordinateRegion(center: newLocation.coordinate, latitudinalMeters: 200, longitudinalMeters: 200)
              MapView.setRegion(region, animated: true)
            }

              locationList.append(newLocation)
          }
    }
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        checkLocationAuthorisation()
    }

    func eachSecond() {
      seconds += 1
      centreViewOnUserLocation()
      updateDisplay()
    }

    private func updateDisplay() {
      let formattedDistance = FormatDisplay.distance(distance)
      let formattedTime = FormatDisplay.time(seconds)
      let formattedPace = FormatDisplay.pace(distance: distance,
                                             seconds: seconds,
                                             outputUnit: UnitSpeed.minutesPerMile)

        DistanceLabel.text = "Distance:  \(formattedDistance)"
        TimeLabel.text = "Time:  \(formattedTime)"
        PaceLabel.text = "Pace:  \(formattedPace)"
    }

    private func startLocationUpdates() {
      locationManager.delegate = self
      locationManager.activityType = .fitness
      locationManager.distanceFilter = 10
      locationManager.startUpdatingLocation()
        centreViewOnUserLocation()
    }

    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
      guard let polyline = overlay as? MKPolyline else {
        return MKOverlayRenderer(overlay: overlay)
      }
      let renderer = MKPolylineRenderer(polyline: polyline)
      renderer.strokeColor = .blue
      renderer.lineWidth = 3
      return renderer
    }
}
...