Section 2/181 menit
2. Masalah yang Dipecahkan
2. Masalah yang Dipecahkan
SiriKit: Boilerplate Besar, Fleksibilitas Rendah
swift
// ❌ TANPA App Intents: SiriKit INIntent — file .intentdefinition + code gen + delegate
// File: OrderCoffeeIntent.intentdefinition (XML, dikelola Xcode)
// + INExtension handler di separate target
// + NSExtensionPrincipalClass di Info.plist
class OrderCoffeeIntentHandler: NSObject, OrderCoffeeIntentHandling {
// Confirm phase — wajib implement
func confirm(intent: OrderCoffeeIntent, completion: @escaping (OrderCoffeeIntentResponse) -> Void) {
completion(OrderCoffeeIntentResponse(code: .ready, userActivity: nil))
}
// Handle phase — wajib implement
func handle(intent: OrderCoffeeIntent, completion: @escaping (OrderCoffeeIntentResponse) -> Void) {
// Akses data dari UI app via shared container atau XPC
// Karena Intent Extension berjalan di separate process!
let sharedDefaults = UserDefaults(suiteName: "group.com.myapp")
let menuItems = sharedDefaults?.array(forKey: "menu") as? [[String: Any]] ?? []
// Masalah: separate process = tidak bisa akses langsung model layer app
// Masalah: INIntent hanya untuk domain tertentu (Messages, Calls, dll)
// Masalah: Customization sangat terbatas
completion(OrderCoffeeIntentResponse.success(totalPrice: 25000))
}
// Resolve setiap parameter secara terpisah
func resolveDrinkType(for intent: OrderCoffeeIntent,
with completion: @escaping (DrinkTypeResolutionResult) -> Void) {
guard let drinkType = intent.drinkType else {
completion(.needsValue())
return
}
completion(.success(with: drinkType))
}
}
swift
// ✓ DENGAN App Intents: pure Swift struct, berjalan in-process, tidak ada code gen
struct OrderCoffeeIntent: AppIntent {
static var title: LocalizedStringResource = "Pesan Kopi"
static var description = IntentDescription("Pesan kopi favorit kamu dari cafe terdekat")
@Parameter(title: "Jenis Minuman")
var drinkType: DrinkEntity
@Parameter(title: "Ukuran", default: .medium)
var size: CoffeeSize
func perform() async throws -> some IntentResult & ProvidesDialog {
// Langsung akses service layer app — in-process!
let order = try await CoffeeService.shared.placeOrder(drink: drinkType, size: size)
return .result(dialog: "Pesanan \(drinkType.name) \(size.rawValue) sudah diterima!")
}
}
NSUserActivity: Tidak Ada Parameter Dinamis
swift
// ❌ TANPA App Intents: NSUserActivity — tidak ada parameter interaktif
class SceneDelegate: UIResponder, UISceneDelegate {
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
// Hanya bisa pass data statis via userInfo dictionary
// Tidak bisa tanya user parameter saat runtime
// Tidak ada parameter completion / disambiguation
guard let productID = userActivity.userInfo?["productID"] as? String else { return }
navigateToProduct(id: productID)
}
}
swift
// ✓ DENGAN App Intents: parameter interaktif, Siri bisa tanya user jika perlu
struct OpenProductIntent: AppIntent {
static var title: LocalizedStringResource = "Buka Produk"
@Parameter(title: "Produk")
var product: ProductEntity // Siri tanya "Produk mana?" jika tidak disebut
static var openAppWhenRun: Bool = true
func perform() async throws -> some IntentResult {
await MainActor.run {
NavigationService.shared.navigate(to: product)
}
return .result()
}
}