I activate the conditions as follows
Unexpected operation found. Details are below
Conditions and configurations used in the testing
"Background Modes" Capability with "Location updates" checked on
added the info.plist keys: NSLocationAlwaysAndWhenInUseUsageDescription, NSLocationWhenInUseUsageDescription with description
monitoring for several beacon regions and invoking startMonitoringSignificantLocationChanges using core location API
My app’s location authorization status set ‘WhenInUse’
add UserNotification in func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool. For that reason, If every app launches, a notification will be triggered in AppDelegate method
Given the condition above applied, What I expect is that if the location permission is 'when in use', if I leave the app by swiping(I have not closed my application by force using "swiping up in the app-switcher screen"), the app will be suspended in the background after 30 seconds.
However, on specific iOS(iOS 16.5.1~ iOS 17.1.2), when I bring the app to the background, the didUpdateLocation function continues to run. I confirmed that the location was updated for over an hour.
Other iOS didn’t occur the issue under iOS 16.3.1.(Couldn't confirm 16.4)
I wonder if this is normal operation.
In addition, I also want to know why it is working differently between iOS versions.
Thanks for your help in advance.
Maps & Location
RSS for tagLearn how to integrate MapKit and Core Location to unlock the power of location-based features in your app.
Post
Replies
Boosts
Views
Activity
Hi experts,
I got an Ultra2 a while ago and has been using it on walking / running exercise.
Recently I came across to this apple site: debug profile and I'm curious about what I would get during the exercise.
So I follow the instruction and install the location services profile. After getting the sysdiagnose report, I try to get location related information from it. And it seems that the log from "locationd" and "gpsd" are what I'm looking for.
But when I try to look into the nmea information, I found out the sysdiagnose only provide around 10-15 mins of nmea data.
For example, let's say I have a walking exercise from 0900 - 1000, but I can only see nmea data from 0945 - 1000. The data from 0900 to 0945 can't be found in the sysdiagnose.
Not sure if's the limitation or any setting I can change to increase the logging period?
Thanks.
I have a code that redirects the user to Google Maps or Apple Maps by pressing the map , when Apple Maps is uninstalled, an alert appears asking the user to download Apple Maps and redirects the user to the App Store, when I select Show in App Store, the user is redirected to App Store, and then the alert is shown again.
func openMaps() {
let coordinate = CLLocationCoordinate2D(latitude: 52.5162746, longitude: 13.3755153)
let mapItem = MKMapItem(placemark: MKPlacemark(coordinate: coordinate))
mapItem.name = "Test"
mapItem.openInMaps(launchOptions: [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDefault])
}
Hi, based on https://developer.apple.com/help/account/configure-app-capabilities/create-a-maps-identifier-and-private-key described, I need to create an Identifier before I can create JWT for MapKit JS. However, I cannot find Maps Ids checkbox when I attempt to set up first MapKit JS access.
In SwitUI when using a map within a tabview the tab bar color is translucent when the map tab is selected. All of the other tabs the tab bar is opaque. In the view that contains the map, if the map is commented out the tab display is opaque, only when the map is displayed.
I have an init in the tabview to set the tab bar parameters:
// Set Tab Bar appearance
let tabbarAppearance = UITabBarAppearance()
tabbarAppearance.configureWithOpaqueBackground()
tabbarAppearance.backgroundColor = .blue
UITabBar.appearance().standardAppearance = tabbarAppearance
UITabBar.appearance().scrollEdgeAppearance = tabbarAppearance
In the view with the map I use a ZStack to set the entire screen color:
ZStack(alignment: Alignment(horizontal: .center, vertical: .top)) {
Color(.blue)
.ignoresSafeArea(.all)
.foregroundColor(.black)
VStack(alignment: .center, spacing: 5) {
Spacer()
Map()
Spacer()
}
}
I've tried using .padding(), frame, removing ignoresSafeArea but the tab bar still becomes translucent when the tab is selected. Selecting another tab the color becomes opaque.
Any suggestions on how to correct this behavior so the tab bar is opaque for all tabs?
Regardless of how much information is provided to the Maps searchAutoComplete API, the response field structuredAddress is always null. This means I have to call the completionUrl afterwards to get a structured address. This consumes our quota and causes unnecessary Maps traffic.
Example request, autocompleting "450 Post St, San Francisco":
https://maps-api.apple.com/v1/searchAutocomplete?
q=450%20Post%20St%2C%20San%20Francisco
&resultTypeFilter=Address
&limitToCountries=US
&lang=en-US
responds 2 results with the actual address found, but each having only these fields:
- completionUrl
- displayLines
- location
Example:
{
"results": [
{
"completionUrl": "/v1/search?q=450%20Post%20St%20San%20Francisco%2C%20CA%2C%20United%20States&metadata=Ch8KCzQ1MCBQb3N0IFN0EgQIABADEgQIBBAEEgQICRACEjQKIFNhbiBGcmFuY2lzY28sIENBLCBVbml0ZWQgU3RhdGVzEgQIGhACEgQIABADEgQIBBAJGAIyRgoSCQAAAEDg5EJAEQAAAOA9ml7AEM6h0aK1wfKqciA5KQAAAAAAAHlAgvEEAzQ1MIjxBDGa8QQCVVOg8QQAsvEEALrxBABiHAoaNDUwIFBvc3QgU3QsIFNhbiBGcmFuY2lzY2%2BC8QQaNDUwIFBvc3QgU3QsIFNhbiBGcmFuY2lzY2%2BI8QQA2vEEFgkAAABAEf3IQBkAAAAAAAAAACABKAPq8QQAkPIEAQ%3D%3D",
"displayLines": [
"450 Post St",
"San Francisco, CA, United States"
],
"location": {
"latitude": 37.78809356689453,
"longitude": -122.41002655029297
}
},
{
"completionUrl": "/v1/search?q=450%20Post%20St%20Napa%2C%20CA%2C%20United%20States&metadata=****",
"displayLines": [
"450 Post St",
"Napa, CA, United States"
],
"location": {
"latitude": 38.30093002319336,
"longitude": -122.27799224853516
}
}
]
}
Anyone figured this out? Seems buggy to me.
Is it free to use MapKit's MKLocalSearchCompleter and MKLocalSearch on iOS currently?
I would like to use them for getting geocode.
I found this forum.
https://developer.apple.com/forums/thread/127493
According to this forum, using MapKit for native app development, there is no cost beyond my Apple Developer Program membership.
Is it the same now?
sincerely
Does the API: https://maps-api.apple.com/v1/directions currently not support public transportation queries, such as subway routes?
If have a custom type (hashable) for map selection:
@State var mapSelection: CustomType
Map(selection: $mapSelection ) {
...
}
However, if I want to selet MapFeature, I need to use MapFeature type for the state variable
@State var mapSelection: MapFeature
But I want to display some Markers by using my CustomType. MapFeature can't be initialized so that I can't map my CustomType to MapFeature to display my Markers.
Is there a way to select MapFeature by custom type?
Hello,
I'm looking for an end-to-end example project that shows a correct implementation for the new iBeacon CoreLocation APIs in iOS 17.0 (CLMonitor, etc.). Ideally the example would cover background waking as that is the area in which I am facing the largest challenges.
Perhaps there's an Open Source project or an official Apple example?
Thanks for pointing me in the right direction.
Jeremy
This is my setup:
Granted always allow permission.
I have location added in UIBackgroundModes, but I did NOT set allowsBackgroundLocationUpdates to true
Note: I have this allowsBackgroundLocationUpdates = true set in my earlier version of app, which worked but we noticed it drained battery much faster, hence we removed all the settings that could affect battery.
The location model is setup with 20 regions, when boundary crossing happen, app sends a local notification. This works fine when app is in foreground/background. If app is killed, the app receives notification for boundary crossing only once.
Failed case for region monitoring:
Setup region monitoring
Kill the app
cross the boundary, app sends a local notification.
wait for 1 hour
leave the device in same state (notification is not opened, app is still killed state)
cross the boundary again
expect a notification, but app did not register any event related to region monitoring.
The console logs did not print anything in this second case.
public class LocationViewModel: NSObject, ObservableObject {
private let maxMonitoredRegions = 20
private var anyCancellable: AnyCancellable?
private let locationManager: CLLocationManager
@Published public var authorizationStatus: CLAuthorizationStatus
@Published public var isMonitoringAvailable: Bool
@Published public var monitoredRegions: [Region]
@Published public var recentLocation: CLLocation?
public var newlyEnteredRegionSignal = PassthroughSubject<CLRegion, Never>()
public var recentLocationSignal = PassthroughSubject<CLLocation, Never>()
public var authorizationStatusPublisher: Published<CLAuthorizationStatus>.Publisher { $authorizationStatus }
public var isLocationEnabled: Bool {
locationManager.authorizationStatus == .authorizedWhenInUse ||
locationManager.authorizationStatus == .authorizedAlways
}
public override init() {
locationManager = CLLocationManager()
authorizationStatus = locationManager.authorizationStatus
isMonitoringAvailable = CLLocationManager.isMonitoringAvailable(for: CLCircularRegion.self)
monitoredRegions = []
super.init()
locationManager.delegate = self
monitoredRegions.append(contentsOf: getMonitoredRegions())
requestLocation()
}
public func requestLocation() {
locationManager.requestLocation()
}
public func startRegionMonitoring(regions: [CLRegion]) {
guard isMonitoringAvailable else {
return
}
stopRegionMonitoring()
if regions.isEmpty {
return
}
if regions.count <= 20 {
for region in regions {
locationManager.startMonitoring(for: region)
}
} else {
for region in regions[0...maxMonitoredRegions-1] {
locationManager.startMonitoring(for: region)
}
}
}
public func stopRegionMonitoring() {
guard isMonitoringAvailable else {
return
}
if monitoredRegions.isEmpty {
return
}
for region in monitoredRegions {
let monitoredRegion = LocationUtils.convertRegionToCLRegion(region)
locationManager.stopMonitoring(for: monitoredRegion)
}
monitoredRegions.removeAll()
}
private func getMonitoredRegions() -> [Region] {
let monitoredRegions = locationManager.monitoredRegions
var regions = [Region]()
for monitoredRegion in monitoredRegions {
if let region = LocationUtils.convertCLRegionToRegion(monitoredRegion) {
regions.append(region)
}
}
return regions
}
public func stopMonitoring() {
recentLocation = nil
stopRegionMonitoring()
}
}
extension LocationViewModel: CLLocationManagerDelegate {
public func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
authorizationStatus = manager.authorizationStatus
switch authorizationStatus {
case .notDetermined:
stopMonitoring()
case .denied:
stopMonitoring()
case .authorizedAlways:
break
case .authorizedWhenInUse:
// If user has requested whenInUse, request for always allow.
locationManager.requestAlwaysAuthorization()
@unknown default:
break
}
if let location = manager.location {
recentLocationSignal.send(location)
recentLocation = location
}
}
public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let recentLocation = locations.last {
self.recentLocation = recentLocation
recentLocationSignal.send(recentLocation)
}
}
public func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
}
public func locationManager(_ manager: CLLocationManager, didStartMonitoringFor region: CLRegion) {
if let monitoredRegion = LocationUtils.convertCLRegionToRegion(region) {
let oldRegion = monitoredRegions.first {
$0.identifier == monitoredRegion.identifier
}
if oldRegion == nil {
monitoredRegions.append(monitoredRegion)
}
}
}
public func locationManager(_ manager: CLLocationManager, monitoringDidFailFor region: CLRegion?, withError error: Error) {
}
public func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
newlyEnteredRegionSignal.send(region)
}
public func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
newlyEnteredRegionSignal.send(region)
}
}
When app is awaken due to location event on app delegate, we initialize this location model, and location manager, and remove old monitored regions, and call startMonitoringRegions again, to keep the regions updated.
Please let me know if I'm missing any crucial information.
@MainActor
perform() async throws -> some IntentResult {
// ...
switch locationManager.authorizationStatus {
case .denied, .restricted:
throw UserLocationError.permissionDenied
case .notDetermined:
await locationManager.requestWhenInUseAuthorization() // to ask permission
default:
break
}
// ...
}
Here is my code.
When the authorizationStatus is .notDetermined,
it invokes requestWhenInUseAuthorization() method on the main thread,
but throws UserLocationError.permissionDenied immediately, eventhough I didn't deny the permission.
It's really weird and unexpected that it throws UserLocationError.permissionDenied when the status is not .denied or .restricted
Even it invokes requestWhenInUseAuthorization(), there's no alert for asking permission
If there's any solution, please let me know
I am working on a virtual simulator for iOS 17 from my macbook.
I want to have the initial view present the Map but zoomed out enough so that it's basically showing the whole world - in a 3d render.
My understanding is that as of iOS17 if you have .standard for the MKMapView type, it should still render as 3D if the altitude is high enough. But on my simulator, I literally cannot zoom out any further.
Is the right protocol to update the mapType to be .hybridFlyover? That seems different than the .standard (which I think is what I actually want).
Does anyone have any idea / is there anything sticking out in this code?
Here is my code:
struct GlobeView: UIViewRepresentable {
var coordinates: [IdentifiableCoordinate]
func makeUIView(context: Context) -> MKMapView {
let mapView = MKMapView()
mapView.mapType = .hybridFlyover
mapView.delegate = context.coordinator
let camera = MKMapCamera(lookingAtCenter: CLLocationCoordinate2D(latitude: 0, longitude: 0), fromDistance: 1_000_000_000, pitch: 0, heading: 0)
mapView.setCamera(camera, animated: true)
return mapView
}
func updateUIView(_ uiView: MKMapView, context: Context) {
let annotations = coordinates.map { coordinate -> MKPointAnnotation in
let annotation = MKPointAnnotation()
annotation.coordinate = coordinate.coordinate
return annotation
}
uiView.addAnnotations(annotations)
}
class Coordinator: NSObject, MKMapViewDelegate {
var parent: GlobeView
init(_ parent: GlobeView) {
self.parent = parent
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
}
Hi, I'm a college student in Hangzhou, China. I want to learn and develop with Find My Network and other useful Apple's tech. But when I access the application website, I can't find the university entrance but only with company.
Can I develop as a college student? Where can I be? Or in the same page, what's the DUNS numbers?
If only corps can, what's the fee to get the DUNS numbers with Apple's support? What's the fee to join in Apple Developments? Should I offer some documents such as Bank Corporate Account Statement? If I create a new corp to join in the development, what should I or corp need and do?
I just wanna develop a school ID card with UWB tech and Apple's useful Find My Network. Hope to get your's help.
Have a good day. Thanks!
In m1 MACs run
sudo arch -x86_64 pod install --allow-root
to resolve this issue.
I need multiple MKTileOverlays with multiple blendModes. Apparently using an overlay with a different blend causes the layer under to use the same blend mode.
For the example below, using a normal blend mode on top of a soft light blend mode causes a normal blend mode to be used instead of soft light. The soft light layer is rendered as expected until the normal layer is displayed starting at zoom level 15.
First, I've subclassed MKTileOverlay to add an overlay type so that the correct renderer is provided per overlay. (I know there is a title, but I prefer this)
enum OverlayType {
case softLight,
normal
}
class TileOverlay: MKTileOverlay {
var type: OverlayType = .normal
}
Then setup layers and renderers in the typical fashion:
var softLightRenderer: MKTileOverlayRenderer!
var normalRenderer: MKTileOverlayRenderer!
private func setupSoftlightRenderer() {
let overlay = TileOverlay(urlTemplate: "http://localhost/softlight/{z}/{x}/{y}")
overlay.type = .softLight
overlay.canReplaceMapContent = false
overlay.minimumZ = 9
overlay.maximumZ = 20
mapView.addOverlay(overlay, level: .aboveLabels)
softLightRenderer = MKTileOverlayRenderer(tileOverlay: overlay)
tileRenderer.blendMode = .softLight
}
private func setupNormalRenderer() {
let overlay = TileOverlay(urlTemplate: "http://localhost/normal/{z}/{x}/{y}")
overlay.type = .normal
overlay.canReplaceMapContent = false
overlay.minimumZ = 15
overlay.maximumZ = 20
mapView.addOverlay(overlay, level: .aboveLabels)
normalRenderer = MKTileOverlayRenderer(tileOverlay: overlay)
normalRenderer.blendMode = .normal
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
if let overlay = overlay as? TileOverlay {
switch overlay.type {
case .softLight:
return softLightRenderer
case .normal:
return normalRenderer
}
}
print("Warning: using unhandled overlay renderer")
return blankRenderer
}
override func viewDidLoad() {
...
setupSoftlightRenderer()
setupNormalRenderer()
}
Interestingly, if I put the overlays at two different levels, one .aboveLabels and another .aboveRoads it works as expected. The problem is that limits me to two different overlay blend modes. I really could use more than two. I tried every possible variation of inserting the layers at different indexes and methods, but the only two that seem to work are the .aboveLabels and .aboveRoads.
How can I use more than two different blend modes?
This post states that attribution is required for MapKit or violates the developer agreement.
Can I provide my own attribution if I am displaying my original map content? It seems bizarre to attribute map sources that are not used.
Hi All,
I need user continues location event if app in background and terminated (Not-running) mode
below is the code I'm using to get the location but still I'm not get the location continuously
import BackgroundTasks
import UIKit
class AppDelegate: UIResponder, UIApplicationDelegate {
var significatLocationManager: CLLocationManager?
func startSignificationLocation() {
self.significatLocationManager = CLLocationManager()
self.significatLocationManager?.delegate = self
self.significatLocationManager?.activityType = .fitness
self.significatLocationManager?.distanceFilter = 10
self.significatLocationManager?.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
self.significatLocationManager?.allowsBackgroundLocationUpdates = true
self.significatLocationManager?.pausesLocationUpdatesAutomatically = false
self.significatLocationManager?.startUpdatingLocation()
self.significatLocationManager?.startMonitoringSignificantLocationChanges()
self.significatLocationManager?.requestAlwaysAuthorization()
}
func stopAllRegionMonitoring(locationManager:CLLocationManager?){
for delRegion in (locationManager?.monitoredRegions ?? []){locationManager?.stopMonitoring(for: delRegion)}
}
}
extension AppDelegate: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
self.myLocation = locations.last
//call update My Location API
if (self.myLocation?.horizontalAccuracy ?? 0.0) <= (self.liveLocationTrackingRegionRadius + 15.0 ){
self.createRegion(location: self.myLocation)
} else {
manager.stopUpdatingLocation()
manager.startUpdatingLocation()
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {}
func locationManagerDidPauseLocationUpdates(_ manager: CLLocationManager) {
manager.startUpdatingLocation()
}
func locationManagerDidResumeLocationUpdates(_ manager: CLLocationManager) {
manager.startUpdatingLocation()
}
}
extension AppDelegate {
func createRegion(location:CLLocation?, type:LocationRegionMonitoringTyep = .LiveLocationTracking) {
if self.significatLocationManager == nil {
self.startSignificationLocation()
}
guard let location = location else { return }
guard CLLocationManager.isMonitoringAvailable(for: CLCircularRegion.self) else{ return }
var identifier:String = "Live_Location_Tracking-" + "\(location.coordinate.latitude)" + "-" + "\(location.coordinate.longitude)"
if (self.significatLocationManager?.monitoredRegions.count ?? 0) > 10 {
self.stopAllRegionMonitoring(locationManager: self.significatLocationManager)
}
var region : CLCircularRegion?
region = CLCircularRegion(center: CLLocationCoordinate2D(latitude: location.coordinate.latitude,longitude: location.coordinate.longitude),radius: 10.0 ,identifier: identifier)
region?.notifyOnExit = true
self.significatLocationManager?.startUpdatingLocation()
if let reg = region {
self.significatLocationManager?.startMonitoring(for: reg)
}
}
func stopAllRegionMonitoring(locationManager:CLLocationManager?){
let WOMRequestId:String? = UserDefaultManager.shared.womEmergencyDetails?.data?.request?.id
for delRegion in (locationManager?.monitoredRegions ?? []){
if let reqId = WOMRequestId {
if delRegion.identifier.contains(reqId) {
locationManager?.stopMonitoring(for: delRegion)
}
} else {
locationManager?.stopMonitoring(for: delRegion)
}
}
}
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
if region.identifier.contains(AppConstants.WatchOverMe) {
AppDelegate.shared?.isWOMReachDestination(location: manager.location, region: region)
} }
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
self.myLocation = manager.location
manager.stopMonitoring(for: region)
self.significatLocationManager?.stopMonitoring(for: region)
manager.startUpdatingLocation()
self.significatLocationManager?.startUpdatingLocation()
self.createRegion(location: self.myLocation)
//update M yLocation API
if region.identifier.contains( AppConstants.WatchOverMe ) {
TabBarController.isWOMReachDestinationAlertShown = false
}
}
func locationManager(_ manager: CLLocationManager, monitoringDidFailFor region: CLRegion?, withError error: Error) {
self.myLocation = manager.location
self.createRegion(location: self.myLocation)
}
}
extension AppDelegate {
func applicationDidEnterBackground(_ application: UIApplication) {
self.scheduleBackgroundTask()
}
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
completionHandler(.newData)
}
func registerBGTask(){
BGTaskScheduler.shared.register(forTaskWithIdentifier: self.getBGTaskIdentifier(), using: nil) { task in
self.handleBackgroundTask(task: task as! BGAppRefreshTask)
}
}
func handleBackgroundTask(task: BGAppRefreshTask) {
task.setTaskCompleted(success: true)
}
func scheduleBackgroundTask() {
let request = BGAppRefreshTaskRequest(identifier: self.getBGTaskIdentifier() )
request.earliestBeginDate = Date(timeIntervalSinceNow: 10) // 30 second
do {
try BGTaskScheduler.shared.submit(request)
} catch {
print("Unable to schedule background task: (error)")
}
}
func getBGTaskIdentifier()->String {
let bundleId:String = AppInfoManager.shared.bundleId + ".locationBackgroundTask"
return bundleId
}
func startLocationTrackingTimer() {
self.stopLocationTrackingTimer()
self.locationTrackingTimer = Timer.scheduledTimer(timeInterval: 1.0,target: self,
selector: #selector(self.updateUserLocation),userInfo: nil,repeats: true)
RunLoop.current.add(self.locationTrackingTimer!, forMode: .common)
}
func stopLocationTrackingTimer() {
self.locationTrackingTimer?.invalidate()
self.locationTrackingTimer = nil
}
@objc func updateUserLocation() {
if self.isSocketActive {
self.updateMyLocationAPI(fromRoam: false)
} else {
self.updateUserCurrentLocation()
}
}
}
I am creating a mobile app based around city tours. I want to include a "download" function that would allow the user to tour offline using GPS/Apple maps. Is this possible?
I found something when I use CLLocationManagerDelegate on VisionOS.
When I called func locationManagerDidChangeAuthorization
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
switch manager.authorizationStatus {
case .notDetermined, .denied:
locationManager.requestWhenInUseAuthorization()
default:
locationManager.startUpdatingLocation()
guard let center = locationManager.location?.coordinate else { return }
isFollowing = false
mapCamera = .region(.init(center: center, span: .init(latitudeDelta: 0.005, longitudeDelta: 0.005)))
addItems()
}
}
Although I choose allow auth, locationManagerDidChangeAuthorization wasn't called.