app-intents

📁 makgunay/claude-swift-skills 📅 12 days ago
4
总安装量
3
周安装量
#49217
全站排名
安装命令
npx skills add https://github.com/makgunay/claude-swift-skills --skill app-intents

Agent 安装分布

opencode 3
claude-code 3
codex 3
cursor 3
gemini-cli 2
github-copilot 2

Skill 文档

AppIntents — Siri, Shortcuts & Spotlight

Critical Constraints

  • ❌ DO NOT use old SiriKit INIntent → ✅ Use AppIntent protocol
  • ❌ DO NOT use NSUserActivity alone for Spotlight → ✅ Use IndexedEntity + CSSearchableIndex.default().indexAppEntities()
  • ❌ DO NOT hardcode foreground-only intents → ✅ Use supportedModes for flexible execution

Basic App Intent

import AppIntents

struct FindNearestLandmarkIntent: AppIntent {
    static var title: LocalizedStringResource = "Find Nearest Landmark"

    @Parameter(title: "Category")
    var category: String?

    func perform() async throws -> some IntentResult {
        let landmark = await findNearestLandmark(category: category)
        return .result(value: landmark)
    }
}

Intent Modes (Background/Foreground Control)

struct GetCrowdStatusIntent: AppIntent {
    static let supportedModes: IntentModes = [.background, .foreground(.dynamic)]

    func perform() async throws -> some ReturnsValue<Int> & ProvidesDialog {
        guard await modelData.isOpen(landmark) else {
            return .result(value: 0, dialog: "Currently closed.")
        }
        if systemContext.currentMode.canContinueInForeground {
            do {
                try await continueInForeground(alwaysConfirm: false)
                await navigator.navigateToCrowdStatus(landmark)
            } catch { }
        }
        let status = await modelData.getCrowdStatus(landmark)
        return .result(value: status, dialog: "Crowd level: \(status)")
    }
}

Mode combinations:

  • [.background, .foreground] — foreground default, background fallback
  • [.background, .foreground(.dynamic)] — background default, can request foreground
  • [.background, .foreground(.deferred)] — background first, guaranteed foreground later

Property Macros

struct LandmarkEntity: IndexedEntity {
    // Computed — reads from source of truth
    @ComputedProperty
    var isFavorite: Bool { UserDefaults.standard.favorites.contains(id) }

    // Deferred — expensive, fetched only when requested
    @DeferredProperty
    var crowdStatus: Int {
        get async throws { await modelData.getCrowdStatus(self) }
    }
}

Spotlight Integration

struct LandmarkEntity: AppEntity, IndexedEntity {
    static var typeDisplayRepresentation = TypeDisplayRepresentation(
        name: "Landmark", systemImage: "mountain.2"
    )
    var id: String
    var name: String
    var displayRepresentation: DisplayRepresentation {
        DisplayRepresentation(title: "\(name)", image: .init(systemName: "mountain.2"))
    }

    var searchableAttributes: CSSearchableItemAttributeSet {
        let attrs = CSSearchableItemAttributeSet()
        attrs.title = name
        return attrs
    }
}

// Index entities
try await CSSearchableIndex.default().indexAppEntities(landmarks, priority: .normal)

// Remove from index
try await CSSearchableIndex.default().deleteAppEntities(identifiedBy: [id], ofType: LandmarkEntity.self)

Interactive Snippets

struct LandmarkSnippetIntent: SnippetIntent {
    @Parameter var landmark: LandmarkEntity

    var snippet: some View {
        VStack {
            Text(landmark.name).font(.headline)
            HStack {
                Button("Add to Favorites") { }
                Button("Search Tickets") { }
            }
        }.padding()
    }
}

App Shortcuts

struct AppShortcuts: AppShortcutsProvider {
    static var appShortcuts: [AppShortcut] {
        AppShortcut(
            intent: FindNearestLandmarkIntent(),
            phrases: ["Find the closest landmark with \(.applicationName)"],
            systemImageName: "location"
        )
    }
}

Swift Package Support

// In framework
public struct LandmarksKitPackage: AppIntentsPackage { }

// In app target
struct LandmarksPackage: AppIntentsPackage {
    static var includedPackages: [any AppIntentsPackage.Type] {
        [LandmarksKitPackage.self]
    }
}

References