How to trigger a function from an App Intent

330 views Asked by At

I created an app that fetches bike parking spots around me. In the app, every thing works perfectly.

Now, I'm trying to create a shortcut that triggers the fetching of the parking spots. Unfortunately, it doesn't work. Everytime, I get a crash.

Here is a partial code of the MapView where I can fetch the spots :

struct MapView: View {
    

    @State private var position: MapCameraPosition = .userLocation(fallback: .region(LocationManager().region))
    @State var manager = LocationManager()
    @State var visibleRegion: MKCoordinateRegion?
    @Namespace var mapScope
    
    var body: some View {
            
            Map(position: $position, selection: $selectedParkedBike, scope: mapScope){
                // Some code to display fetched parking spots
            }
            .ignoresSafeArea()
            .mapControls {
            }
            .onAppear {               
                visibleRegion = manager.region
            }

    // Some code

func fetchParkingSpotsForVisibleRegion(medium: String) {
        
        let (lat, long) = (visibleRegion!.center.latitude, visibleRegion!.center.longitude)
        let visibleRegion = visibleRegion!

        // Some code
    }

And here is my App Intent code

struct TriggerSearchIntent: AppIntent {
    static let title: LocalizedStringResource = "Recherche un emplacement pour mon vélo"
    
    
    @MainActor
    func perform() async throws -> some IntentResult {
        let mapView = MapView()
        mapView.fetchParkingSpotsForVisibleRegion(medium: "shortcut")
        return .result()
    }
    
    static let openAppWhenRun: Bool = true
    
}

When using the shortcut, I got the error that visibleRegion = nil , I don't really get why has the visibleRegion is set when the map is appearing.

To solve this I tried a to set visibleRegion into the App Intent code, and tried many other things that all failed

1

There are 1 answers

0
Zim On BEST ANSWER

I found a way to make it work :

In my App Intent, I send a notification to the app :

struct TriggerSearchIntent: AppIntent {
    static let title: LocalizedStringResource = "Recherche un emplacement pour mon vélo"
    
    static let openAppWhenRun: Bool = true
    
    @MainActor
    func perform() async throws -> some IntentResult {
        
        NotificationCenter.default.post(name: Notification.Name(rawValue: "performSearchFromShortcut"), object: nil)
        
        return .result()
    }
}

In the app, when receiving the notification I perform the function:

    struct MapView: View {
        
    
        @State private var position: MapCameraPosition = .userLocation(fallback: .region(LocationManager().region))
        @State var manager = LocationManager()
        @State var visibleRegion: MKCoordinateRegion?
        @Namespace var mapScope
        
        var body: some View {
                
                Map(position: $position, selection: $selectedParkedBike, scope: mapScope){
                    // Some code to display fetched parking spots
                }
                .ignoresSafeArea()
                .mapControls {
                }
                .onAppear {               
                    visibleRegion = manager.region
                }
                .onReceive(NotificationCenter.default.publisher(for: Notification.Name(rawValue: "performSearchFromShortcut"))) { notification in
                    fetchParkingSpotsForVisibleRegion(medium: "shortcut")
            }
    
        // Some code
    
    func fetchParkingSpotsForVisibleRegion(medium: String) {
            
            let (lat, long) = (visibleRegion!.center.latitude, visibleRegion!.center.longitude)
            let visibleRegion = visibleRegion!
    
            // Some code
        }

And voilà!