[SC]()

iOS. Apple. Indies. Plus Things.

Open Intent in iOS 26

// Written by Jordan Morgan // Aug 19th, 2025 // Read it in about 1 minutes // RE: App Intents

This post is brought to you by Emerge Tools, the best way to build on mobile.

While working on Alyx and its (over 40!) Siri Shortcut actions, I came upon the need for an AppEntity to launch the app. In the past, I had similar intents for Elite Hoops:

struct OpenTeamIntent: AppIntent {
    static var isDiscoverable: Bool = false
    static var title: LocalizedStringResource = "Open Team"
    @Parameter(title: "Team")
    var team: TeamEntity
    
    @Dependency
    var deepLinker: DeepLinker
    
    init(team: TeamEntity) {
        self.team = team
    }
    
    init() {}
    
    @MainActor
    func perform() async throws -> some IntentResult {
        deepLinker.selectedCourtID = team.id
        return .result()
    }
}

Turns out, doing it this way is🥁….

Wrong!

There’s an intent type just for this type of thing, called OpenIntent. So, I adopted that correctly:

struct OpenTeamIntent: OpenIntent {
    static var isDiscoverable: Bool = false
    static var title: LocalizedStringResource = "Open Team"
    @Parameter(title: "Team")
    var target: TeamEntity
    
    @Dependency
    var deepLinker: DeepLinker
    
    init(target: TeamEntity) {
        self.target = target
    }
    
    init() {}
    
    @MainActor
    func perform() async throws -> some IntentResult {
        deepLinker.selectedCourtID = target.id
        return .result()
    }
}

But wait! It’s actually even easier than that! I don’t even need my own navigation class to do this anymore. Enter iOS 26 variant:

import AppIntents
import CaffeineKit

struct OpenDrinkIntent: OpenIntent {
    static let title: LocalizedStringResource = "Log Matched Drink"
    
    @Parameter(title: "Drink", requestValueDialog: "Which drink?")
    var target: CaffeineDrinkEntity
    
    func perform() async throws -> some IntentResult {
        return .result()
    }
}

#if os(iOS)
extension OpenDrinkIntent: TargetContentProvidingIntent {}
#endif

That’s it! Then, in your app in some view, there’s a modifier to handle it:

SomeView()
.onAppIntentExecution(OpenDrinkIntent.self) { intent in
    AlyxLogs.general.info("Opening drink intent: \(intent.target.name)")
    openTheThing()
}

To recap:

  1. Adopt OpenIntent
  2. Provide a target (yes, it MUST be named exactly that) of one of your AppEntity types.
  3. Add the TargetContentProvidingIntent conformance to it.
  4. And use the onAppIntentExecution modifier.

That’s an API at play I used with Visual Lookup support, by the way:

Until next time ✌️

···

Spot an issue, anything to add?

Reach Out.