Reputation: 304
I need to play a custom sound on receiving a push notification in my ios app.
I know, apple don't support the sound alert in silent mode. I have tried sending push notification with custom sound. Its playing when the device is not silent, and vibrates in silent mode.
But, recently I found an app - Chipolo where a custom sound is displayed in silent mode, even when the app is in killed state.
What technology used in playing a sound alert?
Any help is really appreciated!
Upvotes: 2
Views: 1996
Reputation: 441
As for playing a sound when the device is on silent mode you simply can't do it right away. Only Apple can override the silent switch for an emergency situation like finding the device. You would need a special permission from Apple for your app to do it too.
Ganesh's answer is the best thing you can do without it.
Upvotes: 0
Reputation: 2139
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 :)
Upvotes: 2