axiom-app-shortcuts-ref について
Appleプラットフォームの開発者向けに、App Shortcutsの実装を解説するリファレンススキルです。SiriやSpotlightでの発見、パラメーター付きフレーズ、表示促進、更新、トラブルシューティングを扱い、App Intentsとの違いも説明します。
主な機能
- 01AppShortcutsProviderの設定
- 02SiriとSpotlightのフレーズ設計
- 03パラメーター付きショートカットの作成
- 04SiriTipViewによるショートカットの紹介
- 05ショートカットのパラメーター更新
- 06ショートカットの表示問題の調査
活用シーン
- 01アプリの主要操作にショートカットを追加
- 02SiriやSpotlightからアプリ操作を実行
- 03Siriによる追加質問を減らす
- 04ショートカットが表示されない問題を調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ charleswiltgen/ axiom --skill axiom-app-shortcuts-refインストール後、Claude Code で/axiom-app-shortcuts-refを入力して読み込まれたか確認します。
詳細
App Shortcuts リファレンス
概要
Siri、Spotlight、Action Button、Control Center、その他のシステム機能ですぐにアプリのアクションを利用できるようにする App Shortcuts フレームワークの包括的なガイドです。App Shortcuts は、アプリのインストール直後から機能するよう事前設定された App Intents で、ユーザーによる設定は不要です。
重要な違い App Intents はアクションであり、App Shortcuts は、そのアクションをシステム全体ですぐに見つけられるようにする、事前設定済みの「窓口」です。
このスキルを使用する場面
以下の場合にこのスキルを使用します:
- アプリに AppShortcutsProvider を実装する
- Siri での呼び出しに使う候補フレーズを追加する
- Spotlight ですぐに利用できるよう設定する
- パラメーター付きショートカットを作成する(Siri による確認を省略する)
- NegativeAppShortcutPhrase を使用して誤検出を防ぐ(iOS 17 以降)
- SiriTipView でショートカットをおすすめする
- updateAppShortcutParameters() でショートカットを動的に更新する
- ショートカットが「ショートカット」アプリや Spotlight に表示されない問題をデバッグする
- App Intents と App Shortcuts のどちらを使うか選択する
以下の場合はこのスキルを使用しないでください:
- App Intents の一般的な実装(app-intents-ref を使用)
- Core Spotlight のインデックス作成(core-spotlight-ref を使用)
- アプリ全体の見つけやすさの戦略(app-discoverability を使用)
関連スキル
- app-intents-ref — App Intents の実装に関する包括的なリファレンス
- app-discoverability — アプリを見つけやすくするための戦略ガイド
- core-spotlight-ref — Core Spotlight と NSUserActivity の統合
App Shortcuts と App Intents の比較
| 項目 | App Intent | App Shortcut |
|---|---|---|
| 見つけやすさ | 「ショートカット」アプリ内で見つける必要がある | インストール後すぐに利用できる |
| 設定 | ユーザーが「ショートカット」アプリで設定する | 開発者が事前設定する |
| Siri の起動 | カスタムフレーズの設定が必要 | 提供されたフレーズですぐに使える |
| Spotlight | 寄付または IndexedEntity が必要 | 自動的に表示される |
| Action Button | 直接アクセスできない | すぐに割り当てられる |
| 設定時間 | ユーザーごとに数分 | ゼロ |
App Shortcuts を使う場面 すべてのアプリで、主要機能の App Shortcuts を提供する必要があります。ユーザーの手間を一切かけずに、見つけやすさを大幅に向上できます。
基本概念
AppShortcutsProvider プロトコル
準拠要件 アプリには AppShortcutsProvider に準拠する型を、必ず1つだけ用意する必要があります。
struct MyAppShortcuts: AppShortcutsProvider {
// Required: Define your shortcuts
@AppShortcutsBuilder
static var appShortcuts: [AppShortcut] { get }
// Optional: Branding color
static var shortcutTileColor: ShortcutTileColor { get }
// Optional: Dynamic updates
static func updateAppShortcutParameters()
// Optional: Negative phrases (iOS 17+)
static var negativePhrases: [NegativeAppShortcutPhrase] { get }
}
プラットフォームの対応状況 iOS 16 以降、iPadOS 16 以降、macOS 13 以降、tvOS 16 以降、watchOS 9 以降
AppShortcut の構造
AppIntent を、読み上げフレーズやメタデータと関連付けます。
AppShortcut(
intent: StartMeditationIntent(),
phrases: [
"Start meditation in \(.applicationName)",
"Begin mindfulness with \(.applicationName)"
],
shortTitle: "Meditate",
systemImageName: "figure.mind.and.body"
)
構成要素:
intent— 実行する App Intentphrases— Siri/Spotlight で使う読み上げまたは入力用のフレーズshortTitle— 「ショートカット」アプリのタイルに表示する短いラベルsystemImageName— 視覚的に表現するための SF Symbol
AppShortcutPhrase(候補フレーズ)
文字列補間 フレーズでは \(.applicationName) を使って、アプリ名を動的に含めます。
phrases: [
"Start meditation in \(.applicationName)",
"Meditate with \(.applicationName)"
]
Siri/Spotlight に表示される内容:
- 「Calm で瞑想を始める」
- 「Calm で瞑想する」
重要な理由 システムはこれらのフレーズをそのまま使って、Siri 経由でインテントを実行し、Spotlight に候補を表示します。
@AppShortcutsBuilder
ショートカットの配列を定義する結果ビルダーです。
@AppShortcutsBuilder
static var appShortcuts: [AppShortcut] {
AppShortcut(intent: OrderIntent(), /* ... */)
AppShortcut(intent: ReorderIntent(), /* ... */)
if UserDefaults.standard.bool(forKey: "premiumUser") {
AppShortcut(intent: CustomizeIntent(), /* ... */)
}
}
結果ビルダーの機能:
- 条件付きショートカット(if/else)
- ループで生成するショートカット(for-in)
- インラインでの配列構築
フレーズテンプレートのパターン
基本的なフレーズ(パラメーターなし)
AppShortcut(
intent: StartWorkoutIntent(),
phrases: [
"Start workout in \(.applicationName)",
"Begin exercise with \(.applicationName)",
"Work out in \(.applicationName)"
],
shortTitle: "Start Workout",
systemImageName: "figure.run"
)
メリット:
- シンプルで見つけやすい
- すべてのユーザーが利用できる
- パラメーターの曖昧さがない
使用する場面 インテントに必須パラメーターがない場合、またはパラメーターにデフォルト値がある場合に使用します。
パラメーター付きフレーズ(確認を省略)
特定のパラメーター値を指定してインテントを事前設定し、Siri による確認ステップを省略します。
// Intent with parameters
struct StartMeditationIntent: AppIntent {
static var title: LocalizedStringResource = "Start Meditation"
@Parameter(title: "Type")
var meditationType: MeditationType?
@Parameter(title: "Duration")
var duration: Int?
}
// Shortcuts with different parameter combinations
@AppShortcutsBuilder
static var appShortcuts: [AppShortcut] {
// Generic version (will ask for parameters)
AppShortcut(
intent: StartMeditationIntent(),
phrases: ["Start meditation in \(.applicationName)"],
shortTitle: "Meditate",
systemImageName: "figure.mind.and.body"
)
// Specific versions (skip parameter step)
AppShortcut(
intent: StartMeditationIntent(
meditationType: .mindfulness,
duration: 10
),
phrases: [
"Start quick mindfulness in \(.applicationName)",
"10 minute mindfulness in \(.applicationName)"
],
shortTitle: "Quick Mindfulness",
systemImageName: "brain.head.profile"
)
AppShortcut(
intent: StartMeditationIntent(
meditationType: .sleep,
duration: 20
),
phrases: [
"Start sleep meditation in \(.applicationName)"
],
shortTitle: "Sleep Meditation",
systemImageName: "moon.stars.fill"
)
}
メリット:
- 1つのフレーズで完了(追加の質問なし)
- よく使うケースでユーザー体験が向上
- Spotlight に具体的なショートカットが表示される
トレードオフ ショートカットが増えるほど、ショートカットアプリの画面が煩雑になります。よく使うケース(3~5個のショートカット)と柔軟性(パラメーター付きの汎用ショートカット)のバランスを取りましょう。
NegativeAppShortcutPhrase(iOS 17+)
特定のフレーズではアプリを起動しないよう、システムに学習させます。
struct MeditationAppShortcuts: AppShortcutsProvider {
@AppShortcutsBuilder
static var appShortcuts: [AppShortcut] {
AppShortcut(
intent: StartMeditationIntent(),
phrases: ["Start meditation in \(.applicationName)"],
shortTitle: "Meditate",
systemImageName: "figure.mind.and.body"
)
}
// Prevent false positives
static var negativePhrases: [NegativeAppShortcutPhrase] {
NegativeAppShortcutPhrases {
"Stop meditation"
"Cancel meditation"
"End session"
}
}
}
使用する場面:
- ショートカットのフレーズに似ているものの、反対の意味を持つフレーズ
- ユーザーが口にする可能性が高く、アプリを起動すべきではない一般的なフレーズ
- 複数のアプリが似た機能を持つ場合の曖昧さの解消
プラットフォーム iOS 17.0+、iPadOS 17.0+、macOS 14.0+、tvOS 17.0+、watchOS 10.0+
検出 UI コンポーネント
SiriTipView — アプリ内でショートカットを紹介
ショートカットの音声フレーズをアプリの UI に直接表示します。
import AppIntents
import SwiftUI
struct OrderConfirmationView: View {
@State private var showSiriTip = true
var body: some View {
VStack {
Text("Order confirmed!")
// Show Siri tip after successful order
SiriTipView(intent: ReorderIntent(), isVisible: $showSiriTip)
.siriTipViewStyle(.dark)
}
}
}
要件:
- インテントが AppShortcut で使用されている必要があります(そうでない場合、空のビューが表示されます)
- isVisible バインディングで表示状態を制御します
スタイル:
.automatic— 環境に合わせて調整します.light— 明るい背景.dark— 暗い背景
ベストプラクティス ユーザーが操作を完了した後に表示し、次回からより簡単に利用できる方法を提案します。
ShortcutsLink — ショートカットアプリへのリンク
ショートカットアプリ内のアプリのページを開き、利用可能なすべてのショートカットを表示します。
import AppIntents
import SwiftUI
struct SettingsView: View {
var body: some View {
List {
Section("Siri & Shortcuts") {
ShortcutsLink()
// Displays "Shortcuts" with standard link styling
}
}
}
}
使用する場面:
- 設定画面
- ヘルプ/サポートセクション
- オンボーディングフロー
メリット 1回タップするだけで、ユーザーはアプリのすべてのショートカットを確認でき、提案されるフレーズも表示されます。
ShortcutTileColor — ブランディング
ショートカットアプリ内でショートカットに使用する色を設定します。
struct CoffeeAppShortcuts: AppShortcutsProvider {
static var shortcutTileColor: ShortcutTileColor = .tangerine
@AppShortcutsBuilder
static var appShortcuts: [AppShortcut] {
// ...
}
}
利用可能な色:
| 色 | 用途 |
|---|---|
.blue | デフォルト、プロフェッショナル |
.tangerine | 活気、飲食 |
.purple | クリエイティブ、瞑想 |
.teal | 健康、ウェルネス |
.red | 緊急、重要 |
.pink | ライフスタイル、ソーシャル |
.navy | ビジネス、金融 |
.yellow | 生産性、メモ |
.lime | フィットネス、アウトドア |
全リスト:.blue、.grape、.grayBlue、.grayBrown、.grayGreen、.lightBlue、.lime、.navy、.orange、.pink、.purple、.red、.tangerine、.teal、.yellow
色を選ぶ アプリアイコンやブランドイメージに合う色を選びましょう。
動的な更新
updateAppShortcutParameters()
パラメーターの選択肢が変わったときに呼び出し、保存済みのショートカットを更新します。
struct MeditationAppShortcuts: AppShortcutsProvider {
@AppShortcutsBuilder
static var appShortcuts: [AppShortcut] {
// Shortcuts can reference dynamic data
for session in MeditationData.favoriteSessions {
AppShortcut(
intent: StartSessionIntent(session: session),
phrases: ["Start \(session.name) in \(.applicationName)"],
shortTitle: session.name,
systemImageName: session.iconName
)
}
}
static func updateAppShortcutParameters() {
// Called automatically when needed
// Override only if you need custom behavior
}
}
// In your app, when data changes
extension MeditationData {
func markAsFavorite(_ session: Session) {
favoriteSessions.append(session)
// Update App Shortcuts to reflect new data
MeditationAppShortcuts.updateAppShortcutParameters()
}
}
呼び出すタイミング:
- ユーザーがお気に入りを追加または削除したとき
- 利用可能な選択肢が変わったとき
- アプリのデータ構造が更新されたとき
自動呼び出し システムは定期的にこの処理を呼び出しますが、データが変更されたとわかっている場合は、更新を強制できます。
実装の全体例
ステップ 1:App Intents を定義する
import AppIntents
struct OrderCoffeeIntent: AppIntent {
static var title: LocalizedStringResource = "Order Coffee"
static var description = IntentDescription("Orders coffee for pickup")
@Parameter(title: "Coffee Type")
var coffeeType: CoffeeType
@Parameter(title: "Size")
var size: CoffeeSize
@Parameter(title: "Customizations")
var customizations: String?
static var parameterSummary: some ParameterSummary {
Summary("Order \(\.$size) \(\.$coffeeType)") {
\.$customizations
}
}
func perform() async throws -> some IntentResult {
let order = try await CoffeeService.shared.order(
type: coffeeType,
size: size,
customizations: customizations
)
return .result(
value: order,
dialog: "Your \(size) \(coffeeType) is ordered for pickup"
)
}
}
struct ReorderLastIntent: AppIntent {
static var title: LocalizedStringResource = "Reorder Last Coffee"
static var description = IntentDescription("Reorders your most recent coffee")
static var openAppWhenRun: Bool = false
func perform() async throws -> some IntentResult {
guard let lastOrder = try await CoffeeService.shared.lastOrder() else {
throw CoffeeError.noRecentOrders
}
try await CoffeeService.shared.reorder(lastOrder)
return .result(
dialog: "Reordering your \(lastOrder.coffeeName)"
)
}
}
enum CoffeeType: String, AppEnum {
case latte, cappuccino, americano, espresso
static var typeDisplayRepresentation: TypeDisplayRepresentation = "Coffee"
static var caseDisplayRepresentations: [CoffeeType: DisplayRepresentation] = [
.latte: "Latte",
.cappuccino: "Cappuccino",
.americano: "Americano",
.espresso: "Espresso"
]
}
enum CoffeeSize: String, AppEnum {
case small, medium, large
static var typeDisplayRepresentation: TypeDisplayRepresentation = "Size"
static var caseDisplayRepresentations: [CoffeeSize: DisplayRepresentation] = [
.small: "Small",
.medium: "Medium",
.large: "Large"
]
}
ステップ 2:AppShortcutsProvider を作成する
import AppIntents
struct CoffeeAppShortcuts: AppShortcutsProvider {
@AppShortcutsBuilder
static var appShortcuts: [AppShortcut] {
// Generic order (will ask for parameters)
AppShortcut(
intent: OrderCoffeeIntent(),
phrases: [
"Order coffee in \(.applicationName)",
"Get coffee from \(.applicationName)"
],
shortTitle: "Order",
systemImageName: "cup.and.saucer.fill"
)
// Common specific orders (skip parameter step)
AppShortcut(
intent: OrderCoffeeIntent(
coffeeType: .latte,
size: .medium
),
phrases: [
"Order my usual from \(.applicationName)",
"Get my regular coffee from \(.applicationName)"
],
shortTitle: "Usual Order",
systemImageName: "star.fill"
)
// Reorder last
AppShortcut(
intent: ReorderLastIntent(),
phrases: [
"Reorder coffee from \(.applicationName)",
"Order again from \(.applicationName)"
],
shortTitle: "Reorder",
systemImageName: "arrow.clockwise"
)
}
// Branding
static var shortcutTileColor: ShortcutTileColor = .tangerine
// Prevent false positives (iOS 17+)
static var negativePhrases: [NegativeAppShortcutPhrase] {
NegativeAppShortcutPhrases {
"Cancel coffee order"
"Stop coffee"
}
}
}
ステップ 3:UI で紹介する
import SwiftUI
import AppIntents
struct OrderConfirmationView: View {
@State private var showReorderTip = true
var body: some View {
VStack(spacing: 20) {
Image(systemName: "checkmark.circle.fill")
.font(.system(size: 60))
.foregroundColor(.green)
Text("Order Placed!")
.font(.title)
Text("Your coffee will be ready in 10 minutes")
.foregroundColor(.secondary)
// Promote reorder shortcut
if showReorderTip {
SiriTipView(intent: ReorderLastIntent(), isVisible: $showReorderTip)
.siriTipViewStyle(.dark)
.padding(.top)
}
// Link to see all shortcuts
Section {
ShortcutsLink()
} header: {
Text("See all available shortcuts")
.font(.caption)
}
}
.padding()
}
}
App Shortcuts が表示される場所
実装すると、App Shortcuts は次の場所で利用できます。
| 場所 | ユーザー体験 |
|---|---|
| Siri | 指定したフレーズで音声起動 |
| Spotlight | アクションまたはフレーズを検索 → 即時実行 |
| ショートカットアプリ | 事前に登録されたショートカット、設定不要 |
| アクションボタン(iPhone 15 Pro) | ハードウェアボタンに割り当て可能 |
| Apple Watch Ultra | アクションボタンへの割り当て |
| コントロールセンター | ショートカットをコントロールとして追加 |
| ロック画面ウィジェット | ロック解除せずにクイックアクションを実行 |
| Apple Pencil Pro | スクイーズジェスチャに割り当て |
| 集中モードフィルター | コンテキストに応じたフィルタリング |
すぐに利用可能 すべての場所で、アプリのインストール直後から利用できます。ユーザーによる設定は不要です。
テストとデバッグ
ショートカットアプリにショートカットが表示されることを確認する
- デバイスでアプリをビルドして実行します
- ショートカットアプリを開きます
- 「+」をタップして新しいショートカットを作成します
- アプリ名を検索します
- 正しいタイトルとアイコンでショートカットが表示されることを確認します
ショートカットが表示されない場合:
- AppShortcutsProvider がメインアプリのターゲットに含まれていることを確認します
- AppIntents の
isDiscoverableが true であることを確認します(デフォルト) - アプリを再ビルドして再インストールします
- コンソールで AppShortcuts のエラーを確認します
Siri の呼び出しをテストする
- Siri を呼び出します
- 提案されたフレーズのいずれかを話します
- Siri がインテントを実行することを確認します
例:
- あなた:「CoffeeApp でコーヒーを注文して」
- Siri:「サイズと種類を教えてください」
- あなた:「ミディアムのラテ」
- Siri:「ミディアムのラテをテイクアウトで注文しました」
Siri がフレーズを認識しない場合:
- フレーズに
\(.applicationName)が含まれていることを確認します - フレーズが appShortcuts 配列に含まれていることを確認します
- より簡単なフレーズを試します(3〜6語が理想です)
- 複雑な文法や珍しい単語は避けます
Spotlight での検出をテストする
- 下にスワイプして Spotlight を開きます
- アプリ名またはショートカットのフレーズを入力します
- 検索結果にショートカットが表示されることを確認します
- タップして実行します
Spotlight にショートカットが表示されない場合:
- 数分待ちます(インデックス作成に時間がかかります)
- デバイスを再起動します
- 「設定」→「Siriと検索」→[アプリ名]→「検索でアプリを表示」を確認します
コンソールログでデバッグする
#if DEBUG
struct CoffeeAppShortcuts: AppShortcutsProvider {
@AppShortcutsBuilder
static var appShortcuts: [AppShortcut] {
let shortcuts = [
AppShortcut(/* ... */),
// ...
]
print("📱 Registered \(shortcuts.count) App Shortcuts")
shortcuts.forEach { shortcut in
print(" - \(shortcut.shortTitle)")
}
return shortcuts
}
}
#endif
アプリの起動後に Xcode コンソールを確認し、ショートカットが登録されていることを確かめます。
ベストプラクティス
1. フレーズの設計
❌ しないこと:長くて複雑なフレーズ
phrases: [
"I would like to order a coffee from \(.applicationName) please"
]
✅ すること:短く自然なフレーズ
phrases: [
"Order coffee in \(.applicationName)",
"Get coffee from \(.applicationName)"
]
ガイドライン:
- 3〜6語が理想です
- 動詞(注文、開始、取得、表示)から始めます
- 曖昧さを避けるために
\(.applicationName)を含めます - ユーザーが実際に使う自然な言葉を使用します
2. ショートカットの数
❌ しないこと:20個以上のショートカットを用意する
// Bad: Overwhelming
AppShortcut for every possible combination
✅ すること:3〜5個の主要なアクションに絞る
// Good: Focused on common tasks
AppShortcut(intent: OrderIntent(), /* ... */)
AppShortcut(intent: ReorderIntent(), /* ... */)
AppShortcut(intent: ViewOrdersIntent(), /* ... */)
理由 ショートカットが多すぎると、画面が煩雑になります。価値が高く、頻繁に使われるアクションに絞りましょう。
3. パラメーターの組み合わせ
❌ しないこと:あらゆるバリエーションをパラメーター化する
// Bad: Creates 12 shortcuts (3 sizes × 4 types)
for size in CoffeeSize.allCases {
for type in CoffeeType.allCases {
AppShortcut(intent: OrderIntent(type: type, size: size), /* ... */)
}
}
✅ すること:汎用のものに加え、よく使われるケースを上位2〜3個用意する
// Good: Generic + common specific cases
AppShortcut(intent: OrderIntent(), /* ... */) // Generic
AppShortcut(intent: OrderIntent(type: .latte, size: .medium), /* ... */) // Usual
AppShortcut(intent: OrderIntent(type: .espresso, size: .small), /* ... */) // Quick
4. 短いタイトル
❌ しないこと:冗長または重複したタイトルにする
shortTitle: "Order Coffee from Coffee App"
✅ すること:簡潔でわかりやすくする
shortTitle: "Order"
補足 ショートカットアプリにはすでにアプリ名が表示されるため、繰り返す必要はありません。
5. システムイメージ
❌ しないこと:カスタムイメージを使う
// Not supported
shortImage: UIImage(named: "custom")
✅ すること:SF Symbols を使う
systemImageName: "cup.and.saucer.fill"
理由 SF Symbols は適切に拡大縮小され、ダークモードに対応し、システム UI と統合されます。
リソース
WWDC:2022-10170、2022-10169、260
ドキュメント:/appintents/appshortcutsprovider、/appintents/appshortcut、/appintents/app-shortcuts
スキル:axiom-app-intents-ref、axiom-app-discoverability、axiom-core-spotlight-ref
覚えておきましょう App Shortcuts を使うと、iOS 全体ですぐにアプリの機能を利用できるようになります。自然なフレーズを使った主要なショートカットを3〜5個定義し、SiriTipView で UI 上に案内すれば、ユーザーは Siri、Spotlight、アクションボタンなどからすぐに呼び出せます。