iOS:从通知扩展中播放远程音频文件

时间:2018-01-22 10:46:03

标签: ios swift avplayer

我正在尝试播放来自通知扩展程序的远程音频文件

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()
}

但没有任何反应。

在应用程序的功能中,我启用了以下后台模式:“音频,AirPlay和PiP”,“后台提取”,“远程通知”

我需要在通知到达时播放声音而无需用户互动。 此外,媒体附件不是一种选择,因为iOS 10支持是强制性的。

UPD:我试过这个

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()
}

也没有发生任何事情

3 个答案:

答案 0 :(得分:1)

现在可以在iOS 13中实现。如果消息被删除,我将在此处复制消息的内容。 https://forums.developer.apple.com/thread/118404Correct

KevinE于2019年7月30日5:11 PM回答

您的应用应如何运作的细节差异很大 取决于您的特定用例和应用设计,但我们的一般 建议您使用即按即说应用程序 标准的推送通知,而不是用于消息传递的PushKit。 更具体地说,在接收方,您的通知服务 扩展程序应下载相关音频并将该音频附加到 您的特定邮件。

为了支持该方法,从iOS 13开始,系统会寻找 应用程序组容器中可能存在的声音文件以及 预先存在的搜索位置。该文档尚未更新 为此(),但是有头文件文档描述了 “ UNNotificationSound.h”中“ soundNamed:”的注释中的详细信息:

//要为通知播放的声音文件。声音一定是 在应用程序数据容器的“库/声音”文件夹中或 应用程序组数据容器的“库/声音”文件夹。如果文件是 在容器中找不到,系统将在应用程序的捆绑包中查找。

详细说明一下,我们在下面查找声音文件 订单和位置:

您的应用程序将容器直接放置在“库/声音”中。您的应用组 目录名为“ Library / Sounds”的目录中。 这里要记住的主要事情:

目录2是“库/声音”,而不仅仅是“声音”。你需要 创建一个“ Library”目录,其中包含“ Sounds”目录,而不是 只是一个“声音”目录。应用程序直接容器仍然是 我们将排名第一,因此您需要注意自己的工作方式 为文件命名。我建议使用组目录 对于所有声音或遵循两种不同的命名约定 位置,使其永不碰撞。您的网络服务扩展 无法查看目录#1的内容,因此无法知道是否或 没有一个特定的名称会发生​​冲突。

答案 1 :(得分:1)

感谢 TALE 的回答,我已经实现了

- (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);
}

如果您需要 Swift 版本,请随时发表评论

答案 2 :(得分:0)

我认为,根据我之前的经验,我们可以在收到通知时播放Bundle声音文件。意味着,我们必须将声音文件放在应用程序包中,声音文件是app的预定义资源。

如果您想播放不同的声音,请在应用程序包中添加所有声音文件,并使用通知有效负载键添加识别/播放。

For,如果你想播放带有相关通知的ABC文件,那么设置适当的逻辑/ Key with Notification Payload并确定它。

请让我知道你的想法。快乐编码:)

其他参考: Play notification sound using URL

如果您想使用网址播放声音。然后你可以下载这个文件,或者你可以在缓冲特定文件后播放:

How to play mp3 audio from URL in ios swift