iosswiftaudio-playerituneslibrary

Is it possible to save a music from the Ipod library into my app with swift?


I have the reference of an MPMediaItem when a user selects an audio from the iPod library. I am getting the asset URL of that item by using

 let url = item.valueForProperty(MPMediaItemPropertyAssetURL)

But this is not giving me the exact physical location of the file, instead, it is giving me an URL w.r.t iPod library.

ipod-library://item/item.mp3?id=1840064795502796074

Is there a way to get the physical URL of a song from an iPod library?

EDIT - actually I want to extract NSData from the physical file and send it to my backend server, so I need the physical file URL and not the relative URL

MPmediaPickerController is working, I select the song and its playing but I don't want to play the song.I have tried to upload the audio files to a server. And I have using MPMedia Picker view in list audio, when I am going select the audio I will upload to server(HTTP), How can I do this??? How to accessing the media library with Swift code?


Solution

  • Adapting Krishna's answer, which uses AVAssetExportSession to save the MPMediaItem to a file, you can do something like the following in Swift 3:

    /// Export MPMediaItem to temporary file.
    ///
    /// - Parameters:
    ///   - assetURL: The `assetURL` of the `MPMediaItem`.
    ///   - completionHandler: Closure to be called when the export is done. The parameters are a boolean `success`, the `URL` of the temporary file, and an optional `Error` if there was any problem. The parameters of the closure are:
    ///
    ///   - fileURL: The `URL` of the temporary file created for the exported results.
    ///   - error: The `Error`, if any, of the asynchronous export process.
    
    func export(_ assetURL: URL, completionHandler: @escaping (_ fileURL: URL?, _ error: Error?) -> ()) {
        let asset = AVURLAsset(url: assetURL)
        guard let exporter = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetAppleM4A) else {
            completionHandler(nil, ExportError.unableToCreateExporter)
            return
        }
    
        let fileURL = URL(fileURLWithPath: NSTemporaryDirectory())
            .appendingPathComponent(NSUUID().uuidString)
            .appendingPathExtension("m4a")
    
        exporter.outputURL = fileURL
        exporter.outputFileType = "com.apple.m4a-audio"
    
        exporter.exportAsynchronously {
            if exporter.status == .completed {
                completionHandler(fileURL, nil)
            } else {
                completionHandler(nil, exporter.error)
            }
        }
    }
    
    func exampleUsage(with mediaItem: MPMediaItem) {
        if let assetURL = mediaItem.assetURL {
            export(assetURL) { fileURL, error in
                guard let fileURL = fileURL, error == nil else {
                    print("export failed: \(error)")
                    return
                }
    
                // use fileURL of temporary file here
                print("\(fileURL)")
            }
        }
    }
    
    enum ExportError: Error {
        case unableToCreateExporter
    }
    

    Or, in Swift 2:

    /// Export MPMediaItem to temporary file.
    ///
    /// - Parameters:
    ///   - assetURL: The `assetURL` of the `MPMediaItem`.
    ///   - completionHandler: Closure to be called when the export is done. The parameters are a boolean `success`, the `URL` of the temporary file, and an optional `Error` if there was any problem. The parameters of the closure are:
    ///
    ///   - fileURL: The `URL` of the temporary file created for the exported results.
    ///   - error: The `Error`, if any, of the asynchronous export process.
    
    func export(assetURL: NSURL, completionHandler: (NSURL?, ErrorType?) -> ()) {
        let asset = AVURLAsset(URL: assetURL)
        guard let exporter = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetAppleM4A) else {
            completionHandler(nil, ExportError.unableToCreateExporter)
            return
        }
    
        let fileURL = NSURL(fileURLWithPath: NSTemporaryDirectory())
            .URLByAppendingPathComponent(NSUUID().UUIDString)!
            .URLByAppendingPathExtension("m4a")
    
        exporter.outputURL = fileURL
        exporter.outputFileType = "com.apple.m4a-audio"
    
        exporter.exportAsynchronouslyWithCompletionHandler {
            if exporter.status == .Completed {
                completionHandler(fileURL, nil)
            } else {
                completionHandler(nil, exporter.error)
            }
        }
    }
    
    func exampleUsage(with mediaItem: MPMediaItem) {
        if let assetURL = mediaItem.assetURL {
            export(assetURL) { fileURL, error in
                guard let fileURL = fileURL where error == nil else {
                    print("export failed: \(error)")
                    return
                }
    
                // use fileURL of temporary file here
                print("\(fileURL)")
            }
        }
    }
    
    enum ExportError: ErrorType {
        case unableToCreateExporter
    }
    

    As you can see, I put it in a temporary folder rather than the Documents folder. Also, I use UUID rather than the number of seconds since some reference date to generate the temporary file. But the idea is basically the same.