iOS App Intents: Dynamically open the app and bring it to the foreground

1.8k Views Asked by At

I'm using the App Intents API to provide an automation through the iOS Shortcuts app. When my intent runs, I'd like to be able to decide if I want to open the app (bring it to the foreground) or not. I know openAppWhenRun can be used to open the app, but its value cannot be modified.

I tried using openAppWhenRun, but it does not have a setter. Therefore, I cannot dynamically update this variable to determine if the app should be opened in the foreground or not.

3

There are 3 best solutions below

3
On

you don't need a setter in this case you must override it:

static var openAppWhenRun: Bool = true

Hope it helps!

0
On

This is possible as of iOS 16.4 via the ForegroundContinuableIntent protocol. It will run in the background until you decide to bring the app to the foreground. Here's an example:

import AppIntents

@available(iOS 16.4, *)
struct TestIntent: ForegroundContinuableIntent {
    static var title: LocalizedStringResource = "Test Intent"

    @Parameter(title: "Open App")
    var shouldOpenApp: Bool

    @MainActor
    func perform() async throws -> some IntentResult & ProvidesDialog {
        if shouldOpenApp {
            // 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.")
        } else {
            return .result(dialog: "I did not open the app.")
        }
    }
}
1
On

Inside your intent's perform-method, return .result(opensIntent:), opening another intent, that brings your app to the foreground. Should the conditions to do so not apply, you can throw a custom error (otherwise perform wouldn't return some IntentResult). Just make sure your Error-enum adheres to CustomLocalizedStringResourceConvertible, so the user gets a useful message.