
28. Apr 2025
iOSApp Intents tips and tricks: How to make iOS apps more accessible than ever
App Intents is a framework introduced in iOS 16 that makes it easy to create shortcuts, automations, and voice commands for Siri in our apps. It allows you to improve how users interact with your app without opening it.


🚀 Why use App Intents?
- Actions available through Siri, Spotlight and Shortcuts.
- Simplified creation of custom shortcuts.
- Usability in Widgets.

Opening the application
To demonstrate how to work with App Intents, we will implement a simple intent to open an app. This intent will be able to be triggered via Siri, Shortcuts or Spotlight, giving users quick access to the app and its key functionality. Let's do it!
First we make our own intent by implementing the protocol AppIntent.
import AppIntents
struct OpenApp: AppIntent {
static let title = LocalizedStringResource(stringLiteral: "Open app")
static let description = IntentDescription(stringLiteral: "This intent opens the app")
static let openAppWhenRun: Bool = true
func perform() async throws -> some IntentResult {
return .result()
}
}
Title is the readable name of the intent that appears in the Shortcuts application. We use LocalizedStringResource, which makes it easy to localize the title into multiple languages. Like title, description helps users understand what the intent is for.
If we want to ensure that the application is actually opened after the intent is started, we need to set the openAppWhenRun
variable to true
.
Finally, we come to the very heart of our intent, which is the perform()
function. The logic contained within it is executed after the intent is run and returns an IntentResult
. In this case, we can leave it empty because the application will open for us, and that was the goal of this action.
At this point, our app opening intent is visible and available to users in the Shortcuts. From there, they can launch it, add it to the home screen, or create custom automations.
In order to make our app's functionality even more accessible - specifically, to allow it to be displayed in Spotlight searches and triggered by voice commands via Siri - we need to register the intent with the AppShortcutsProvider
. We can do this simply as follows:
struct ShortcutsProvider: AppShortcutsProvider {
@AppShortcutsBuilder
static var appShortcuts: [AppShortcut] {
AppShortcut(
intent: OpenApp(),
phrases: [
"Open \(.applicationName)",
"Open \(.applicationName) app",
"Launch \(.applicationName)",
"Start \(.applicationName)",
"Run \(.applicationName)",
],
shortTitle: "Opens app",
systemImageName: "square.stack"
)
}
}
In this way, we also define example phrases that trigger it via Siri. By defining a number of different phrases, we allow for a broader and more flexible way for the user to interact with the app.
Search in the app
A very useful example is the implementation of in-app search intent. It focuses on search, a feature that most apps today offer in various forms. When such an intent is triggered, the application requests an input parameter - the expression to be searched. The system then waits for the user to enter this expression. After the user enters it, the application will open in the search state, already pre-loaded with the expression that the user has entered.
This process enables faster and more efficient use of the app's search functionality, improving the user experience.
struct SearchInAppIntent: ShowInAppSearchResultsIntent {
static let title = LocalizedStringResource(stringLiteral: "Search in app")
static let searchScopes: [StringSearchScope] = [.general]
@Parameter(
title: "Search term",
description: "Enter a keyword to search",
requestValueDialog: .init("What would you like to search for?")
)
var criteria: StringSearchCriteria
func perform() async throws -> some IntentResult {
await coordinator?.search(for: criteria.term)
return .result()
}
}
Interactive widgets
Interactive widgets are a great tool for improving user experience and increasing engagement with apps. Widgets allow users to quickly access important features of an app directly from the home screen, without having to open the app itself. Interactive widgets not only save time, but also add convenience to the day-to-day use of the app, contributing to higher user satisfaction and more frequent engagement with the app.
An example of a simple counter implementation might look like this:
struct CountEntry: TimelineEntry {
let date: Date
let count: Int
}
First, we create a CountryEntry (serves as a data model for the widget). date is a mandatory parameter by which WidgetKit specifies the display of data and the count parameter stores the value of the counter that is displayed in the widget.
struct Provider: TimelineProvider {
private var actualCount: Int { SharedStorage().count() }
func placeholder(in context: Context) -> CountEntry {
CountEntry(date: Date(), count: actualCount)
}
func getSnapshot(in context: Context, completion: @escaping (CountEntry) -> ()) {
completion(CountEntry(date: Date(), count: actualCount))
}
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
let timeline = Timeline(
entries: [CountEntry(date: Date(), count: actualCount)],
policy: .atEnd
)
completion(timeline)
}
}
TimelineProvider is responsible for providing current and future data that will be used in the widget.
- placeholder: Used as a preview when adding a widget in the editor and provides the content while the real data is being loaded.
- getSnapshot: Used to provide a snapshot of the state of the widget.
- getTimeLine: This function is used to provide real-time data and offers the ability to supply future data. In this particular case, there is no point in defining future data since we are using a static value to display the counter state. If the value were to change in a predictable way (timer, countdown, ...) we could anticipate future data and provide it in this function.
struct counterEntryView : View {
var entry: Provider.Entry
var body: some View {
VStack {
Text("\(entry.count)")
.font(.title)
.fontWeight(.bold)
.contentTransition(.numericText())
if #available(iOS 17.0, *) {
Button(
intent: IncrementCounterIntent(),
label: { Text("Tap me!") }
)
}
}
}
}
In the last step, we create the UI for the widget that displays the count (counter state) and includes an interactive button (minimum iOS version is 17.0). Such a button is capable of triggering an action, which we define as App Intent. A given action and the logic implemented behind it is triggered and executed without the need to open the app.
Implementation of the IncementCounterIntent()
action is simple and its only task is to increment the counter stored in the local memory of the device.
struct IncrementCounterIntent: AppIntent {
static var title: LocalizedStringResource { "Counter title" }
static var description: IntentDescription { "Counter description" }
func perform() async throws -> some IntentResult {
SharedStorage().increment()
return .result()
}
}
Control Center
Control widgets are a powerful tool that allows users to easily control various application features directly from the Control Center or even from the lock screen.
@available(iOSApplicationExtension 18.0, *)
struct OpenAppControl: ControlWidget {
let kind: String = "openAppControl"
var body: some ControlWidgetConfiguration {
StaticControlConfiguration(
kind: kind,
content: {
ControlWidgetButton(
action: OpenApp(),
label: { Label("Open App", systemImage: "square.stack") }
)
}
)
}
}
Control widgets are only available from iOS version 18 and above. kind
is the unique identifier of this control widget. The body of the widget itself contains a configuration with static content - in this case, a button that performs the OpenApp()
action (intent), which we have already implemented above.
Control widget implemented in this way allows us to easily add an action to the Control Center or directly to the lock screen. This approach increases comfort and efficiency as it allows to perform actions directly from the Control Center or the lock screen.
✅ Summary
App Intents are a powerful tool for integrating apps with Siri, Shortcuts and Spotlight. They are simple to implement and provide intuitive control of apps by voice or automations. If you want to improve the user experience in your app, App Intents are definitely the way to go!
Curious how these features boost business results? Read more in our business blog!


Related articles

App Intents: How to make your app more accessible through Siri, Spotlight, and Widgets


How to build a successful iOS app using overlooked features


Removing barriers: How to make your app accessible for everyone
