Xcode15中SwiftUI新Map API的UserAnnotation功能失效求助
解决MapKit SwiftUI中UserAnnotation获取位置失败(kCLErrorDomain Code=1)的问题
问题描述
参照WWDC2023《Meet MapKit for SwiftUI》教程,在Xcode15中使用_MapKit_SwiftUI框架的UserAnnotation()获取模拟器用户位置时功能失效,点击定位按钮后界面无限缓冲,报错:
CLLocationManager(<CLLocationManager: 0x600000010b20>) for <MKCoreLocationProvider: 0x600003000c60> did fail with error: Error Domain=kCLErrorDomain Code=1 "(null)"
已完成操作:
- Info.plist中添加
Privacy - Location Always Usage Description和Privacy - Location Always and When In Use Usage Description权限 - 已设置模拟器位置
解决方案
1. 补充缺失的核心权限键
iOS 17+中,仅添加Always相关权限不足以支持前台位置请求,必须在Info.plist中补充**Privacy - Location When In Use Usage Description**键。requestWhenInUseAuthorization()依赖该描述,缺少会导致授权请求不触发,直接返回权限拒绝(对应Code=1错误)。
2. 修复CLLocationManager生命周期问题
当前代码在onAppear中创建的CLLocationManager是局部变量,会被立即销毁,无法正常处理权限请求和位置更新。需将其声明为视图的持久化属性:
@StateObject private var locationManager = CLLocationManager()
然后在onAppear中发起权限请求:
.onAppear { locationManager.requestWhenInUseAuthorization() // 若需后台位置权限,可在用户授权前台后再请求: // if locationManager.authorizationStatus == .authorizedWhenInUse { // locationManager.requestAlwaysAuthorization() // } }
3. 重置模拟器权限缓存
模拟器可能缓存旧的权限设置,导致新配置不生效:
- 关闭模拟器
- 执行终端命令:
xcrun simctl erase all(会清除所有模拟器数据,注意备份) - 重新打开模拟器并运行App,重新授权位置权限
4. 优化权限请求逻辑
避免同时调用requestAlwaysAuthorization()和requestWhenInUseAuthorization(),这会导致权限请求冲突。根据App需求选择其一:
- 仅前台使用位置:只调用
requestWhenInUseAuthorization(),确保对应权限描述已添加 - 需要后台位置:先请求前台权限,用户授权后再请求后台权限,且两个权限描述都要配置
代码修改示例(CustomMapViewLookAround.swift)
import SwiftUI import _MapKit_SwiftUI @available(iOS 17.0, *) struct CustomMapViewLookAround: View { @State private var position: MapCameraPosition = .automatic @State private var visibleRegion: MKCoordinateRegion? @State var route: MKRoute? @State var searchResults: [MKMapItem] = [] @State private var selectedResult: MKMapItem? @StateObject private var locationManager = CLLocationManager() // 新增持久化管理对象 func getDirections() { print("results count: \(searchResults.count)") route = nil guard let selectedResult else { return } let request = MKDirections.Request() request.source = MKMapItem(placemark: MKPlacemark(coordinate: .parking)) request.destination = selectedResult Task { let directions = MKDirections(request: request) let response = try? await directions.calculate() route = response?.routes.first } } var body: some View { Map(position: $position, selection: $selectedResult) { Annotation("Parking", coordinate: .parking) { ZStack { RoundedRectangle(cornerRadius: 5) .fill(.background) RoundedRectangle(cornerRadius: 5) .stroke(.secondary, lineWidth: 5) Image(systemName: "car") .padding(5) } } .annotationTitles(.hidden) ForEach(searchResults, id: \.self) { result in Marker(item: result) } .annotationTitles(.hidden) if let route { MapPolyline(route) .stroke(.blue, lineWidth: 5) } UserAnnotation() } .mapStyle(.standard) .safeAreaInset(edge: .bottom) { HStack { Spacer() VStack(spacing: 0) { if let selectedResult { ItemInfoView(route: route, selectedResult: selectedResult) .frame(height: 128) .clipShape(RoundedRectangle (cornerRadius: 10)) .padding([.top, .horizontal]) } BeantownButtons(searchResults: $searchResults, position: $position, visibleRegion: visibleRegion) .padding(.top) } Spacer() } .background(.thinMaterial) } .onChange(of: searchResults) { position = .automatic } .onMapCameraChange { context in visibleRegion = context.region } .onChange(of: selectedResult) { getDirections() } .mapControls { MapUserLocationButton() MapCompass() MapScaleView() } .onAppear { locationManager.requestWhenInUseAuthorization() } } } #Preview { if #available(iOS 17.0, *) { CustomMapViewLookAround() } else { EmptyView() } }
内容的提问来源于stack exchange,提问作者S. S. Saruar Jahan
相关产品推荐
相关产品推荐

