2.4K Views
October 04, 25
スライド概要
CA.unity #10 での講演資料です。
https://cyberagent.connpass.com/event/366674/
# 目次
## 1. オーディオの制御
- Unity for iOS でのオーディオ制御はどうなっているのか?
- iOS でのオーディオ制御に関する概要 (AVAudioSession について)
- Unity においての制御や注意点など
## 2. ハプティックフィードバック
- ハプティックフィードバックに関する概要
- どういったところで用いると良いのか?など
iOSプラットフォーム向けの 開発Tips 2025/09/30 mao
mao •所属: 株式会社アプリボット Unity エンジニア / LDX (Lead Developer Experience) ・システム系の基盤開発や開発支援など ・プラットフォーム固有の機能を使うためのネイティブプラグイン実装 •個人活動など X: mao🐑 (@TEST_H_) / X Qiita: mao_ - Qiita 最近は Unity x iOS に関するマニアックなネタをよく投稿 GitHub: mao-test-h · GitHub
この講演について
この講演について •iOS プラットフォーム向けに以下のトピックについて解説します 1. オーディオの制御 ・Unity for iOS でのオーディオ制御はどうなっているのか? ・iOS でのオーディオ制御に関する概要 ・AVAudioSession について ・Unity においての制御や注意点など 2. ハプティックフィードバック ・ハプティックフィードバックに関する概要 ・どういったところで用いると良いのか?など •講演の目的 : iOS ネイティブに関する機能を把握しておくことで、 今後の開発や不具合調査などに活かすための足掛かりとしていただけると幸いです
話さないこと •ネイティブプラグイン開発に関する話は割愛します 今回はあくまで機能について把握すること を目的としているので、プラグイン開発周りの話題は薄くして あります ・気になる方は拙作ですが、以下の記事を参照していただけると幸いです 【Unity】iOSネイティブプラグイン開発を完全に理解する 【Unity】iOSネイティブプラグイン開発を完全に理解する - サンプルコードを Swiftだけで完結 出来るように置き換える ※スライドは講演終了後に公開予定
注意点 •今回の資料は以下の環境を元に検証してます ・Unity 6000.0.57f1 ・Xcode 16.4 ※バージョンによって挙動が変わる可能性がある旨についてはご了承ください ・次で話す「オーディオの制御について」の章は、 Unity 標準のオーディオシステムを使うことを前提としてます ・もし他のオーディオミドルウェアなどを導入している場合には Unity 周りの動作が異なっている可能性が あるので、その点についてもご了承ください...! ・あとは Unity のオーディオ制御はブラックボックスな部分も多く、一部は挙動などから推測した部分も含 んでます
オーディオの制御について
この章で話すこと •iOS アプリにおけるオーディオ制御はどうやるのか? ・ミュージックアプリで音楽を再生中にアプリを開いた際の挙動を制御するには? → ミックスして再生を行う / ダッキングして再生、ミュージックアプリの再生を停止するなど ・バックグラウンド再生を行うには? ※バックグラウンド再生 == アプリがバックグラウンドに回った状態でもサウンドを再生する方法 ・サイレントモード時にオーディオを再生させないようにするには? •上記の基礎を抑えつつ Unity アプリでの特性について解説します ・Unity ではどのような設定になっているのか?設定を変更するにはどうしたら良いか? ・設定変更する上での注意点など
この章で話すこと その上で以下の点について持ち帰って頂けると幸いです •オーディオ制御を理解して使いこなす上での概要 •オーディオ制御に関するプラグインを実装する際、またはサードパーティプラグインを導入 する際の心構えなど → 例えば導入したら音が鳴らなくなったみたいな問題が起きた際のトラブルシューティングなど
Unityでのオーディオ制御は どうなっているのか?
Unityでのオーディオ制御はどうなっているのか? •デフォルト設定では以下のような動作になってます ・音楽アプリなどでバックグラウンド再生している状態でアプリを開いた場合にはミックスされる ※ただし、一部の API 実行中には挙動が変わったりします。詳しくは後述 ・バックグラウンド再生は出来ない ・サイレントモードの影響を受ける
Unityでのオーディオ制御はどうなっているのか? •デフォルト設定では以下のような動作になってます ・音楽アプリなどでバックグラウンド再生している状態でアプリを開いた場合にはミックスされる ※ただし、一部の API 実行中には挙動が変わったりします。詳しくは後述 ・バックグラウンド再生は出来ない ・サイレントモードの影響を受ける •→ ではこれらの制御はどう行われているのか? ・これらの動作はネイティブ側にある「AVAudioSession」と言う API を用いて制御を行います ・Unity も例外的ではなく、内部的にはこちらを用いて制御しているかと思われました → まずは AVAudioSession とは何なのか?と言う話から解説していきます
iOS でのオーディオ制御に関する概要
オーディオシステムの制御について •iOS (Apple Platform) にはアプリがシステムに オーディオをどう扱うかを伝えるための機能として AVAudioSession と言うクラスがあります •まずはこちらについての簡単な概要の解説から入り、 その後に「 Unity ではどう扱われているのか? 」「制御する 上での注意点 」などについて触れていきます https://developer.apple.com/documentation/avfaudio/avaudiosession
AVAudioSession について •アプリがシステムにオーディオをどう扱うかを伝えるための機能 ・実態としてはシングルトンなインスタンスであり、こちらを経由してアプリ全体 の設定を行う ・通常、Unity を使う上ではエンジンが裏で制御を行なっている (詳しくは後述) •具体的に言うと以下のような制御を行える ・ミュージックアプリで音楽を再生中にアプリを開いた際の挙動を制御 → ミックスして再生を行う / ダッキングして再生、ミュージックアプリの再生を停止するなど ・バックグラウンド再生を行うか ・サイレントモード時にオーディオを止めるかどうか ・セッションの有効化 / 無効化 ・各種設定値の取得や再設定、イベントの購読など → サンプルレート、チャンネル数、システム音量、ルーティングの変更通知など
AVAudioSession について •アプリがシステムにオーディオをどう扱うかを伝えるための機能 ・実態としてはシングルトンなインスタンスであり、こちらを経由してアプリ全体の設定を行う 今回はこちらについて具体的に解説していきます ・通常、Unity を使う上ではエンジンが裏で制御を行なっている (詳しくは後述) •具体的に言うと以下のような制御を行える ・ミュージックアプリで音楽を再生中にアプリを開いた際の挙動を制御 → ミックスして再生を行う / ダッキングして再生、ミュージックアプリの再生を停止するなど ・バックグラウンド再生を行うか ・サイレントモード時にオーディオを止めるかどうか ・セッションの有効化 / 無効化 ・各種設定値の取得や再設定、イベントの購読など → サンプルレート、チャンネル数、システム音量、ルーティングの変更通知など
では具体的にどう設定するのか? •AVAudioSession では以下の項目を設定することで、アプリがオーディオをどのように扱うか を決めます ・Category → アプリ全体のオーディオの動作を定義 ・Mode → より具体的な利用シナリオ ・CategoryOption → Category を補完する追加フラグ ・setActive → セッションの有効化 / 無効化
では具体的にどう設定するのか? •AVAudioSession では以下の項目を設定することで、アプリがオーディオをどのように扱うか を決めます ・Category → アプリ全体のオーディオの動作を定義 ・Mode → より具体的な利用シナリオ ・CategoryOption → Category を補完する追加フラグ ・setActive → セッションの有効化 / 無効化
Category について •アプリ全体のオーディオの動作を定義する項目 •設定可能な項目としては次のようなものがあります (次ページへ ) https://developer.apple.com/documentation/avfaudio/avaudiosession/category-swift.struct
Category について •ambient ・他のアプリ(ミュージックアプリなど)でサウンドを流している場合にはミックスされる ・画面ロックやサイレントモードの影響を受ける (消音される) ・Unity はデフォルトだとこちらが設定されている •soloAmbient ・他のアプリでサウンドを流している場合にはミックスされない ・画面ロックやサイレントモードの影響を受ける (消音される) •playback ・ミックスはオプションを設定すれば可能 ・サイレントモードの影響を受けない ・サイレントモードに設定していても音声が再生される ・設定を加えればバックグラウンド再生も可能 (詳しくは後述 ) https://developer.apple.com/documentation/avfaudio/avaudiosession/category-swift.struct
Category について •record ・録音用のカテゴリであり、オーディオ再生は不可 ・設定を行えばバックグラウンドでの利用も可能 •playAndRecord ・オーディオの再生と録音の両方を行うカテゴリ ・record と同じく設定を行えばバックグラウンドの利用も可能 ・Unity の場合には Microphone API の Start を呼び出すと、End を呼び出すまでの間は 自動的にこちらが設定される •multiRoute ・オーディオを異なるデバイスに出力する際のカテゴリ ・(詳細についてはあまり調べきれておらず...) https://developer.apple.com/documentation/avfaudio/avaudiosession/category-swift.struct
では具体的にどう設定するのか? •AVAudioSession では以下の項目を設定することで、アプリがオーディオをどのように扱うか を決めます ・Category → アプリ全体のオーディオの動作を定義 ・Mode → より具体的な利用シナリオ ・CategoryOption → Category を補完する追加フラグ ・setActive → セッションの有効化 / 無効化
Mode について •より具体的な利用シナリオを決定する項目 ・default ・gameChat ・measurement ・moviePlayback ・etc... •設定に応じて信号処理や挙動などが最適化される模様 参考: AVAudioSessionの深い話 •Unity だと `default` が設定される https://developer.apple.com/documentation/avfaudio/avaudiosession/mode-swift.struct
では具体的にどう設定するのか? •AVAudioSession では以下の項目を設定することで、アプリがオーディオをどのように扱うか を決めます ・Category → アプリ全体のオーディオの動作を定義 ・Mode → より具体的な利用シナリオ ・CategoryOption → Category を補完する追加フラグ ・setActive → セッションの有効化 / 無効化
CategoryOption について •Category の動作を補完する追加フラグ ・mixWithOther → 他のアプリのオーディオとミックスするか ・dockOthers → ミックスする際にダッキングを行うか ・AllowBluetothA2DP ・defaultToSpeaker ・etc... •カテゴリーの設定に応じて自動で設定される物もある ・例えば Category に ambient を指定すると、mixWithOthers が自 動で設定される ・他にもオプションに duckOthers を設定すると、mixWithOthers も 合わせて自動で設定されるなど https://developer.apple.com/documentation/avfaudio/avaudiosession/categoryoptions-swift.struct
では具体的にどう設定するのか? •AVAudioSession では以下の項目を設定することで、アプリがオーディオをどのように扱うか を決めます ・Category → アプリ全体のオーディオの動作を定義 ・Mode → より具体的な利用シナリオ ・CategoryOption → Category を補完する追加フラグ ・setActive → セッションの有効化 / 無効化
セッションの有効化 / 無効化 •オーディオセッションの有効化 / 無効化を設定 ・オーディオを利用する旨をシステムにリクエストする ・通常の iOS アプリであれば、例えばオーディオを扱うタイミング でセッションを有効化し、終わったら無効化すると言ったケースが 考えられる ※ただし Unity の場合には少しケースが変わるかもです。詳細はのちほど •Option に notifyOthersOnDeactivation を渡すことで、セッ ションが中断されていた他のアプリに無効化したことを通知 することができるようになる → 対応アプリで通知を受け取った際に再生復帰などを行える (e.g. 音楽アプリなら音楽再生を再開するなど) https://developer.apple.com/documentation/avfaudio/avaudiosession/setactive(_:options:)
Unity ではどう扱われているか?
Unityでのセッションの扱い •Unity では初期化時のタイミングにセッションが有効化されている ・iOS ビルドで出力される UnityAppController.mm のコードを読むに、初期化タイミングでセッションを有効 化しているように思われた ※ Audio Settings -> Disable Unity Audio の ON/OFF で呼び出しが変わってそうだった ・→ なのでこちらから明示的に呼び出す必要はない
Unityでのセッションの扱い •逆に言うとセッションの管理はエンジンが行なっているので、 こちらからの無効化などは意図しない挙動になる可能性があるので注意 ・試しに手元で setActive(false) を呼び出した後に、再度 setActive(true) で有効化してみたところ、Unity 側 の AudioSource などが鳴らなくなる現象を確認 •Discussions / Issue などを探ったところ、そもそもエンジンとしてもセッションを無効化すること自 体は非推奨らしく、復帰させる場合には AudioSettings.Reset() を呼び出して復元する必要があ る説明があった 参考: [iOS] Audio files are not played when using CallKit What does UnityInterface.UnitySetAudioSessionActive actually do? ※ Issue にもある通り、ネイティブプラグインから UnitySetAudioSessionActive と言うメソッドを呼び出す形でも可
AudioSettings.Reset() について •引数に渡した AudioConfiguration の内容でオーディオシステムを再設定する API ・現在の設定で適用するなら `AudioSettings.Reset(AudioSettings.GetConfiguration())` で呼び出し可能 •恐らくは内部的に AVAudioSession の状態をリセットしていると思われる ・試しに Category を playback に変更してこちらを呼び出したら ambient に戻ったのを確認 ・内部的にセッションの有効化も同時に行っているかと思われる ・下記の Issue でも言及されている通り、呼び出すとオーディオの状態がリセットされるので、 シーン中の AudioSource などの再生は停止する →参考: [iOS] Audio files are not played when using CallKit https://docs.unity3d.com/ScriptReference/AudioSettings.Reset.html
設定を変更するには?
一部の設定は Project Settings より変更可能 •Mute Other Audio Source ・デフォルトは OFF ・ON だと soloAmbient、OFF だと ambient が設定される ・その他詳細はドキュメント参照 Scripting API: PlayerSettings.muteOtherAudioSources ・Prepare iOS for Recording ・ON の場合には最初から Microphone.Start を呼び出した状態と 同じ設定で開始される ・Category: playAndRecord ・Mode: default ・CategoryOption: allowBluetoothA2DP https://docs.unity3d.com//Manual/class-PlayerSettingsiOS.html
設定を変更するには? •前述した Project Settings 以外で変更する場合には、基本 的にネイティブプラグインの実装が必要となります •今回の講演では実装方法までについては詳しくは解説し ませんが、検証用のサンプルプロジェクトを用意したの で、呼び出し方法などはこちらをご覧ください → https://github.com/mao-test-h/Unity-AVAudioSession-Test
バックグラウンド再生を行うには? •Project Settings より「Enable Custom Background Behaviours」を有効にし、プラグインの呼び出しで Category を Playback に変更すれば対応可能 ・この中の「Audio, AirPlay, PiP」を有効にする必要があります •ただし、あくまで再生されるだけ もしサウンドテスト機能などを実装する際に、音楽アプリにあるよ うなコントローラーを表示したい要件がある場合には、別途実装 が必要となってくるかと思われるので注意 https://docs.unity3d.com//Manual/class-PlayerSettingsiOS.html
制御する上での注意点
プラグインでの設定変更は注意が必要 •前述した通り、 AVAudioSession の変更などは基本的にエンジン側でも行われます ・そのため、変更内容やタイミングによっては意図しない挙動になる可能性があります → 例えば録音中に Category を Record or playAndRecord 以外に切り替えるとマイクが止まるなど •プラグインで設定を変える際には注意 ・良くも悪くも全体に影響があることを理解すること ・設定を変更するプラグインを配布する際には、設定変更する旨をドキュメントに記載する、もしくはオプ ション化するなどを検討すると安全かもしれません
プラグインでの設定変更は注意が必要 •特にサードパーティプラグインを導入する際には、意図しない感じに設定が書き換えられた りしてないか注意してみると良いかも ・「サウンドが止まった」「マイクが止まった」みたいな現象が起きた際には、原因調査の一環として AVAudioSession の各状態を見てみるのも有りかもです •AudioSettings.Reset を呼び出すと初期状態にリセットすることが可能 ・もし導入したプラグインが原因でセッションが無効化されてしまうケースが起きているなら、ワークアラ ウンドとして呼び出してみるのも手かもしれません 参考: AudioSettings.Reset - Scripting API
ハプティックフィードバックにつ いて
お話に入る前に... •この章でお話しする具体的な内容については、以下の記事として投稿してます 【Unity】iPhone アプリでの Haptic Feedback 入門 - Qiita 【Unity】iPhone アプリでの Haptic Feedback 入門 - Core Haptics 編 - Qiita •今回お話しする内容としては、記事中の内容からイメージしやすいところをピックアップしつ つ、ざっくりとご紹介できればと思います
ハプティクスフィードバックとは? •iPhone には、画面の様々なアクションに応じて振動を発生させる フィードバック ) と言う仕組みが備わっています Haptic Feedback (触覚 → OS 標準だと、例えば以下のような場面で再生されます。 フラッシュライトの ON/OFF カレンダーアプリなどにある時間選 択のスクロール FaceID による認証処理の結果表示
ハプティクスフィードバックとは? •こちらをアプリで導入することにより、「 視覚や音だけでは伝わらない物理的な感覚 」をユー ザーに届けることが可能になるかと思います ・UI を操作した際のフィードバック ・ゲームの状況に応じた振動 (アクションゲームの場合には攻撃時の衝撃感など) フラッシュライトの ON/OFF カレンダーアプリなどにある時間選 択のスクロール FaceID による認証処理の結果表示
ゲームだとどこで使えそうか •いろんな作品をリサーチした訳では無いですが、所感だと以下のようなところで活用されて いる例を見受けました ・UI の操作時 (何かを動かしたり、ボタンを押下したタイミングなど) ・パズル系ゲームだとブロックを操作したタイミングや消滅するタイミングなど ・その他、物理的なフィードバックに対する補完 •具体的にどういった機能があるのか?どう言ったところで使えそうか?と言う点について簡 単に解説していきます ※デモアプリを用意してます。懇親会にてお気軽にお声がけください。
ベストプラクティスについて •Apple の Human Interface Guideline (HIG) には、実装する 上でのガイドラインとしてのベストプラクティスが公開され てます 触覚フィードバックの提供 | Apple Developer Documentation ・一貫性を持たせる ・視覚・聴覚といった他のフィードバックを補完する ・多用しすぎない ・オフにできるようにする ・etc •実装する上での心構えとして、利用する前に一読してみ ると良いかもしれません
再生するには? 振動(ハプティックパターン )を再生するには以下の API を持ちいることで再生可能です。 •UIFeedbackGenerator ・システムが提供するプリセットのパターンを再生する API ・名前の通り、主に UI 向けではあるが、ゲームでも使い所はあるはず ・API がシンプルであり、導入難易度は低い •Core Haptics ・任意のパターンを再生する API ・例えば連続的な再生 (バイブレーションみたいな機能) もこちらなら再生可能 ・自由度が高い分、使うには色々と覚える必要有り
再生するには? 今回はこちらについて具体的に解説していきます (以降、UIFeedbakGenerator は「UIFG」と省略します ) 振動(ハプティックパターン )を再生するには以下の API を持ちいることで再生可能です。 •UIFeedbackGenerator ・システムが提供するプリセットのパターンを再生する API ・名前の通り、主に UI 向けではあるが、ゲームでも使い所はあるはず ・API がシンプルであり、導入難易度は低い •Core Haptics ・任意のパターンを再生する API ・例えば連続的な再生 (バイブレーションみたいな機能) もこちらなら再生可能 ・自由度が高い分、使うには色々と覚える必要有り
呼び出すためのプラグイン •API を呼び出すためにはネイティブプラグインを実装する 必要がありますが、 こちらを呼び出すためのプラグインが Apple 公式から公開されています GitHub - apple/unityplugins → UIFG もこの中の「Apple.CoreHaptics」に含まれています •あとは UIFG については API がそこまで複雑ではないの で、基盤などを作っている場合には自分で実装して呼び 出してしまうのも手かもです
UIFeedbackGenerator (UIFG) について
UIFG について •システムが提供するプリセットのパターンを再生する API ※言い換えると決まったパターンしか再生できないので、独自のパターンを再生するなら Core Haptics を 使う必要あり •再生可能なパターンとしては以下のようなものがあります ・UINotificationFeedbackGenerator ・アクションやイベントに対する結果(成否)を示すためのパターン ・UISelectionFeedbackGenerator ・UI の選択状態の変更などを示すためのパターン ・UIImpactFeedbackGenerator ・視覚情報を補完するためのパターン ・物理的な衝撃などをシミュレートするためのパターンとも言えるかも...
UINotificationFeedbackGenerator
UINotificationFeedbackGenerator •こちらはアクションやイベントに対する「成功 / 警告 / 失 敗」を示すためのパターンを再生する API です •上述の通り、以下 3つのパターンを再生することが可能で す success タスクが成功したことを示すパターン warning タスクが警告を出したことを示すパターン error タスクが失敗したことを示すパターン
UINotificationFeedbackGenerator •主な用途としては名前にある通り、一連のタスクやアク ションを行った際の成否を伝えるなどが挙げられるかと思 います → 例えば左の GIF のように、アプリ内通知に応じて対応するパ ターンを再生するなど
UISelectionFeedbackGenerator
UISelectionFeedbackGenerator •こちらは UI の選択状態や値の変更などを示すためのパ ターンを再生する API です •こちらは以下 1つのパターンを再生することが可能です selectionChanged UI要素の値が変化したことを示すパターン
UISelectionFeedbackGenerator •主な用途としてはドラムロール UI などで選択項目を変更 した時のフィードバックなどが挙げられるかと思います
UIImpactFeedbackGenerator
UIImpactFeedbackGenerator •こちらは主に視覚情報を補完するためのパターンを再生 する API です ドキュメントの言葉を借りると「物理的な衝撃などをシミュレートす るためのパターン」とも言えるかも。 (次ページへ)
UIImpactFeedbackGenerator •以下 5つのパターンを再生することが可能です light 軽い衝撃 medium 中程度の衝撃 heavy 大きい(重い)衝撃 rigid 剛性のある物体と衝突した際の衝撃 heavy 柔らかい物体と衝突した際の衝撃 •ちなみに iOS 13 以降であれば、 intensity (振動の強さ ) も 調整可能です
UIImpactFeedbackGenerator どこで使えるのか? → 個人的には以下のところで使えるかなと思ってます •ゲーム中でボタンなどを押した時のフィードバック •D&D で操作するタイプの UI カチッとはめた時のフィードバックなど •パズルゲームなどでピースを選択したり、消した時などの フィードバック ・正確に言えば UI 操作では無いが...衝撃感と言う面では有りか もしれない? ・場合によっては Core Haptics を使った方が適切かも
ありがとうございました