Broaden your reach with Siri Event Suggestions
System & Services 进阶 22m

通过 Siri 事件建议扩大应用触达

Broaden your reach with Siri Event Suggestions

2020年6月25日

在 Apple 官方观看视频

一句话判断

如果你的应用处理日历事件、机票、酒店预订等信息但没有接入 Siri Event Suggestions,你正在错过一个免费的系统级曝光入口。

这场 Session 讲了什么

Siri Event Suggestions 让你的应用可以向系统捐赠事件信息(如航班、酒店预订、餐厅预约等),这些信息会自动出现在日历、地图、Siri 建议等系统界面中。Session 详细介绍了如何使用 INInteraction 和相关的 Intent 类型来捐赠事件,以及系统如何利用这些信息为用户提供主动建议。

核心机制是 Intent Donation。当用户在你的应用中完成一个事件相关的操作时(如预订了一顿晚餐),你可以创建一个 INReservationINPayment Intent 并捐赠给系统。Siri 会学习用户的使用模式,在合适的时间和地点主动展示相关建议。比如用户每周五晚上都在你的应用上点同一家餐厅的外卖,Siri 会在周五下午建议”点外卖”。

Session 覆盖了多种事件类型:餐厅预约(INRestaurantReservation)、航班信息(INFlightReservation)、酒店预订(INLodgingReservation)、火车/巴士票务(INTrainTrip)等。每种类型都有对应的结构化数据模型,包含时间、地点、参与者、确认码等信息。

值得深挖的点

事件捐赠与 Siri 建议的学习循环

Siri 的建议系统基于用户行为模式学习。你捐赠的事件越完整(包含准确的时间、地点、类型信息),Siri 的学习效果越好。学习循环是:你捐赠事件 -> Siri 学习模式 -> Siri 在合适时机建议 -> 用户点击建议 -> 你的应用获得流量。这是一个正向循环——你提供的信号越强,获得的回报越大。

结构化数据的重要性

捐赠事件时,务必提供完整的结构化数据。比如一个餐厅预约,不要只提供餐厅名称,还要提供地址、预约时间、人数、确认码。这些数据越完整,系统在日历、地图等界面上的展示就越丰富,用户点击进入你应用的概率就越高。

代码片段

import Intents

// 捐赠餐厅预约事件
class ReservationDonor {
    
    func donateRestaurantReservation(
        restaurant: Restaurant,
        date: Date,
        partySize: Int,
        confirmationCode: String
    ) {
        // 创建餐厅对象
        let restaurantObject = INRestaurant(
            name: restaurant.name,
            location: CLPlacemark(
                location: CLLocation(latitude: restaurant.lat, longitude: restaurant.lng),
                name: restaurant.name,
                postalAddress: restaurant.postalAddress
            ),
            provider: nil,
            category: .restaurant,
            reserveAction: nil
        )
        
        // 创建预约 Intent
        let intent = INListRideOptionsIntent()
        
        // 使用 INReservation 捐赠
        let reservation = INRestaurantReservation(
            restaurant: restaurantObject,
            reservationDate: date,
            partySize: NSNumber(value: partySize),
            bookingDate: Date(),
            reservationNumber: confirmationCode
        )
        
        let interaction = INInteraction(reservation: reservation, intent: nil)
        interaction.donate { error in
            if let error = error {
                print("预约事件捐赠失败: \(error)")
            } else {
                print("预约事件捐赠成功")
            }
        }
    }
}
// 捐赠航班信息
class FlightDonor {
    
    func donateFlightReservation(
        flightNumber: String,
        departureAirport: String,
        arrivalAirport: String,
        departureTime: Date,
        arrivalTime: Date,
        airline: String,
        passengerName: String
    ) {
        // 创建航班行程
        let departure = INAirport(
            name: departureAirport,
            location: nil,
            terminal: nil,
            gate: nil
        )
        let arrival = INAirport(
            name: arrivalAirport,
            location: nil,
            terminal: nil,
            gate: nil
        )
        
        let flight = INFlight(
            flightNumber: flightNumber,
            airline: airline,
            departureAirport: departure,
            arrivalAirport: arrival,
            departureTime: departureTime,
            arrivalTime: arrivalTime
        )
        
        let reservation = INFlightReservation(
            itemRef: INSpeakableString(spokenPhrase: "航班 \(flightNumber)"),
            reservationNumber: flightNumber,
            bookingTime: Date(),
            reservationStatus: .confirmed,
            reservationHolderName: INPerson(
                personHandle: nil,
                nameComponents: PersonNameComponents(givenName: passengerName),
                displayName: passengerName,
                image: nil,
                contactIdentifier: nil,
                customIdentifier: nil
            ),
            actions: [],
            flight: flight,
            passengers: []
        )
        
        let interaction = INInteraction(reservation: reservation, intent: nil)
        interaction.donate { error in
            if let error = error {
                print("航班事件捐赠失败: \(error)")
            }
        }
    }
}
// 捐赠通用事件建议
class EventDonor {
    
    func donateCustomEvent(title: String, date: Date, location: String?) {
        // 使用 INTask 或自定义 Intent 捐赠通用事件
        let intent = INSearchForItemsIntent()
        
        // 或者使用 userActivity 捐赠
        let activity = NSUserActivity(
            activityType: "com.example.app.event"
        )
        activity.title = title
        activity.userInfo = [
            "eventDate": date.timeIntervalSince1970,
            "location": location ?? "",
        ]
        activity.isEligibleForSearch = true
        activity.isEligibleForPrediction = true
        
        // 设置 Siri 建议短语
        if #available(iOS 12, *) {
            activity.suggestedInvocationPhrase = "查看\(title)"
        }
        
        activity.becomeCurrent()
        print("事件已捐赠: \(title)")
    }
}

最佳实践

  • 在用户完成每个关键操作后立即捐赠事件,不要批量延迟捐赠
  • 提供尽可能完整的结构化数据——地址、时间、确认码、参与者信息缺一不可
  • 为捐赠的事件设置 suggestedInvocationPhrase,帮助用户用语音触发
  • 定期检查捐赠日志,确认事件是否成功传递给系统
  • 不要捐赠虚假或推测性的事件——只捐赠用户实际完成的操作

还有什么值得关注

  • Siri Event Suggestions 的数据与 Spotlight 索引共享,你的捐赠也会提升应用的搜索排名
  • 捐赠的事件在系统日历中可能以”Siri 建议”的形式出现,用户可以一键添加到日历
  • Session 提到 CarPlay 也支持 Siri Event Suggestions,驾驶场景下的语音触发特别有价值
WWDC 2020