swiftuisirishortcutsappintents

How to trigger a function from an App Intent


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 😕


Solution

  • 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à!