3

I'm trying to play remote audio file from notification extension

override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
    //...
    let url = URL(string: "https://firebasestorage.googleapis.com/v0/b/XXX.appspot.com/o/XXXXXXX?alt=media&token=XXXXXXX")
    let item = AVPlayerItem(url: url!)
    NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: item)
    let player = AVPlayer(playerItem: item)
    player.play()
}

But nothing happens.

In capabilities of app I've enabled following background modes: "Audio, AirPlay, and PiP", "Background fetch", "Remote notifications"

I need to play sound when notification arrives without user interaction. Also, media attachment is not an option, because iOS 10 support is mandatory.

UPD: I've tried this

func download(url: URL) {
    URLSession.shared.downloadTask(with: url, completionHandler: { _, _, error in
        if let error = error {
            print(error)
        }
        self.play(url: url)
    }).resume()
}

func play(url: URL) {
    let player = try! AVAudioPlayer(contentsOf: url)
    player.prepareToPlay()
    player.volume = 1.0
    player.play()
}

Nothing happened too

Dmytro Rostopira
  • 10,588
  • 4
  • 64
  • 86

3 Answers3

3

Thanks to TALE answer, I've implemented it

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
    self.receivedRequest = request;
    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];
    
    if (request.content.userInfo != nil && request.content.userInfo[@"audioUrl"] != nil) {
        NSURL* audioUrl = [NSURL URLWithString:request.content.userInfo[@"audioUrl"]];
        NSString* audioName = audioUrl.lastPathComponent;
        [[[NSURLSession sharedSession] downloadTaskWithURL:audioUrl completionHandler: ^void (NSURL* location, NSURLResponse* response, NSError* error) {
            if (location == nil) {
                contentHandler(self.bestAttemptContent);
                NSLog(@"%@", error);
                return;
            }
            NSFileManager* fileMan = [NSFileManager defaultManager];
            NSString* containerPath = [fileMan containerURLForSecurityApplicationGroupIdentifier:@"group.com.example"].path; // Put your app group id here
            NSString* soundDir = [containerPath stringByAppendingString:@"/Library/Sounds"];
            NSError* errorOut;
            if (![fileMan fileExistsAtPath:soundDir]) {
                [fileMan createDirectoryAtPath:soundDir withIntermediateDirectories:YES attributes:nil error:&errorOut];
            } else {
                // Delete old files
                NSArray<NSString*>* oldFiles = [fileMan contentsOfDirectoryAtPath:soundDir error:&errorOut];
                if (oldFiles != nil) {
                    for (NSString* oldFileName in oldFiles) {
                        NSString* oldFilePath = [soundDir stringByAppendingString:oldFileName];
                        [fileMan removeItemAtPath:oldFilePath error:&errorOut];
                    }
                }
            }
            NSString* soundPath = [soundDir stringByAppendingString:[@"/" stringByAppendingString:audioName]];
            NSURL* soundUrl = [NSURL fileURLWithPath:soundPath];
            [fileMan copyItemAtURL:location toURL:soundUrl error:&errorOut];
            UNNotificationSound* sound = [UNNotificationSound soundNamed:audioName];
            self.bestAttemptContent.sound = sound;
            contentHandler(self.bestAttemptContent);
        }] resume];
        return;
    }
    
    // Your logic for non-audio notification
    
    self.contentHandler(self.bestAttemptContent);
}

Feel free to leave comment if you need a Swift version

Dmytro Rostopira
  • 10,588
  • 4
  • 64
  • 86
2

This is now possible with iOS 13. I'll copy the content of the message here in case it gets removed. https://forums.developer.apple.com/thread/118404Correct

Answer by KevinE on Jul 30, 2019 5:11 PM

The specifics of how your app should work are going to vary a lot depending on your specific use cases and app design, but our general recommendation for push to talk apps is that you shift to using standard push notifications instead of PushKit for message delivery. More specifically, on the receiver side your Notification Service Extension should download the relevant audio and attach that sound to your particular message.

To support that approach, starting in iOS 13, the system looks for possible sound files in the apps group container(s) as well as the preexisting search locations. The documentation hasn't been updated for this yet (), but there is header file documentation describing the details in the comments for "soundNamed:" in "UNNotificationSound.h":

// The sound file to be played for the notification. The sound must be in the Library/Sounds folder of the app's data container or the Library/Sounds folder of an app group data container. If the file is not found in a container, the system will look in the app's bundle.

Breaking that down in detail, we look for sound files in the following order and locations:

Your apps direct container in "Library/Sounds". Your apps group(s) directory in a directory named "Library/Sounds" Your apps bundle The main things to keep in mind here:

Directory #2 is "Library/Sounds", not just "Sounds". You'll need to create a "Library" directory with a "Sounds" directory inside it, not just a "Sounds" directory. The apps direct container is still the first place we'll look, so you'll need to be careful about how you name your files. I would recommend either using the group directory for all sounds or following a naming convention for the two different locations so that they never collide. Your Network Service Extension can't see the contents of directory #1, so it can't know whether or not a particular name will collide.

TALE
  • 960
  • 13
  • 22
0

I think, As per my earlier experience, We are able to Play Bundle sound file when a notification arrives. Means that, we must put sound file in application bundle and a Sound file is a predefined resource of app.

If you want to play different sound then add all sound files in application bundle and Identify/Play using notification payload key.

For, Ex if you want to Play ABC file with relevant notification then set appropriate logic/Key with Notification Payload and idetify it.

Please let me know your thoughts. Happy Coding :)

Other Reference: Play notification sound using URL

If you want to Play sound using URL. Then you can download this file or you can play after buffering particular file:

How to play mp3 audio from URL in ios swift

Renish Dadhaniya
  • 10,642
  • 2
  • 31
  • 56
  • Please, read the question title. It clearly says "remote audio file". Now it's hardcoded for testing, but later it's will be audio messages, so I can't put them in bundle – Dmytro Rostopira Jan 22 '18 at 11:13
  • Yes, I have read it carefully. I have told you that, It is not possible to Play audio file using url directly with notification. There are two solution 1. You need to download the File then you will able to Play. Please review this URl: https://stackoverflow.com/questions/34563329/how-to-play-mp3-audio-from-url-in-ios-swift . 2.Using Predifine file with app bundle. – Renish Dadhaniya Jan 22 '18 at 11:18
  • @DimaRostopira hi Dear. I need your help. – Ekta Padaliya Apr 21 '18 at 08:51
  • @EktaPadaliya what's up? – Dmytro Rostopira Apr 21 '18 at 09:03
  • @DimaRostopira I want to stream audio when push receive. So how can I do that ? – Ekta Padaliya Apr 21 '18 at 10:07
  • @EktaPadaliya it's not possible, as far as I know – Dmytro Rostopira Apr 21 '18 at 10:12
  • @DimaRostopira I did using notification extension. When notification is receive my audio is playing. But problem is that when phone is lock that time notification extension not working thats why my audio is not playing. – Ekta Padaliya Apr 21 '18 at 10:13
  • @DimaRostopira Hi, Do you know if it's possible now, for example with using ios notification attachment? In Zello app is does work somehow... Thank you! – fnklstn Dec 17 '21 at 16:56
  • @fnklstn yes it's possible, I've even provided code for that, check my answer – Dmytro Rostopira Dec 20 '21 at 13:12
  • @DimaRostopira Thank you! Upvoted. И с Новым годом! – fnklstn Dec 20 '21 at 16:31