swiftuiappintents

How to open App via AppIntents conditionally?


I am currently creating an App which is supposed to launch via an AppIntent. For example whenever I open Instagram it should trigger the AppIntent, which then decides if my App is supposed to open or not. The first part already works fine via Apple Shortcuts. The problem is dynamically opening or not opening my App. Unfortunately the openAppWhenRun field is supposed to be static and cannot be computed at runtime.

Here is the AppIntent so far:

struct OpenTimeEfficientIntent: AppIntent {
    
    static var title: LocalizedStringResource = "Opens the app conditionally"
    static var openAppWhenRun: Bool = false
    @Parameter(title: "OpenedApp", optionsProvider: Provider())
    var app: String //this is the initially opened app e.g. Instagram (i want to pass it)
    
    @MainActor
    func perform() async throws -> some IntentResult & ProvidesDialog {
        //at this point I want to decide, whether the app should be launched or not
    }
}

Just to specify: I don't want to decide which view I want to open but rather if I want to open the App at all.

What did I try?

I already tried to open the app via Deeplinks which is not allowed on iOS as the AppIntent is just a background task: The App is neither visible nor entitled, so may not perform un-trusted user actions

Trying to set the openAppWhenRun dynamically didn't work either.

For context

The app is basically a confirmation dialog. When I press no, the app closes and nothing happens. When I press yes, Instagram would be opened again. But in that case I don't want to launch my app again to prevent being stuck in a loop.


Solution

  • If you adopt ForegroundContinuableIntent rather than AppIntent, it will run in the background until you indicate it needs to open your app in the perform function. This allows you to conditionally decide whether you want to open your app.

    @available(iOS 16.4, *)
    struct OpenTimeEfficientIntent: ForegroundContinuableIntent {
        
        static var title: LocalizedStringResource = "Opens the app conditionally"
        static var openAppWhenRun: Bool = false
    
        @Parameter(title: "OpenedApp", optionsProvider: Provider())
        var app: String //this is the initially opened app e.g. Instagram (i want to pass it)
        
        @MainActor
        func perform() async throws -> some IntentResult & ProvidesDialog {
            //at this point you can decide whether the app should be brought to the foreground or not
    
            // Stop performing the app intent and ask the user to continue to open the app in the foreground
            throw needsToContinueInForegroundError()
    
            // You can customize the dialog and/or provide a closure to do something in your app after it's opened
            throw needsToContinueInForegroundError("Please continue to open the app.") {
                UIApplication.shared.open(URL(string: "yourapp://deeplinktocontent")!)
            }
    
            // Or you could ask the user to continue performing the intent in the foreground - if they cancel the intent stops, if they continue the intent execution resumes with the app open
            // This API also accepts an optional dialog and continuation closure
            try await requestToContinueInForeground()
            return .result(dialog: "I opened the app.")
        }
    
    }