実現したいこと
お世話になっております。
表題の通りなのですが、特にiOS側で音量0でも強制的にSEを再生させる方法が知りたいです。
発生している問題・分からないこと
調べたところ、iOSではMPVolumeViewを使えばユーザー操作なしでも端末の音量を変更できるとありました。
しかし、実装方法が悪いのか、動作しませんでした。
該当のソースコード
特になし
試したこと・調べたこと
- teratailやGoogle等で検索した
- ソースコードを自分なりに変更した
- 知人に聞いた
- その他
上記の詳細・結果
検索方法が難しく、調べても「PayPayでミュートする方法」といった情報が出てきて、
開発側の資料に到達できませんでした。
一応、検索にヒットした以下の記事を参考に実装してみましたが、音量を変化させることは出来ませんでした。
https://qiita.com/sekibouya/items/990bf2ab9e3e57ed9f81
補足
開発環境:
Tahoe 26.5.1
Xcode26.5
シミュレーター:
iPhone 17 Pro MAX (iOS 26.5)
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
回答3件
0
iOSでこれをやるには、大きく分けて2つのステップが必要です。
- 音声セッションの設定(マナーモードでも音を出すようにする)
- MPVolumeViewを使って一時的に音量を上げて、鳴らし終わったら元に戻す
まず、AVAudioSessionを使います。これで「自分のアプリはマナーモードでも音を出していいよ」とシステムに伝えます。
コードはこんな感じ。
import AVFoundation
func setupAudioSession() {
let audioSession = AVAudioSession.sharedInstance()
do {
try audioSession.setCategory(.playback, mode: .default)
try audioSession.setActive(true)
} catch {
print("音声セッション設定エラー: (error)")
}
}
次に、MPVolumeViewを使ってシステム音量を一時的に変えます。普通の方法ではアプリから直接音量を変えられないので、MPVolumeViewの中に隠れているスライダーを探して操作します。
import MediaPlayer
class SoundManager {
private var savedVolume: Float = 0.5 private var volumeSlider: UISlider? { let volumeView = MPVolumeView(frame: .zero) // 一旦画面に追加しないとスライダーが見つからない UIApplication.shared.windows.first?.addSubview(volumeView) let slider = volumeView.subviews.first(where: { $0 is UISlider }) as? UISlider volumeView.removeFromSuperview() return slider } func prepareToPlay(fixedVolume: Float) { savedVolume = AVAudioSession.sharedInstance().outputVolume volumeSlider?.setValue(fixedVolume, animated: false) } func playSound() { guard let url = Bundle.main.url(forResource: "payment_sound", withExtension: "mp3") else { return } do { let player = try AVAudioPlayer(contentsOf: url) player.prepareToPlay() player.play() } catch { print("再生失敗: \(error)") } } func restoreVolume() { volumeSlider?.setValue(savedVolume, animated: false) }
}
実際に使うときは、こんな感じです。
let soundManager = SoundManager()
// 音量を仮に0.5(半分)に設定して準備
soundManager.prepareToPlay(fixedVolume: 0.5)
// 音を鳴らす
soundManager.playSound()
// 2秒後に元の音量に戻す(実際はAVAudioPlayerのデリゲートでやるのがベター)
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
self.soundManager.restoreVolume()
}
大事な注意点がいくつかあります。
App Storeの審査についてですが、ユーザーが許可していないのに勝手にシステム音量を変えるのは厳しく見られます。だから「決済成功時だけ」「一瞬だけ」など、明確な理由が必要です。できれば設定画面でオンオフを選べるようにするとベター。
ユーザー体験的にも、音量ゼロのときに突然音が鳴るとびっくりするかもしれないので、本当に必要な場面だけに使いましょう。
あと、AudioServicesPlaySystemSoundという方法もあります。これは短い「ピッ」という音に向いていますが、音量をコントロールできないので「音量ゼロでも鳴らす」目的には使えません。
まとめると、
- AVAudioSessionを.playbackに設定する(必須)
- MPVolumeViewで一時的に音量を上げて、鳴らし終わったら戻す
- 審査やユーザー体験を考慮して、機能をオンオフできるようにする
これでPayPayのような「音量ゼロでも決済音が鳴る」アプリが実装できます。
投稿2026/06/15 09:44
総合スコア74
0
PayPayのあの「ペイペイ♪」という音、端末がミュートでも容赦なく鳴り響くので、開発者目線だと「どうやって実装してるんだ!?」って気になりますよね。
Qiitaの記事で試されていた MPVolumeView を使って端末のシステム音量(マスターボリューム)をプログラムから強制的に書き換える手法は、近年のiOS(特にiOS 15以降〜iOS 26系)ではAppleのセキュリティ・アクセシビリティ方針によって完全に塞がれています。 画面上にスライダーを非表示にして裏で音量を上げる、といったハック的な挙動は現在動作しません。
では、PayPayや他の決済アプリがどうやって音を鳴らしているかというと、システム音量をいじるのではなく、「音量設定が0(ミュート)でも音が鳴るオーディオセッションのカテゴリ」を設定した上で、アプリ専用の独立した音量(プレイヤー音量)を最大にして再生するというアプローチをとっています。
具体的な実装方法とロジックを整理しましたので、参考にしてみてください。
音量0でも音を鳴らす仕組み(コアロジック)
iOSのオーディオ管理(AVAudioSession)には、端末の挙動(消音スイッチや音量0)を無視して音を鳴らせるカテゴリが存在します。
- AVAudioSession.Category.playback を指定する
このカテゴリを設定すると、ユーザーが本体横のスイッチで「消音(マナーモード)」にしていても、それを無視して音を鳴らすことができます。 - システム音量ではなく「プレイヤー自体の音量」を最大にする
AVAudioPlayer などのインスタンスには、システム音量とは別に volume プロパティ(0.0 〜 1.0)があります。これを 1.0(最大)に固定して再生します。
[!NOTE]注意点 ユーザーが端末の物理ボタンで「音量ゼロ」にしている場合、playback カテゴリであっても、システム音量が0倍されるため、そのままでは音が聞こえなくなるケースがあります。
これを回避するために、多くの決済アプリでは「通知音(Sound Effects)」用の別のオーディオ出力ルートや、特殊なオーディオセッションのオプション(.mixWithOthers など)を組み合わせ、アプリ内の最大音量で割り込ませる実装を行っています。
実装サンプル(Swift)
Xcode 26環境(Swift 6ベース)を想定した、実装のイメージコードです。決済ボタンが押されたタイミングなどで、セッションをアクティブにして再生します。
swift
1import UIKit 2import AVFoundation 3 4class PaymentViewController: UIViewController { 5 6 var audioPlayer: AVAudioPlayer? 7 8 func playPaymentSound() { 9 // 1. オーディオセッションの設定 10 let audioSession = AVAudioSession.sharedInstance() 11 12 do { 13 // .playback カテゴリを設定(マナーモードを無視) 14 // .mixWithOthers を入れることで、BGM等が流れていても割り込んで鳴らせる 15 try audioSession.setCategory(.playback, mode: .default, options: [.mixWithOthers]) 16 17 // セッションをアクティブにする 18 try audioSession.setActive(true) 19 20 // 2. 音源ファイルの読み込み(あらかじめプロジェクトに SE.mp3 などを追加しておく) 21 guard let soundURL = Bundle.main.url(forResource: "payment_sound", withExtension: "mp3") else { 22 print("音源ファイルが見つかりません") 23 return 24 } 25 26 audioPlayer = try AVAudioPlayer(contentsOf: soundURL) 27 28 // 3. アプリ内プレイヤーの音量を最大(1.0)にする 29 // ※これがシステム音量0に対する「強制力」になります 30 audioPlayer?.volume = 1.0 31 32 // 再生 33 audioPlayer?.play() 34 35 } catch { 36 print("オーディオ再生エラー: \(error.localizedDescription)") 37 } 38 } 39} 40
なぜPayPayは「爆音」で鳴るのか?
実は、PayPay等のアプリは上記の実装に加えて、「独自の音量管理ロジック」を入れていると言われています(公式仕様は非公開ですが、挙動からの推測です)。
ユーザーへの事前警告と設定保持
アプリ内の設定画面に「決済音量」という独自の項目がありませんか?
アプリ起動時や決済直前に、独自の音量設定(例 アプリ内音量50%など)を読み込み、システム音量がどうであれ、その音量比率で AVAudioPlayer.volume を計算して鳴らしています。
物理的な限界
もし端末のマスターボリュームが完全に「ゼロ(消音)」かつ、ハードウェア側で波形がカットされるレベルの場合、上記コードでも完全に無音になることがあります。そのため、一部の決済アプリでは、決済画面が開いている間だけ「システム音量がゼロなら、不自然じゃない程度(1目盛り分など)にシステム音量を自動で上げる」という実装を(規約に触れない合法的なAPIの範囲で)組み合わせている可能性もあります。
まずは上記サンプルのように、AVAudioSession のカテゴリを.playback に変更し、プレイヤー側の volume = 1.0 で再生してみて、シミュレーターや実機で挙動が変わるか試してみてください!
投稿2026/06/16 00:46
総合スコア4
0
さて、送信いただいたメッセージの途中で切れてしまっていますが、
音量をユーザ…
もし「音量をユーザーに事前に知らせる方法」や「音量を元に戻す際の注意点」などについて引き続きお知りでしたら、具体的にお聞かせください。以下のような補足も可能です。
- 音量を一時的に上げる前に、現在の音量を保存しておき、鳴らし終わったら復元する(回答内のコードで実装済み)
- ユーザーが意図せず音が出るのを避けるために、アプリの設定で「決済音を常に鳴らす/端末音量に従う」を切り替えられるようにするのが親切です
- 実機でテストする際、イヤホン未接続・マナーモードでも音が出るかは
AVAudioSession.Category.playbackとoptions: .duckOthersなどの組み合わせで調整可能です
何か他に詰まっている点や、実装に関する疑問があれば遠慮なくお聞かせください。
投稿2026/06/16 00:37
総合スコア74
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。