Thanks for being a part of WWDC25!

How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here

iOS 18 App Intents while supporting iOS 17

iOS 18 App Intents while supporting iOS 17

Hello,

I have an existing app that supports iOS 17. I already have three App Intents but would like to add some of the new iOS 18 app intents like ShowInAppSearchResultsIntent.

However, I am having a hard time using #available or @available to limit this ShowInAppSearchResultsIntent to iOS 18 only while still supporting iOS 17.

Obviously, the ShowInAppSearchResultsIntent needs to use @AssistantIntent which is iOS 18 only, so I mark that struct as @available(iOS 18, *). That works as expected. It is when I need to add this "SearchSnippetIntent" intent to the AppShortcutsProvider, that I begin to have trouble doing. See code below:

struct SnippetsShortcutsAppShortcutsProvider: AppShortcutsProvider {
    
    @AppShortcutsBuilder
    static var appShortcuts: [AppShortcut] {
        //iOS 17+
        AppShortcut(intent: SnippetsNewSnippetShortcutsAppIntent(), phrases: [
            "Create a New Snippet in \(.applicationName) Studio",
        ], shortTitle: "New Snippet", systemImageName: "rectangle.fill.on.rectangle.angled.fill")
        
        AppShortcut(intent: SnippetsNewLanguageShortcutsAppIntent(), phrases: [
            "Create a New Language in \(.applicationName) Studio",
        ], shortTitle: "New Language", systemImageName: "curlybraces")
        
        AppShortcut(intent: SnippetsNewTagShortcutsAppIntent(), phrases: [
            "Create a New Tag in \(.applicationName) Studio",
        ], shortTitle: "New Tag", systemImageName: "tag.fill")
        
        //iOS 18 Only
        AppShortcut(intent: SearchSnippetIntent(), phrases: [
            "Search \(.applicationName) Studio",
            "Search \(.applicationName)"
        ], shortTitle: "Search", systemImageName: "magnifyingglass")
    }
    
    let shortcutTileColor: ShortcutTileColor = .blue
}

The iOS 18 Only AppShortcut shows the following error but none of the options seem to work. Maybe I am going about it the wrong way.

'SearchSnippetIntent' is only available in iOS 18 or newer

Add 'if #available' version check

Add @available attribute to enclosing static property

Add @available attribute to enclosing struct

Thanks in advance for your help.

Are you sure this doesn't work? (not actual code)

if(#available iOS 18) {
  AppShortcut(intent: SearchSnippetIntent(), phrases: [
              "Search \(.applicationName) Studio",
              "Search \(.applicationName)"
          ], shortTitle: "Search", systemImageName: "magnifyingglass")
  }
}

Have you tried something like: (not actual code)

@available iOS 18
struct SnippetsShortcutsAppShortcutsProvider: AppShortcutsProvider {
  // List all four items here
}

@available iOS 17
struct SnippetsShortcutsAppShortcutsProvider: AppShortcutsProvider {
  // List just the three iOS 17 ones here
}

The builder you want is iOS 17.4 forward; so to support 17 and 18 you'll need a minimum of 17.4.

Hi @wingover,

Thanks for the suggestion! Can you elaborate more on what my AppShortcutsBuilder should look like after I up the target to 17.4?

For Example, the following code crashes on iOS 17.5 with a 17.5 or 17.4 target:

struct SnippetsShortcuts: AppShortcutsProvider {
    
    @AppShortcutsBuilder
    static var appShortcuts: [AppShortcut] {
        AppShortcut(intent: CreateAppIntent(), phrases: [
            "Create a \(\.$selection) in \(.applicationName) Studio",
            "Create a \(\.$selection) in \(.applicationName)",
            "Create a \(\.$selection)"
        ], shortTitle: "Create", systemImageName: "plus")
            
        if #available(iOS 18, *) {
            AppShortcut(intent: SearchAppIntent(), phrases: [
                "Search \(.applicationName) Studio",
                "Search \(.applicationName)"
            ], shortTitle: "Search", systemImageName: "magnifyingglass")
        }
    }
    
    let shortcutTileColor: ShortcutTileColor = .blue
}

Here is the crash message:

dyld[23602]: Symbol not found: _$s10AppIntents15AssistantSchemaV06IntentD0VAC0E0AAWP Referenced from: <C18D0365-AAAC-3FC5-A60C-D73C2D9E7552> /Users/jonathan/Library/Developer/CoreSimulator/Devices/2E9641A0-00E1-463A-8B24-F488669B1229/data/Containers/Bundle/Application/7E2B4104-BF7F-43A2-9EEA-AD24EC95E096/Snippets Studio.app/Snippets Studio.debug.dylib Expected in: <88E18E38-24EC-364E-94A1-E7922AD247AF> /Library/Developer/CoreSimulator/Volumes/iOS_21F79/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 17.5.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/AppIntents.framework/AppIntents

First I thought this might work for you:

public struct MyShortcutsProvider: AppShortcutsProvider {

    public static var appShortcuts: [AppShortcut] = shortcuts()

    private static func shortcuts() -> [AppShortcut] {
        if #available(iOS 18.0, *) {
            [AppShortcut(intent: IntentA(), phrases: [""])]
        } else {
            [AppShortcut(intent: IntentB(), phrases: [""])]
        }
    }

But apparently it's not that easy to make @AppShortcutsBuilder static var appShortcuts: [AppShortcut] { get } dynamic.

iOS 18 App Intents while supporting iOS 17
 
 
Q