App Intents はじめの三歩

1.9K Views

November 14, 24

スライド概要

「【Sansan × YUMEMI】iOSランチタイムLT」での発表資料です。
https://yumemi.connpass.com/event/333140/

profile-image

フリーランスiOSエンジニア 「エンジニアと人生」コミュニティ主宰

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

(ダウンロード不可)

関連スライド

各ページのテキスト
1.

App Intents はじめの三歩

2.

自己紹介 • 堤 修一 • @shu223 (GitHub, Zenn, Qiita, note, Docswell, 𝕏, YouTube, Podcast, etc...) • 書籍(商業出版4冊、個人出版多数 @BOOTH):

3.

App Intents とは • アプリの「意図(インテント)」をシステムに伝えるもの • アプリの機能をアプリ外の様々な場所から使えるようになる

4.

App Intentsに「今」取り組むモチベーション App Intents対応 ≒ Apple Intelligence対応 Siriがアプリの機能を使ってくれるようになる(iOS 18.?)

5.

どの機能をインテントとして切り出せばいいの? → 全部

6.

アシスタントスキーマ(Assistant Schemes) の話 • 概要: Apple Intelligenceに対応する • 11/19開催のイベントで実践的な話をする予定

7.

本発表の位置付け • App Intentsの概念とApple Intelligenceの関係はわかった • 「全機能切り出そう」というAppleの言い分もわかった • でもどこから始めたらいいの? → はじめの三歩目 ぐらいまでをナビゲーションする 1 1 一歩目だけだとその先に困る、三歩ぐらいやるとユーザー体験として意味のあるインテントがつくれるようになる)

8.

一歩目 アプリを開くだけのイン テント

9.
[beta]
// AppIntentに準拠
struct OpenAppIntent: AppIntent {
// タイトルは必須

static var title: LocalizedStringResource = "Open Hoge"
// インテント実行時にアプリを起動する
static var openAppWhenRun: Bool = true
// インテント実行時の処理
func perform() async throws -> some IntentResult {
// 何もしない

}

}

return .result()

10.

• 既存実装に手をいれる必要がない • 実質5行程度

11.

動作確認 • インテント ≒ (ショートカットアプ リにおける)アクション • アプリをインストールするだけでリ ストに出てくるようになる

12.

二歩目 入力を持つインテント

13.

動画ファイルを入力に受け取ってアプリを開くインテント インテント(アクション)を実行 → 動画選択 → 選択した動画 ファイルを入力としてアプリ起動

14.
[beta]
struct TrimSilenceIntent: AppIntent {

static var title: LocalizedStringResource = ...
static var openAppWhenRun: Bool = true
// 入力パラメータとして動画ファイルを受け取る
@Parameter(title: "Video File", supportedTypeIdentifiers: ["public.movie"])
var video: IntentFile
@MainActor

func perform() async throws -> some IntentResult {
// 動画ファイルのURLにアクセス

guard let videoURL = video.fileURL else { ... }
// 実際の処理
...

}

}

return .result()

15.

@Parameter プロパティラッパー @Parameter(title: "Video File", supportedTypeIdentifiers: ["public.movie"]) var video: IntentFile これを指定したプロパティは、インテントのパラメータ(= ア クションのパラメータ)としてショートカットアプリに表示さ れるようになる

16.

三歩目 出力を持つインテント

17.

動画から音声を抽出するインテント インテント(アクション)を実行 → 動画選択 → 選択した動画 ファイルを入力 → 音声を抽出(バックグラウンド処理) → 音声ファイルを出力

18.
[beta]
struct ExtractAudioIntent: AppIntent {

static var title: LocalizedStringResource = ...
static var description = ...

@Parameter(title: "Video File", supportedTypeIdentifiers: ["public.movie"])
var video: IntentFile

// IntentFile型を返すことを明示
func perform() async throws -> some IntentResult & ReturnsValue<IntentFile> {
guard let videoURL = video.fileURL else { ... }
let audioFileUrl: URL = ...

// 動画から音声データを抽出して audioFileUrl に保存
...
// 音声ファイルを `IntentFile` として出力
let intentFile = IntentFile(fileURL: audioFileUrl)

}

}

return .result(value: intentFile)

19.
[beta]
差分のある perform() メソッドだけ抜粋
// IntentFile型を返すことを明示
func perform() async throws -> some IntentResult & ReturnsValue<IntentFile> {
guard let videoURL = video.fileURL else { ... }
let audioFileUrl: URL = ...

// 動画から音声データを抽出して audioFileUrl に保存
...
// 音声ファイルを `IntentFile` として出力
let intentFile = IntentFile(fileURL: audioFileUrl)
}

return .result(value: intentFile)

20.

ポイント1: ReturnsValue の型をちゃんと指定する before func perform() async throws -> some IntentResult エラーになる: Fatal error: perform() returned types not declared in method signature

21.

ポイント1: ReturnsValue の型をちゃんと指定する after func perform() async throws -> some IntentResult & ReturnsValue<IntentFile>

22.
[beta]
ポイント2: IntentFile 型でファイル出力
ReturnsValue<URL> でファイルURLを出力しても、その音声
を再生できない

func perform() async throws -> some IntentResult & ReturnsValue<URL> {
...

}

return .result(value: audioFileUrl)

23.
[beta]
ポイント2: IntentFile 型でファイル出力
ReturnsValue<IntentFile> で、ファイルを出力する
func perform() async throws -> some IntentResult & ReturnsValue<IntentFile> {
...

let intentFile = IntentFile(fileURL: audioFileUrl)
}

return .result(value: intentFile)

→ 後段のアクション(例:サウンドを再生 / Play sound)
で、抽出した音声ファイルを利用可能に

24.

まとめ • 一歩目:アプリを起動するだけのインテント • 既存実装に手をいれる必要がない • 実質5行程度 • 二歩目:入力を持つインテント • @Parameter プロパティラッパー • 三歩目:出力を持つインテント