繁体   English   中英

iOS13做一个后台处理器来更新位置

[英]iOS13 make a background processor to update location

我知道我不是唯一遇到这个问题的人,

Basiclly 似乎 SwiftUI 不能始终请求 Location 即使它在 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 &amp; Sports. As well as local offers.</string>
    <key>NSLocationUsageDescription</key>
    <string>Delivering location based Fuel Price Updates, Weather, News &amp; 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>


位置服务.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的 Core Location 中的新增功能。它解释了临时 - 始终位置权限的工作原理。

查看您的代码,您似乎正在尝试重新发明significant location change monitoring Core Location 可以为您做到这一点,仅当用户移动了 500 米或更远时才提供更新; 这听起来很适合您的用例。

另外,根据您的用例,我看不到您实际上需要 ios13+ 的“始终”权限; 您可以在启用后台模式的情况下使用“使用时”进行重要的位置更改监控。 您可以在用户停止音频 stream 时停止后台位置更新; 当用户不播放音频时,您的应用没有充分的理由访问用户的位置。

请注意,在 iOS 12 及更早版本中,您需要请求“始终”许可,但由于您提到了 SwiftUI,因此大概 iOS 13 是您支持的最低版本。

最后,关于 Swift UI,应该在您的场景委托中创建一个 object 之类的LocationServices并注入到环境中,而不是由视图创建。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM