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.
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
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.
Hi, I am learning about MapKit for SwiftUI, at first I created the MKMapItem
@State private var mapSelection: MKMapItem?
@State var starbucksReserve = MKMapItem(placemark: .init(coordinate: CLLocationCoordinate2D(latitude: 41.894178596474575, longitude: -87.62451598445733)))`
I put that in the Map
Map(position: $cameraPosition,selection: $mapSelection){
Marker("Starbucks Reserve", systemImage: "cup.and.saucer.fill" ,coordinate: starbucksReserve.placemark.coordinate)
}
Even though I have put the selection $mapSelection, my Marker is not selectable. I am not sure why. I tried to fix it by changing mapSelection to Int? and made a tag for Marker, but because I am learning how to use it so I want to make sure why marker cannot be selectable with the first approach?
Thank you
CLMonitor WWDC video, it says the same name can be reused await CLMonitor("greeting") but the production iOS 17 API actually crashes. Is this the correct behaviour? (See screenshot 1)
for try await events in monitor.events should work in from the WWDC video, but the production iOS 17 API does not work and need to insert await after in keyword. Also, never received any events from the monitor (See screenshot 2)
WWDC Video: https://developer.apple.com/wwdc23/10147
Hi Developers. I need to try to embed GeoData into a USDZ model and then have the capabilities to "explore" the model while walking around in the real world.
e.g. load and display a 3D model of Time Square and show a location pin which displays a users' virtual position on the model... when the user walks 10 meters north, in the real world, the location pin must move 10m (to scale) on the displayed model.
As a new developer, I'm starting from scratch so would benefit greatly from having my hand held - please don't be afraid of patronizing me.
Step 1 - load and display the 3D model
Step 2 - geolocate the user
Step 3 - translate the user's current position into a position on the 3D model and represent their "position" on the model with a traditional GPS location marker "pin".
Step 4 - move the user's GPS pin on the mode, relative to (and reflecting) their actual real world movement.
Is this acheivable or have I explained things to ambiguously?
I look forward to hearing from my savior(s) as soon as convenient.
Thank you in advance