[iOS, SwiftUI] SiriKit (Shortcuts)
SiriKit
- Intents와 IntentsUI 프레임워크를 이용하여, 시리를 통해 디바이스와 상호작용을 할 수 있는 프레임워크
import Intents
import IntentsUI
SiriKit Capability
- add SiriKit Capability into the project setting for using siri

Shortcuts
NSUserActivity
NSUserActivity를 이용하여 쉽게 단축어(Shortcuts)를 추가하고, 시리를 통하여 앱을 실행

Set Shortcut to Siri Suggestions
import Intents
final class UserActivityShortcutsManager {
public enum Shortcut: CaseIterable {
case redview
case blueview
var type: String {
switch self {
case .redview:
return "com.tigi44.shortcuts.redview"
case .blueview:
return "com.tigi44.shortcuts.blueview"
}
}
var title: String {
switch self {
case .redview:
return "레드뷰 실행"
case .blueview:
return "블루뷰 실행"
}
}
var invocationPhrase: String {
switch self {
case .redview:
return "레드뷰 보여줘"
case .blueview:
return "블루뷰 보여줘"
}
}
var userActivity: NSUserActivity {
let userActivity = NSUserActivity(activityType: self.type)
userActivity.title = self.title
userActivity.suggestedInvocationPhrase = self.invocationPhrase
return userActivity
}
func makeShortcut() -> INShortcut {
return INShortcut(userActivity: self.userActivity)
}
}
static func setup() {
var shortcuts: [INShortcut] = []
for shortcut in Shortcut.allCases {
shortcuts.append(shortcut.makeShortcut())
}
INVoiceShortcutCenter.shared.setShortcutSuggestions(shortcuts)
}
}
// main
@main
struct SiriKitExampleApp: App {
init() {
UserActivityShortcutsManager.setup()
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
// if use appDelegate..
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UserActivityShortcutsManager.setup()
return true
}
- NSUserActivity를 이용하여 INShortcut을 만들고, 이를 INVoiceShortcutCenter.shared.setShortcutSuggestions(shortcuts)로 단축어에 설정
- 설정된 Shortcut은 단축어(Shortcuts)앱내의 Gallery에서 확인 및 사용 가능

Continue UserActivity
- 단축어(Shortcuts)로 실행된 내용을 SwiftUI에서 동작시키기 위해서는 View내의
onContinueUserActivity를 이용하여 쉽게 적용 가능 - Shortcut type에 따라 그에 맞는 onContinueUserActivity 설정
struct ContentView: View {
@State var showRedView: Bool = false
@State var showBlueView: Bool = false
var body: some View {
VStack(spacing: 100) {
Button(action: {
showRedView.toggle()
}, label: {
Label("Show a RedView", systemImage: "eye.circle.fill")
})
.foregroundColor(.red)
Button(action: {
showBlueView.toggle()
}, label: {
Label("Show a BlueView", systemImage: "eye.circle.fill")
})
.foregroundColor(.blue)
}
.sheet(isPresented: $showRedView, content: {
RedView()
})
.sheet(isPresented: $showBlueView, content: {
BlueView()
})
.onContinueUserActivity(UserActivityShortcutsManager.Shortcut.redview.type, perform: { userActivity in
showRedView.toggle()
})
.onContinueUserActivity(UserActivityShortcutsManager.Shortcut.blueview.type, perform: { userActivity in
showBlueView.toggle()
})
}
}
- 만약
appDelegate혹은sceneDelegate를 사용한다면 아래 함수에서 shortcut 동작을 실행 시키면 됨 - sceneDelegate를 이용하는 경우, 앱이 백그라운드로 실행중이지 않을 경우를 대비하여
scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions)에 동작을 추가해야 함
// appDelegate
func application(UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: [AnyObject]? -> Void) -> Bool {
switch userActivity.activityType {
...
}
}
// sceneDelegate
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let userActivity = connectionOptions.userActivities.first else { return }
self.scene(scene, continue: userActivity)
}
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
switch userActivity.activityType {
...
}
}
SiriButton (INUIAddVoiceShortcutButton)

- Shortcuts 추가는 앱내의 해당 화면에서 SiriButton(INUIAddVoiceShortcutButton)을 통하여 가능
- SwiftUI에서는 UIViewControllerRepresentable를 이용하여 INUIAddVoiceShortcutButton 기능 추가
import SwiftUI
import IntentsUI
struct SiriButton: UIViewControllerRepresentable {
public let shortcut: INShortcut
func makeUIViewController(context: Context) -> SiriUIViewController {
return SiriUIViewController(shortcut: shortcut)
}
func updateUIViewController(_ uiViewController: SiriUIViewController, context: Context) {
}
}
class SiriUIViewController: UIViewController {
let shortcut: INShortcut
init(shortcut: INShortcut) {
self.shortcut = shortcut
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
let button = INUIAddVoiceShortcutButton(style: .blackOutline)
button.shortcut = shortcut
self.view.addSubview(button)
view.centerXAnchor.constraint(equalTo: button.centerXAnchor).isActive = true
view.centerYAnchor.constraint(equalTo: button.centerYAnchor).isActive = true
button.translatesAutoresizingMaskIntoConstraints = false
button.delegate = self
}
}
extension SiriUIViewController: INUIAddVoiceShortcutButtonDelegate {
func present(_ addVoiceShortcutViewController: INUIAddVoiceShortcutViewController, for addVoiceShortcutButton: INUIAddVoiceShortcutButton) {
addVoiceShortcutViewController.delegate = self
addVoiceShortcutViewController.modalPresentationStyle = .formSheet
present(addVoiceShortcutViewController, animated: true)
}
func present(_ editVoiceShortcutViewController: INUIEditVoiceShortcutViewController, for addVoiceShortcutButton: INUIAddVoiceShortcutButton) {
editVoiceShortcutViewController.delegate = self
editVoiceShortcutViewController.modalPresentationStyle = .formSheet
present(editVoiceShortcutViewController, animated: true)
}
}
extension SiriUIViewController: INUIAddVoiceShortcutViewControllerDelegate {
func addVoiceShortcutViewController(_ controller: INUIAddVoiceShortcutViewController, didFinishWith voiceShortcut: INVoiceShortcut?, error: Error?) {
controller.dismiss(animated: true)
}
func addVoiceShortcutViewControllerDidCancel(_ controller: INUIAddVoiceShortcutViewController) {
controller.dismiss(animated: true)
}
}
extension SiriUIViewController: INUIEditVoiceShortcutViewControllerDelegate {
func editVoiceShortcutViewController(_ controller: INUIEditVoiceShortcutViewController, didUpdate voiceShortcut: INVoiceShortcut?, error: Error?) {
controller.dismiss(animated: true)
}
func editVoiceShortcutViewController(_ controller: INUIEditVoiceShortcutViewController, didDeleteVoiceShortcutWithIdentifier deletedVoiceShortcutIdentifier: UUID) {
controller.dismiss(animated: true)
}
func editVoiceShortcutViewControllerDidCancel(_ controller: INUIEditVoiceShortcutViewController) {
controller.dismiss(animated: true)
}
}
// add a siributton into a blueview
import SwiftUI
import Intents
struct BlueView: View {
let shortcut: INShortcut = UserActivityShortcutsManager.Shortcut.blueview.makeShortcut()
var body: some View {
ZStack {
Color.blue
.ignoresSafeArea()
SiriButton(shortcut: shortcut).frame(height: 34)
}
}
}
Intents

- Intents를 사용할 경우, Shortcuts 앱내의
Add Action메뉴에서 사용이 가능해짐 - Intents를 통해 추가 파라미터등을 입력받을 수 있는 등, 다양한 방식으로 Shortcut 활용이 가능
Create a SiriKit Intent Definition File

- Add
ShowIntentViewIntent
-
Custom Intent (Category) https://developer.apple.com/design/human-interface-guidelines/siri/overview/custom-intents/
-
Add Text Parameter into the intent

- Set a Parameter into Shortcuts App and Siri Suggestions

Continue UserActivity
- UserActivityType은 Intent Definition 생성시 info.plist 파일에 자동 생성
ShowIntentViewIntent에서 text 파라미터를 받을 수 있기때문에, userActivity에서 text 파라미터를 가져와 사용
struct ContentView: View {
...
var body: some View {
...
.onContinueUserActivity("ShowIntentViewIntent", perform: { userActivity in
if let intent = userActivity.interaction?.intent
as? ShowIntentViewIntent {
intentViewText = intent.text
}
showIntentView.toggle()
})
}
}
Leave a comment