ローカル通知の音を動的に変更する(iOS10以降)
ローカル通知の着信音をカスタマイズしたいんだけど、っていうニーズはまさにFAQで、stackoverflowなんかにもたくさんあがっています。
Choose custom sound for local notifications
iOS9以前では、UILocalNotification
のsoundName
プロパティにメインバンドルに含まれる.caf
ファイルの名前を指定すればその音を鳴らせるようになっていました。逆に言うと、あらかじめバンドルに入れてビルドした音声ファイルしか通知を受信したときに鳴らすことが出来ませんでした。
iOS10ではUILocalNotification
はdeprecatedとなり、新たにUNNotificationRequest
とUNNotificationContent
を使って通知を送ることが推奨されるようになりました。
概要は下記の記事などを参照下さい。
UNNotificationContent
には、UNNotificationSound
型のsound
というプロパティが追加されています。
このUNNotificationSoundの、init(named:)
コンストラクタのnamed
パラメータの説明に、
The name of the sound file to play. This file must be located in the current executable’s main bundle or in the
Library/Sounds directory of the current app container directory. This parameter must not be nil.
とあり、iOS10からは従来のメインバンドルだけでなく、Library/Soundsの下に置いたファイル名を指定できるようになりました。
レアケースなんですけど、インハウスの業務用向けアプリの開発で、特殊な環境の現場で使うので、どんな通知音が聞き取りやすいかは現場で使ってもらわないと選べないから、通知の音はシステムの効果音のなかから、後で任意に選べるようにして欲しいというオーダーがありました。
システム効果音は、 /System/Library/Audio/UISounds
などの中に納められているので、ローカル通知を送る前にこれらのファイルを選んで、<App>/Library/Sounds
にコピーしておくことで、システム効果音をならすことが出来ました。
通常、アプリケーションのLibrary
の下にSounds
ディレクトリはないので、作成します。
参考:File System Basics:About the iOS File System
// <App>/Library/Soundsが無ければ作成
let libraryUrl = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask)[0]
let soundDirUrl = libraryUrl.appendingPathComponent("Sounds")
try? FileManager.default.createDirectory(at: soundDirUrl, withIntermediateDirectories: true, attributes: nil)
Library/Sounds
の下に効果音ファイルを置きます。
// あらかじめリストアップしておいたファイルから選んで${App}/Library/Soundsにコピー
do {
let from = URL(fileURLWithPath:"/System/Library/Audio/UISounds/Modern").appendingPathComponent("calendar_alert_chord.caf")
let dest = soundDirUrl.appendingPathComponent(file)
try FileManager.default.copyItem(at: from, to: dest)
}catch{
log.error(error)
return false
}
return true
UNNotificationSoundに先ほどコピーした"calendar_alert_chord.caf"を指定して、ローカル通知を送ります。
let content = UNMutableNotificationContent()
content.title = ".."
content.subtitle = "..."
content.body = ".."
content.userInfo = [...]
content.sound = UNNotificationSound(named:"calendar_alert_chord.caf")
let request = UNNotificationRequest.init(identifier: UUID().uuidString, content: content, trigger: nil)
let center = UNUserNotificationCenter.current()
center.add(request)
以上です。
Discussion