问题描述
我知道我不是唯一遇到此问题的人,
基本上,SwiftUI似乎无法请求位置总是,即使它位于info.plist中,您也必须稍后再对其进行调用(我已完成)。
我可以看到的问题是,人们不会将其从使用应用程序时更改为始终使用。
那么如何使后台处理器不断更新呢? -我看到Apple允许执行所有后台任务
我的信息.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundLeversion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Delivering location based Fuel Price Updates,Weather,News & Sports. As well as local offers.</string>
<key>NSLocationUsageDescription</key>
<string>Delivering location based Fuel Price Updates,News & Sports. As well as local offers.</string>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowScenesessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
</dict>
</array>
</dict>
</dict>
<key>uibackgroundmodes</key>
<array>
<string>audio</string>
<string>location</string>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIrequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UIStatusBarHidden</key>
<false/>
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
LocationServices.swift
//
// LocationManager.swift
// CoreLocationDemo
//
// Created by Sheikh Bayazid on 7/18/20.
// copyright © 2020 Sheikh Bayazid. All rights reserved.
//
import Foundation
import CoreLocation
import Combine
import UIKit
import SwiftUI
class LocationManager: NSObject,CLLocationManagerDelegate,ObservableObject {
private let manager: CLLocationManager
static var LMlat = 0.0
static var LMlong = 0.0
@Published var lastKNownLocation: CLLocation?
// var getLat: String {
// return "\(lastKNownLocation?.coordinate.latitude)"
// }
// var getLon: String {
// return "\(lastKNownLocation?.coordinate.longitude)"
// }
func locationManager(_ manager: CLLocationManager,didChangeAuthorization status: CLAuthorizationStatus) {
if status == .denied{
print("denied")
}
else{
print("athorized")
manager.requestLocation()
}
}
func start() {
//manager.requestAlwaysAuthorization()
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
}
init(manager: CLLocationManager = CLLocationManager()) {
self.manager = manager
super.init()
}
func locationManager(_ manager: CLLocationManager,didFailWithError error: Error) {
print(error.localizedDescription)
}
func startUpdating() {
self.manager.delegate = self
// self.manager.requestAlwaysAuthorization()
self.manager.requestWhenInUseAuthorization()
self.manager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager,didUpdateLocations locations: [CLLocation]) {
lastKNownLocation = locations.last
// print(lastKNownLocation!.coordinate.latitude)
self.manager.requestAlwaysAuthorization()
if(lastKNownLocation!.coordinate.latitude != LocationManager.LMlat && lastKNownLocation!.coordinate.longitude != LocationManager.LMlong)
{
print("Last KNown Location Is not a match")
LocationManager.LMlat = lastKNownLocation!.coordinate.latitude
LocationManager.LMlong = lastKNownLocation!.coordinate.longitude
updateServerLocation(latitude: LocationManager.LMlat,longitude: LocationManager.LMlong)
}
/* Maybe Use in Future Version
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: lastKNownLocation!.coordinate.latitude,longitude: lastKNownLocation!.coordinate.longitude)
geoCoder.reverseGeocodeLocation(location,completionHandler:
{
placemarks,error -> Void in
// Place details
guard let placeMark = placemarks?.first else { return }
// Location name
if let locationName = placeMark.location {
print(locationName)
}
// Street address
if let street = placeMark.thoroughfare {
print(street)
}
// City
if let city = placeMark.subAdministrativeArea {
print(city)
}
// Zip code
if let zip = placeMark.isoCountryCode {
print(zip)
}
// Country
if let country = placeMark.country {
print(country)
}
})
*/
//showLocation()
}
func updateServerLocation(latitude:Double,longitude:Double)
{
let locationurl = URL(string: "https://EXAMPLE.com/lat=\(latitude)&long=\(longitude)")!
//print(locationurl )
// print("location: \(MusicPlayer.uuid ?? "") lat: \(latitude),long: \(longitude)")
URLSession.shared.dataTask(with: locationurl) { (data,res,err) in
dispatchQueue.main.async{
// print("The Server should of updated")
// guard let data = data else { return }
}
return
}.resume()
}
// func showLocation(){
// print("From showLocation method")
// print("Latitude: \(getLat)")
// print("Longitude: \(getLon)")
// }
}
以及在我的ContentView.Swift
中 var lat: String{
return "\(location.lastKNownLocation?.coordinate.latitude ?? 0.0)"
}
var lon: String{
return "\(location.lastKNownLocation?.coordinate.longitude ?? 0.0)"
}
init() {
self.location.startUpdating()
}
解决方法
我建议您做一些事情来改善对位置的使用。
首先,您似乎对以下事实感到困惑:当您在iOS 13上请求“始终”位置许可时,实际上会提示用户“使用中”。在iOS 13.4上,您可以先请求(并接收)“使用中”,然后再询问“始终”来触发“始终”的提示。在某些情况下,这是正确的方法,但我认为您的应用不是其中之一。
您应该首先观看WWDC 2019上的What's new in Core Location。它说明了临时位置许可的工作原理。
查看您的代码,看来您正在尝试重新发明significant location change monitoring。 Core Location可以为您做到这一点,仅在用户移动500m或更多时才提供更新;听起来很适合您的用例。
另外,根据您的用例,我看不到您实际上需要ios13 +上的“ always”权限;您可以在启用背景模式的情况下使用“使用时”进行重要的位置更改监控。当用户停止音频流时,可以停止后台位置更新。您的应用没有充分的理由可以在用户不播放音频时访问其位置。
请注意,在iOS 12及更早版本中,您将需要“始终”许可,但是由于提到了SwiftUI,因此大概是最低支持的版本是iOS 13。
最后,对于Swift UI,应该在场景委托中创建一个LocationServices
之类的对象,并将其注入到环境中,而不是由视图创建。