We can't change the system sound when receiving push notification but we can play audio by using MediaPlayer
and AVFoundation
. We need to use Notification Service extension to process foreground and background notification
In NotificationService Extension
import UserNotifications
import AVFoundation
import MediaPlayer
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
// Properties
var error:NSError?
var audioPlayer = AVAudioPlayer()
let tempInfo = request.content.userInfo as! [String:NSObject]
var songName = ""
if tempInfo.index(forKey: "SoundFileName") != nil {
songName = (tempInfo["SoundFileName"] as! String)
}
var opecode = ""
if tempInfo.index(forKey: "Opcode") != nil {
opecode = (tempInfo["Opcode"] as! String)
}
if opecode == "RingDevice" {
var songTitle = ""
var songExtension = ""
if songName == "" {
songTitle = "Input"
songExtension = "caf"
} else {
let testStr = songName.components(separatedBy: ".")
songTitle = "\(testStr[0])"
songExtension = "\(testStr[1])"
}
if let url = Bundle.main.url(forResource: "\(songTitle)", withExtension: "\(songExtension)") {
let volumeView = MPVolumeView()
if let view = volumeView.subviews.first as? UISlider{
view.value = 1.0 //---0 t0 1.0---
}
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
try AVAudioSession.sharedInstance().setActive(true)
audioPlayer = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.caf.rawValue)
audioPlayer.volume = 1.0
DispatchQueue.main.asyncAfter(deadline: .now() + 5) { // Give 5 sec delay to play audio or else audio will not hearable
audioPlayer.play()
}
} catch _ as NSError {
print("[SoundPlayer] There was an error: \(String(describing: error))")
}
if (audioPlayer.isPlaying) {
audioPlayer.stop()
}
audioPlayer.play()
}
}
if let bestAttemptContent = bestAttemptContent {
// Modify the notification content here...
bestAttemptContent.title = "\(bestAttemptContent.title)"
contentHandler(bestAttemptContent)
}
}
override func serviceExtensionTimeWillExpire() {
// Called just before the extension will be terminated by the system.
// Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
}
In my case i need to check two parameters in pushnotification SoundFileName
and Opcode
. if Opcode
is RingDevice
means i'm playing sound which is mentioned in PushNotification
Don't forget to enable background mode

Hope this will help you :)