App Intents’i 3 projede uyguladım. Doğru tasarlandığında kullanıcının uygulamayı açmadan işini görmesini sağlıyor; Shortcuts app, Siri, Spotlight ve hatta Focus Mode filter’ları üzerinden tetiklenebiliyor. Yanlış tasarlandığında ise görünmez bir özellik olarak kalıyor.
Temel bir intent: görev ekleme
import AppIntents
struct AddTaskIntent: AppIntent {
static var title: LocalizedStringResource = "Görev Ekle"
static var description = IntentDescription("Listeye hızlı görev ekle")
@Parameter(title: "Görev") var text: String
func perform() async throws -> some IntentResult & ProvidesDialog {
try await TaskStore.shared.add(text)
return .result(dialog: "Eklendi: (text)")
}
}Bu kadar basit bir intent bile Shortcuts app’te görünüyor ve Siri ile “uygulama adı, görev ekle X” diyerek tetikleniyor. Ek Info.plist veya storyboard gerekmiyor.
AppShortcutsProvider: görünürlük için şart
Intent’i tanımlamak yetmiyor; kullanıcının keşfedebilmesi için AppShortcutsProvider gerekiyor:
struct MyAppShortcuts: AppShortcutsProvider {
static var appShortcuts: [AppShortcut] {
AppShortcut(
intent: AddTaskIntent(),
phrases: [
"(.applicationName) ile görev ekle",
"(.applicationName)'a görev ekle"
],
shortTitle: "Görev Ekle",
systemImageName: "plus.circle"
)
}
}Phrases kısmı kritik; Türkçe ekli-ek kurallarına dikkat etmek gerekiyor. applicationName placeholder’ı app ismini koyuyor; örneğin uygulama adı “Not” ise “Not ile görev ekle” çıkıyor.
Parametrize intent
Bir görevin önceliğini parametre olarak almak istersen:
enum Priority: String, AppEnum {
case low, medium, high
static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "Öncelik")
static var caseDisplayRepresentations: [Priority: DisplayRepresentation] = [
.low: "Düşük", .medium: "Orta", .high: "Yüksek"
]
}
struct AddTaskIntent: AppIntent {
@Parameter(title: "Görev") var text: String
@Parameter(title: "Öncelik") var priority: Priority
func perform() async throws -> some IntentResult {
try await TaskStore.shared.add(text, priority: priority)
return .result()
}
}Shortcuts app parametreyi dropdown olarak gösteriyor. Siri çağrısında parametre eksikse kullanıcıya soru soruyor.
EntityQuery: entity’lerle çalışma
“Görevi tamamla” intent’i için hangi görevi seçeceğini kullanıcıya sorman gerekiyor. Bunu AppEntity ve EntityQuery ile yapıyorsun:
struct TaskEntity: AppEntity {
static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "Görev")
static var defaultQuery = TaskQuery()
let id: UUID
let title: String
var displayRepresentation: DisplayRepresentation {
DisplayRepresentation(title: "(title)")
}
}
struct TaskQuery: EntityQuery {
func entities(for identifiers: [UUID]) async throws -> [TaskEntity] {
try await TaskStore.shared.fetch(ids: identifiers)
}
func suggestedEntities() async throws -> [TaskEntity] {
try await TaskStore.shared.fetchOpen(limit: 10)
}
}Focus Filter: projede kullandığım senaryo
Çalışma Focus’unda sadece iş görevleri görünsün; Kişisel Focus’ta kişisel olanlar. SetFocusFilterIntent ile kullanıcı Focus Mode ayarında uygulama filter’ımı görüyor:
struct WorkFocusFilter: SetFocusFilterIntent {
static var title: LocalizedStringResource = "Çalışma Görevleri"
@Parameter(title: "Tag") var tag: String
func perform() async throws -> some IntentResult {
UserDefaults.standard.set(tag, forKey: "focusTag")
NotificationCenter.default.post(name: .focusChanged, object: nil)
return .result()
}
}Ana uygulama açıldığında focusTag‘i okuyup listeyi filtreliyor.
Interactive widget ile entegre
iOS 17 widget’larında button ve toggle, App Intent’i direkt tetikleyebiliyor. Benim todo widget’ımda checkbox tıklandığında:
Button(intent: ToggleTaskIntent(taskId: task.id)) {
Image(systemName: task.isDone ? "checkmark.circle.fill" : "circle")
}Widget refresh otomatik oluyor; ayrıca timeline reload çağırmana gerek kalmıyor.
Pitfall: async’ten dialog dönmek
Intent async işlem sırasında dialog göstermek istiyorsan ProvidesDialog trait’ini ekle ve .result(dialog:) döndür. Sadece .result() döndürürsen Siri sessiz kalıyor, kullanıcı ne oldu anlamıyor.
Localization
LocalizedStringResource kullandığın her yerde String Catalog (.xcstrings) entegrasyonu otomatik yapılıyor. Ama phrase’lerdeki interpolation parametreleri için ekstra özen lazım; Türkçe’nin ek yapısı İngilizce sabit kalıp varsayımını bozuyor.
Son tavsiye
3 iyi intent, 30 eksik intent’ten değerli. Kullanıcıların sana 3 hızlı aksiyonla erişmesi, uygulamayı günlük kullanımına oturtmaya yetiyor. Silip takılmayan özellik böyle çıkıyor.