[iOS 12]Siri Shortcutsの最小実装 – Intent編

この記事は iOS (その2) Advent Calendar 2018 の 14 日目の記事です。

こんにちは。
iOSエンジニアの玉井(@tamadon3776)です。

今回はマネーフォワード MEのiOSアプリで実装したSiri Shortcutsについてご紹介します。

Siri Shortcutsの実装方法はNSUserActivityを用いた方法とIntentsを用いた方法がありますが、本記事ではIntentsを用いたSiri Shortcutsの最小実装 だけ を紹介します。

NSUserActivityを用いた方法については、本Advent Clendar1日目の[iOS 12]Siri Shortcutsの最小実装 – NSUserActivity編 が参考になるかと思います。
タイトルを真似させてもらいました。

実装方法を理解するためにサンプルアプリを作成しました。
SiriShortcutIntentSample

サンプルアプリの仕様

  • ラーメン二郎のトッピングをUITextFieldに入力する
  • キーボードのdoneボタンを押すと入力した内容が画面上部のUILabelに反映される
  • リセットボタンを押すとUITextFieldとUILabelがクリアされる
  • 確定したトッピングはSiri Shortcutsで呼び出せる
  • Siri Shortcuts経由でアプリを起動すると○○を注文するの○○が画面上部のUILabelに反映される

実装手順

  • Intentの定義
  • ShortcutのDonate
  • Shortcutのハンドル

Intentの定義

まずはIntentを定義します。Intentとはアプリケーションが実行可能なタスクの事です。

今回はトッピングを注文するというIntentが必要ですが、標準で提供されているSend MessageやSend Payment等のIntentとは合致しないため、Custom Intentを作成します。

Xcode10以上で追加されたIntent Definition fileという形式のファイルを追加し、Intentのタイトル・パラメータ等を定義していきます。

Project Navigatorで右クリック > New File… > SiriKit Intent Definition File

といった操作で追加出来ます(intentで検索すると早いです)

Intentを定義後にビルドすると、Intent Definition fileの内容を元にしたprotocolやclassを定義するコードが自動生成されます。

自動生成されると、このようにXcode上でコードが補完されるようになります。

普通に開発する時は自動生成されたファイルを意識する必要が無さそうですが、補完されない時は以下の点を確認してみると良いかもしれません。

  • コードは自動生成されているか
    • 参考までに、僕の環境では以下のパスに出力されていました。環境毎に異なると思います。
~/Library/Developer/Xcode/DerivedData/SiriShortcutIntentSample-geeepxpeibgscnbhikvkajsbuopy/Build/Intermediates.noindex/SiriShortcutIntentSample.build/Debug-iphonesimulator/SiriShortcutIntentSample.build/DerivedSources/IntentDefinitionGenerated/Intents/ToppingIntent.swift

ShortcutのDonate

Intentの定義が出来たら、ShortcutのDonate処理を記述しましょう。
Donate処理とは『ユーザーがアプリ上で行った操作をSiriに伝える』みたいな意味だと理解しています。
Donating Shortcuts-Apple

Intentを作成してパラメータをセットしたら、それを元にINInteractionを作成しdonateメソッドを呼ぶだけです。
注意点としては、パラメータ(サンプルコードではtopping)がnilだとdonateに失敗する事くらいでしょうか。

let intent = ToppingIntent()
intent.topping = text

let interaction = INInteraction(intent: intent, response: nil)
interaction.donate { error in
    if let error = error as NSError? {
        print(error.localizedDescription)
    }
}

Shortcutのハンドル

最後にShortcut経由のアプリ起動をハンドリングします。

Shortcut経由のアプリ起動時、UIApplicationDelegateのapplication(_:continue:restorationHandler:)が呼ばれます。

そこでNSUserActivityが引数として渡されてくるのでハンドリングすれば完成です。

func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
    if userActivity.activityType == String(describing: ToppingIntent.self) {
        guard let intent = userActivity.interaction?.intent as? ToppingIntent,
            let topping = intent.topping,
            let window = self.window,
            let vc = window.rootViewController as? ViewController else {
                return false
        }

        vc.topping = topping
        return true
    }
    return false
}

ここでの処理は引数のuserActivityからactivityTypeを判別し、userActivity.interaction.intentのパラメータを取得して遷移するViewControllerの変数に代入しているだけです。

まとめ

いかがでしたでしょうか。
結構簡単に実装出来ることがご理解いただけたかと思います。

ユーザーからのリクエストに対してバックグラウンドで処理を行いたい場合はIntents App Extensionを使用する必要があるのですが、今回は最小実装を目指したので割愛しています。

こちらの実装が気になる方はAppleからサンプルコードが提供されているので、参考にしてください。
Soup Chef: Accelerating App Interactions with Shortcuts

最後に

マネーフォワードでは、一緒に働いてくれるiOSエンジニアを募集しています。
ご応募お待ちしています。

【採用サイト】
マネーフォワード採用サイト
Wantedly | マネーフォワード

【マネーフォワードのプロダクト】
自動家計簿・資産管理サービス『マネーフォワード ME』 iPhone,iPad Android

「しら」ずにお金が「たま」る 人生を楽しむ貯金アプリ『しらたま』 iPhone,iPad

おトクが飛び出すクーポンアプリ『tock pop トックポップ』

金融商品の比較・申し込みサイト『Money Forward Mall』

くらしの経済メディア『MONEY PLUS』

■ビジネス向けクラウドサービス『マネーフォワードクラウドシリーズ』
バックオフィス業務を効率化『マネーフォワードクラウド』
会計ソフト『マネーフォワードクラウド会計』
確定申告ソフト『マネーフォワードクラウド確定申告』
請求書管理ソフト『マネーフォワードクラウド請求書』
給与計算ソフト『マネーフォワードクラウド給与』
経費精算ソフト『マネーフォワードクラウド経費』
マイナンバー管理ソフト『マネーフォワードクラウドマイナンバー』
資金調達サービス『マネーフォワードクラウド資金調達』

Pocket