Swift AVAudioPlayer (Xcode) - воспроизведение аудиофайлов вне пакета приложений

В моем проекте Xcode настроен следующий код (упрощенный код):

import Cocoa
import AVKit

class ViewController: NSViewController {

    var audioPlayer = AVAudioPlayer()

    override func viewDidLoad() {
        super.viewDidLoad()

        do {
            guard let filePath = Bundle.main.path(forResource: "sample", ofType: "mp3") else {
                print("ERROR: Failed to retrieve music file Path")
                return
            }
            let fileURL = URL.init(fileURLWithPath: filePath)
            print(" PATH: \(filePath)")
            print("  URL: \(fileURL)")
            try audioPlayer = AVAudioPlayer.init(contentsOf: fileURL)
        } catch {
            print("ERROR: Failed to retrieve music file URL")
        }

        audioPlayer.play() 
    }
}

//CONSOLE PRINTS ----------:
// PATH: /Users/vakho/Library/Developer/Xcode/DerivedData/MusicPlayer-foqzsckozmcjnofvlvhuwabfssqi/Build/Products/Debug/MusicPlayer.app/Contents/Resources/sample.mp3
//  URL: file:///Users/vakho/Library/Developer/Xcode/DerivedData/MusicPlayer-foqzsckozmcjnofvlvhuwabfssqi/Build/Products/Debug/MusicPlayer.app/Contents/Resources/sample.mp3

Я успешно могу передать filePath файла sample.mp3 (содержащегося в пакете приложения) в audioPlayer, сначала преобразовав его в URL. Вызов функции play () воспроизводит аудиофайл.

Однако, поскольку я создаю приложение для музыкального проигрывателя, я хотел бы иметь возможность воспроизводить аудиофайл, который находится в папках каталогов, таких как рабочий стол, папка загрузок и т. Д. ... Но когда я пытаюсь передать filePath аудио файл вне пакета приложений, код ломается:

import Cocoa
import AVKit

class ViewController: NSViewController {

    var audioPlayer = AVAudioPlayer()

    override func viewDidLoad() {
        super.viewDidLoad()

        do {
            let filePathOptional: String? = "/Users/vakho/Downloads/sample.mp3"
            guard let filePath = filePathOptional else {
                print("ERROR: Failed to retrieve music file Path")
                return
            }
            let fileURL = URL.init(fileURLWithPath: filePath)
            print(" PATH: \(filePath)")
            print("  URL: \(fileURL)")
            try audioPlayer = AVAudioPlayer.init(contentsOf: fileURL)
        } catch {
            print("ERROR: Failed to retrieve music file URL")
        }

        audioPlayer.play()
    }
}

//CONSOLE PRINTS ----------:
// PATH: /Users/vakho/Downloads/sample.mp3
//  URL: file:///Users/vakho/Downloads/sample.mp3
//ERROR: Failed to retrieve music file URL

//ERRORS ----------:
//  (lldb)
//  Thread 1: EXC_BAD_ACCESS (code=1, address=0x38)

Из того, что я мог бы сделать вывод, библиотека AVAudioPlayer и AVKit предназначена для доступа к активам приложений и объединению файлов мультимедиа, а также к потоковой передаче мультимедиа из Интернета. Но он не может воспроизводить медиа из каталога.

Я нашел несколько тем по этой проблеме, все неполные или оставшиеся без ответа, например: https://forums.developer.apple.com/thread/18272

Итак, если AVKit не может делать то, что, как я думал, он должен иметь, какую библиотеку или подход я могу использовать для доступа к файлам каталогов? Приложения музыкального проигрывателя для OSX, конечно, могут предлагать пользователю сканировать каталог и получать доступ к музыкальным файлам. Как они это делают?


person Vakho    schedule 11.06.2019    source источник


Ответы (1)


Кажется, проблема здесь:

guard let filePath = filePathOptional else {
    print("ERROR: Failed to retrieve music file Path")
    return
}

Пожалуйста, измените печать на:

print("ERROR: Failed to retrieve music file Path \(error.localizedDescription)")

Думаю, вы поймете, что проблема в том, что у вас нет доступа к этому файлу. По умолчанию у вас есть доступ только к песочнице вашего приложения и папке рабочего стола.

Также попробуйте поместить свой файл на рабочий стол и воспроизвести его.

person NikR    schedule 11.06.2019
comment
Я попытался разместить файл на рабочем столе, но случилось то же самое. Затем я попробовал отформатировать filePath как fileURL самостоятельно в соответствии с тем, как он был отформатирован в случае пакета приложений, и передал его инициализатору. Похоже, что audioPlayer не может быть инициализирован с URL-адресом вне пакета, как я предполагал. Если это действительно проблема с разрешением доступа, я попытаюсь запросить доступ. - person Vakho; 11.06.2019
comment
Вы поправляем, я уловил сообщение об ошибке и распечатал его в консоли. Он сказал permErr: ошибка разрешений (при открытии файла). Затем я прочел документацию Apple, и оказалось, что Sanboxing включен из соображений конфиденциальности. Отключение Sanboxing - это вариант, но это означает, что вы больше не можете отправлять приложение в магазин приложений. Правильным решением был импорт файла / директории через NSOpenPanel. Спасибо! - person Vakho; 11.06.2019