簡體   English   中英

Swift - 從遠程 URL 下載視頻並將其保存在相冊中

[英]Swift - Download a video from distant URL and save it in an photo album

我目前正在我的應用程序中顯示一個視頻,我希望用戶能夠將其保存到其設備畫廊/相冊照片/相機膠卷中。 這就是我正在做的,但視頻沒有保存在相冊中:/

    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)

但是我有錯誤“無法從文件(空)創建數據”。 我的“資產變更請求”為零。 我不明白,因為我的 url 是有效的,當我使用瀏覽器訪問它時,它會下載一個快速時間文件。

如果有人可以幫助我,將不勝感激! 我正在使用 Swift 並針對 iOS 8.0 分鍾。

更新

想使用URLSession來更新斯威夫特3的答案,想通了,答案已經相關主題中存在這里 用它。

原始答案

下面的代碼將視頻文件保存到相機膠卷。 我重復使用了你的代碼 - 我刪除了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的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!")
                }
            }
        }
    }
}
PHPhotoLibrary.shared().performChanges({
     PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: video.url!)}) {
     saved, error in
     if saved {
          print("Save status SUCCESS")
     }
}

遵循@Nimble 和@Yuval Tal 解決方案,更可取的做法是使用URLSession dataTask(with:completionHandler:)方法在編寫文件之前下載文件,如NSData(contentsOf:) Apple 文檔的警告部分所述

重要的

不要使用這個同步初始化器來請求基於網絡的 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()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM