2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

INRestaurantReservation: ユーザーの予約情報をSiriに共有して、イベントを自動的に提案する

2
Last updated at Posted at 2021-01-05

あなたがレストラン予約アプリケーション、またはユーザーのために予約を入れるアプリケーション(フライト、列車、チケット)を開発している場合、予約の詳細についてSiriに通知することができます。

この記事では、予約アプリのデモを作成します。ユーザーが予約を行うと、アプリが予約情報をSiriに送信し、Siriは予約情報をカレンダーに追加するようユーザーに促します。予約が閲覧されると、アプリが予約時間を更新します。システムカレンダーアプリが予約情報の更新について、ユーザーに通知するのが確認できます。

利点

Siriに通知することで、ユーザーはイベントをカレンダーに追加するための通知を即座に受け取ります。

イベント会場の詳細情報もSiriによって自動的に入力されます。

また、Siriは予約前に関連情報をユーザーの画面に表示します。

もう一つのメリットは、(予約IDに基づいて)特定の予約イベントに関する最新情報がアプリ上で更新されると、Siriがイベントの詳細を自動的に更新することです。アプリ上で既存の予約に変更があると、システムカレンダーアプリに通知バッジが表示されます。

import intents

Github: https://github.com/mszmagic/SiriReservationSample

ステップ 1. 期間を定める

まず、予約が続行する期間を定める関数を書きます。実演アプリケーションでは、レストランの予約を2時間に設定しました。

private func getReservationPromoteDateRange(_ item: Reservation) -> INDateComponentsRange {
    let calendar = Calendar.autoupdatingCurrent
    // 予約時間の2時間後まで、予約の詳細を閲覧するようユーザーに宣伝しましょう
    let promoteDate_end = calendar.date(byAdding: .hour, value: 2, to: item.bookedTime) ?? item.bookedTime
    let promoteDate_end_components = calendar.dateComponents(in: TimeZone.autoupdatingCurrent, from: promoteDate_end)
    let promoteDate_start = item.bookedTime
    let promoteDate_start_components = calendar.dateComponents(in: TimeZone.autoupdatingCurrent, from: promoteDate_start)
    //
    return .init(start: promoteDate_start_components, end: promoteDate_end_components)
}

ステップ 2. 予約名を定める

予約項目に対して固有の識別名を作成する必要があります。

let reservation_item = INSpeakableString(vocabularyIdentifier: item.reservationID, spokenPhrase: "\(item.restaurantName)の予約", pronunciationHint: nil)

ステップ 3. 予約を見る時に実行するアクションを定める

それから、ユーザーが予約を見たい時に実行するアクションを定めます。URLを提供することもできます。これらの情報は、ユーザーが特定の予約項目を見たい時に、どのようなアクションを実行するかをSiriが認識するために使用されます:

private func getViewReservationDetailsAction(_ item: Reservation) -> INReservationAction {
    let viewDetailsAction = NSUserActivity(activityType: "com.example.SiriReservationSample.viewReservationDetails")
    let reservationDateStr = DateFormatter.localizedString(from: item.bookedTime, dateStyle: .short, timeStyle: .short)
    viewDetailsAction.title = "\(item.restaurantName)における\(reservationDateStr)での予約状況の詳細を表示します"
    viewDetailsAction.userInfo = ["reservationID" : item.reservationID]
    viewDetailsAction.requiredUserInfoKeys = ["reservationID"]
    viewDetailsAction.webpageURL = generateReservationURL(item)
    return .init(type: .checkIn,
                 validDuration: getReservationPromoteDateRange(item),
                 userActivity: viewDetailsAction)
}

ステップ4. 予約オブジェクトを決めてください

let reservation = INRestaurantReservation(itemReference: reservation_item,
                                          reservationNumber: item.reservationID,
                                          bookingTime: item.bookedTime,
                                          reservationStatus: item.reservation_status,
                                          reservationHolderName: item.personName,
                                          actions: reservation_actions,
                                          url: generateReservationURL(item),
                                          reservationDuration: getReservationPromoteDateRange(item),
                                          partySize: item.reservation_partySize,
                                          restaurantLocation: item.restruantLocation)
Variable name Explanation
itemReference 参照IDオブジェクト reservation_item
reservationNumber 予約ID
bookingTime ユーザーがこの予約を入れる時間
reservationStatus 予約状況
reservationHolderName この予約を行なった人物の名前
actions この例における関数 getViewReservationDetailsAction() のアウトプット
url ユーザーが予約詳細へアクセスするためのURLアドレス(ウェブページ)
reservationDuration 予約の開始と終了を定めてください。getReservationPromoteDateRange() 機能の出力
partySize この予約の対象人数
restaurantLocation レストランの所在地 CLPlacemark

ステップ5.予約についてシステムに入力してください。

ここで、予約についてシステムに入力する必要があります。

let intent = INGetReservationDetailsIntent(reservationContainerReference: reservation_item, reservationItemReferences: nil)
let response = INGetReservationDetailsIntentResponse(code: .success, userActivity: nil)
response.reservations = [reservation]
let interaction = INInteraction(intent: intent, response: response)
interaction.donate(completion: completionHandler)

これで、カレンダーのイベントに追加するためのSiriのメッセージがユーザーに表示されます。

関数を呼び出すタイミング

ユーザーが予約を閲覧するたびに(情報が変更されていなくても)上記の関数を呼び出す必要があります。予約の詳細が変更された場合は、Siriがカレンダーアプリを通じてユーザーに通知します。

なお、1つの予約に対してご自分の予約IDが同じであることを確認することが重要です。

ステップ6. NSUserActivityTypes

プロジェクトの設定から Info タブに移動し、サポートされているアクティビティタイプの情報を追加します。上のコードでは、アクティビティタイプとして com.example.SiriReservationSample.viewReservationDetails を使用しています。

ステップ 7. Siriでのアプリケーションの起動を処理

ユーザーが予約の閲覧を希望する場合、Siriでアプリケーションを起動する事ができます。

SceneDelegate.swift ファイル内に次の関数を追加してください:

func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
    if userActivity.activityType == "INGetReservationDetailsIntent" {
        //
    }
}

こちらが予約IDをフェッチする方法です:

if let userActivity = notificationObject.object as? NSUserActivity,
   let intentObject = userActivity.interaction?.intent as? INGetReservationDetailsIntent,
   let reservationName = intentObject.reservationItemReferences?.first,
   let reservationID = reservationName.vocabularyIdentifier {
    DispatchQueue.main.async {
        self.viewingReservationID = .init(reservationID: reservationID)
    }
}

userInfo プロパティの利用を試みましたが、そこには、予約IDは含まれていないようです。つきましては、代わりに上記のコードを使って予約IDを取得してください

以前のコードの設定:

let reservation_item = INSpeakableString(vocabularyIdentifier: item.reservationID, spokenPhrase: "\(item.restaurantName)の予約", pronunciationHint: nil)

従って、変数 vocabularyIdentifier にアクセスすると、item.reservationID が得られます。


:relaxed: Twitter @MszPro

:sunny: 私の公開されているQiita記事のリストをカテゴリー別にご覧いただけます。

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?