【问题标题】:Swift - Download a video from distant URL and save it in an photo albumSwift - 从远程 URL 下载视频并将其保存在相册中
【发布时间】:2016-05-30 12:38:33
【问题描述】:

我目前正在我的应用中显示一个视频,我希望用户能够将其保存到其设备图库/相册照片/相机胶卷中。 这就是我正在做的,但视频没有保存在相册中:/

    func downloadVideo(videoImageUrl:String)
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
        //All stuff here

        print("downloadVideo");
        let url=NSURL(string: videoImageUrl);
        let urlData=NSData(contentsOfURL: url!);

        if((urlData) != nil)
        {
            let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0];

            let fileName = videoImageUrl; //.stringByDeletingPathExtension

            let filePath="\(documentsPath)/\(fileName)";

            //saving is done on main thread

            dispatch_async(dispatch_get_main_queue(), { () -> Void in

                urlData?.writeToFile(filePath, atomically: true);
                print("videoSaved");
            })

        }
    })

}

我也在研究这个:

let url:NSURL = NSURL(string: fileURL)!;

    PHPhotoLibrary.sharedPhotoLibrary().performChanges({
        let assetChangeRequest = PHAssetChangeRequest.creationRequestForAssetFromVideoAtFileURL(url);
        let assetPlaceHolder = assetChangeRequest!.placeholderForCreatedAsset;
        let albumChangeRequest = PHAssetCollectionChangeRequest(forAssetCollection: self.assetCollection)
        albumChangeRequest!.addAssets([assetPlaceHolder!])
        }, completionHandler: saveVideoCallBack)

但我有错误“无法从文件(空)创建数据”。我的“assetChangeRequest”为零。我不明白,因为我的网址是有效的,当我用浏览器访问它时,它会下载一个快速时间文件。

如果有人可以帮助我,将不胜感激!我正在使用 Swift 并针对 iOS 8.0 分钟。

【问题讨论】:

  • 如果要将文件保存到相机胶卷,请查看 PHPhotoLibrary 类和方法 creationRequestForAssetFromVideoAtFileURLPHAssetChangeRequest
  • 在此处的文档中:developer.apple.com/library/prerelease/ios/documentation/Photos/…,我不明白 fileURL 是什么。
  • fileURL 是指向视频文件的链接。您是否尝试将您的filePath 用作fileURL?它可能看起来像这样PHAssetChangeRequest.creationRequestForAssetFromVideoAtFileURL(NSURL(fileURLWithPath: filePath))
  • 顺便说一下,您不需要手动保存文件。使用 NSURLSession downloadTaskWithURL 下载视频文件。有一个完成处理程序返回location:NSURL,这是存储服务器响应的临时文件的位置。在creationRequestForAssetFromVideoAtFileURL中使用这个location:NSURL
  • 我的 url 在字符串中,然后我让 url = NSURL(string: fileURL);我在第二次代码和平中使用了这个 url,但是在执行时 Xcode 在这个 ligne 上停止:albumChangeRequest!.addAssets([assetPlaceHolder!])

标签: ios iphone swift ipad


【解决方案1】:

更新

想使用 URLSession 更新 Swift 3 的答案,并发现答案已经存在于相关主题 here 中。使用它。

原答案

以下代码将视频文件保存到相机胶卷。我重用了您的代码并稍作更改-我删除了let fileName = videoImageUrl;,因为它导致文件路径不正确。

我测试了这段代码,并将资产保存到相机胶卷中。您询问了在creationRequestForAssetFromVideoAtFileURL 中放置什么 - 将下载的视频文件的链接放在下面的示例中。

let videoImageUrl = "http://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_1mb.mp4"

DispatchQueue.global(qos: .background).async {
    if let url = URL(string: urlString),
        let urlData = NSData(contentsOf: url) {
        let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0];
        let filePath="\(documentsPath)/tempFile.mp4"
        DispatchQueue.main.async {
            urlData.write(toFile: filePath, atomically: true)
            PHPhotoLibrary.shared().performChanges({
                PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: URL(fileURLWithPath: filePath))
            }) { completed, error in
                if completed {
                    print("Video is saved!")
                }
            }
        }
    }
}

【讨论】:

  • 非常感谢!你是生命的救星:)
  • @Nimble 你知道我们可以将视频直接存储到照片库而不先将其存储到文件夹吗?
  • 您将文件保存在文档目录中,但之后不会被删除(至少在这些代码中)。您还应该考虑清理。如果要自动清理,为什么不保存在临时目录中呢?或者,如果您需要手动操作,请在完成块中进行清理。
【解决方案2】:

来自@Nimble 的 Swift 3 版本代码:

DispatchQueue.global(qos: .background).async {
    if let url = URL(string: urlString),
        let urlData = NSData(contentsOf: url)
    {
        let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0];
        let filePath="\(documentsPath)/tempFile.mp4"
        DispatchQueue.main.async {
            urlData.write(toFile: filePath, atomically: true)
            PHPhotoLibrary.shared().performChanges({
                PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: URL(fileURLWithPath: filePath))
            }) { completed, error in
                if completed {
                    print("Video is saved!")
                }
            }
        }
    }
}

【讨论】:

  • 您有什么想法可以直接将视频存储到照片库而不先将其存储到文件夹中吗?
  • 我不知道。您应该将照片库视为数据库,因此下载到“数据库”是没有意义的。
  • 好的。但是您知道我们可以为特定应用程序存储多少数据 (GB)。就像 WhatsApp 将所有图像和视频存储到照片库一样。同时将它们保存到文件夹中吗?因为我正在开发类似的应用程序,从服务器下载图像和视频并将其保存到文件夹。
  • 我认为没有限制。看看 Apple 的指导方针developer.apple.com/icloud/documentation/data-storage/…
【解决方案3】:
PHPhotoLibrary.shared().performChanges({
     PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: video.url!)}) {
     saved, error in
     if saved {
          print("Save status SUCCESS")
     }
}

【讨论】:

【解决方案4】:

按照@Nimble 和@Yuval Tal 解决方案,最好使用URLSession dataTask(with:completionHandler:) 方法在写入文件之前下载文件,如NSData(contentsOf:) Apple documentation 的警告部分所述

重要

不要使用此同步初始化程序来请求基于网络的 URL。 对于基于网络的 URL,此方法可以阻塞当前线程 在慢速网络上数十秒,导致用户不佳 经验,并且在 iOS 中,可能会导致您的应用被终止。

相反,对于非文件 URL,请考虑使用 URLSession 的 dataTask(with:completionHandler:) 方法

正确的实现可能是:

let defaultSession = URLSession(configuration: .default)
var dataTask: URLSessionDataTask? = nil

func downloadAndSaveVideoToGallery(videoURL: String, id: String = "default") {
    DispatchQueue.global(qos: .background).async {
        if let url = URL(string: videoURL) {
            let filePath = FileManager.default.temporaryDirectory.appendingPathComponent("\(id).mp4")
            print("work started")
            self.dataTask = self.defaultSession.dataTask(with: url, completionHandler: { [weak self] data, res, err in
                DispatchQueue.main.async {
                    do {
                        try data?.write(to: filePath)
                        PHPhotoLibrary.shared().performChanges({
                            PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: filePath)
                        }) { completed, error in
                            if completed {
                                print("Saved to gallery !")
                            } else if let error = error {
                                print(error.localizedDescription)
                            }
                        }
                    } catch {
                        print(error.localizedDescription)
                    }
                }
                self?.dataTask = nil
            })
            self.dataTask?.resume()
        }
    }
}

另一个好处是您可以通过调用 dataTask 上的相应方法来暂停、恢复和终止下载: URLSessionDataTask .resume() .suspend() .cancel()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多