下载视频并将其保存到相机胶卷
Download and Save Video to Camera Roll
根据我阅读的所有示例和文档,这似乎应该是非常简单的事情,但由于某些奇怪的原因我仍然无法让它工作。
我正在使用 Alamofire Frame 工作从 instagram 下载视频。下载后,我想将视频保存到相机胶卷。这是我下载视频并保存到磁盘的代码:
let destination: (NSURL, NSHTTPURLResponse) -> (NSURL) = {
(temporaryURL, response) in
if let directoryURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] as? NSURL {
let finalPath = directoryURL.URLByAppendingPathComponent("\(Scripts.dateToString2(date: NSDate())).\(response.suggestedFilename!)")
InstagramEngine.downloadMediaPath = finalPath
Scripts.log("Final Path >> \(finalPath)")
return finalPath
}
return temporaryURL
}
let request = Alamofire.download(.GET, self.videoURL, destination)
request.response { _, response, data, error in
NSNotificationCenter.defaultCenter().postNotificationName(kMediaDownloadComplete, object: nil)
}
下载完成后,触发通知,调用此函数将其保存到相册:
UISaveVideoAtPathToSavedPhotosAlbum(InstagramEngine.downloadMediaPath.URLString, self, Selector("video:didFinishSavingWithError:contextInfo:"), nil)
一切都是根据我的日志语句调用的,没有发生错误。甚至为 UISaveVideoAtPathToSavedPhotosAlbum 成功调用了 didFinishSavingWithError,我确认没有发现错误。但是当我去查看相机胶卷时,我仍然没有看到那里保存的视频。有什么想法吗?
不幸的是,存在与 UISaveVideoAtPathToSavedPhotosAlbum
和格式 mp4
有关的错误,这是 Instagram 使用的格式。
有一个名为 UIVideoAtPathIsCompatibleWithSavedPhotosAlbum
的辅助方法可以帮助指示视频是否与方法 UISaveVideoAtPathToSavedPhotosAlbum
兼容。此returnsfalse
为从Instagram下载的视频。
幸运的是,仍然可以将视频存储到相机胶卷中。这可以使用 ALAssetsLibrary
。我已尝试采用您的示例代码并对其进行调整以使用 ALAssetsLibrary
,希望这可以帮助您使其正常工作。
import AssetsLibrary
...
...
func downloadVideoToCameraRoll() {
// Local variable pointing to the local file path for the downloaded video
var localFileUrl: String?
// A closure for generating the local file path for the downloaded video. This will be pointing to the Documents directory with a unique UDID file name.
let destination: (NSURL, NSHTTPURLResponse) -> (NSURL) = {
(temporaryURL, response) in
if let directoryURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] as? NSURL {
let finalPath = directoryURL.URLByAppendingPathComponent("\(NSUUID()).\(response.suggestedFilename!)")
localFileUrl = finalPath.absoluteString
return finalPath
}
return temporaryURL
}
// The media post which should be downloaded
let postURL = NSURL(string: "https://api.instagram.com/v1/media/" + "952201134785549382_250131908" + "?access_token=" + InstagramEngine.sharedEngine().accessToken)!
// Then some magic happens that turns the postURL into the videoURL, which is the actual url of the video media:
let videoURL = NSURL(string: "https://scontent.cdninstagram.com/hphotos-xfp1/t50.2886-16/11104555_1603400416544760_416259564_s.mp4")!
// Download starts
let request = Alamofire.download(.GET, videoURL, destination)
// Completion handler for the download
request.response { (request, response, data, error) -> Void in
if let path = localFileUrl {
let isVideoCompatible = UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(path)
println("bool: \(isVideoCompatible)") // This logs out "bool: false"
let library = ALAssetsLibrary()
library.writeVideoAtPathToSavedPhotosAlbum(NSURL(string: path), completionBlock: { (url, error) -> Void in
// Done! Go check your camera roll
})
}
}
}
以下是使用 Alamofire 下载和保存视频的方法。代码在 Swift 4. 请注意,我们需要使用 Photos
框架,因为 AssetsLibrary
已被弃用
import UIKit
import Alamofire
import Photos
/// Download and save video to camera roll
final class VideoFetcher {
private let fileManager: FileManager
init(fileManager: FileManager = FileManager.default) {
self.fileManager = fileManager
}
func downloadAndSave(videoUrl: URL, completion: @escaping (Bool) -> Void) {
let destination: (URL, HTTPURLResponse) -> (URL, DownloadRequest.DownloadOptions) = {
tempUrl, response in
let option = DownloadRequest.DownloadOptions()
let finalUrl = tempUrl.deletingPathExtension().appendingPathExtension(videoUrl.pathExtension)
return (finalUrl, option)
}
Alamofire.download(videoUrl, to: destination)
.response(completionHandler: { [weak self] response in
guard response.error == nil,
let destinationUrl = response.destinationURL else {
completion(false)
return
}
self?.save(videoFileUrl: destinationUrl, completion: completion)
})
}
private func save(videoFileUrl: URL, completion: @escaping (Bool) -> Void) {
PHPhotoLibrary.shared().performChanges({
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: videoFileUrl)
}, completionHandler: { succeeded, error in
guard error == nil, succeeded else {
completion(false)
return
}
completion(true)
})
}
}
根据我阅读的所有示例和文档,这似乎应该是非常简单的事情,但由于某些奇怪的原因我仍然无法让它工作。
我正在使用 Alamofire Frame 工作从 instagram 下载视频。下载后,我想将视频保存到相机胶卷。这是我下载视频并保存到磁盘的代码:
let destination: (NSURL, NSHTTPURLResponse) -> (NSURL) = {
(temporaryURL, response) in
if let directoryURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] as? NSURL {
let finalPath = directoryURL.URLByAppendingPathComponent("\(Scripts.dateToString2(date: NSDate())).\(response.suggestedFilename!)")
InstagramEngine.downloadMediaPath = finalPath
Scripts.log("Final Path >> \(finalPath)")
return finalPath
}
return temporaryURL
}
let request = Alamofire.download(.GET, self.videoURL, destination)
request.response { _, response, data, error in
NSNotificationCenter.defaultCenter().postNotificationName(kMediaDownloadComplete, object: nil)
}
下载完成后,触发通知,调用此函数将其保存到相册:
UISaveVideoAtPathToSavedPhotosAlbum(InstagramEngine.downloadMediaPath.URLString, self, Selector("video:didFinishSavingWithError:contextInfo:"), nil)
一切都是根据我的日志语句调用的,没有发生错误。甚至为 UISaveVideoAtPathToSavedPhotosAlbum 成功调用了 didFinishSavingWithError,我确认没有发现错误。但是当我去查看相机胶卷时,我仍然没有看到那里保存的视频。有什么想法吗?
不幸的是,存在与 UISaveVideoAtPathToSavedPhotosAlbum
和格式 mp4
有关的错误,这是 Instagram 使用的格式。
有一个名为 UIVideoAtPathIsCompatibleWithSavedPhotosAlbum
的辅助方法可以帮助指示视频是否与方法 UISaveVideoAtPathToSavedPhotosAlbum
兼容。此returnsfalse
为从Instagram下载的视频。
幸运的是,仍然可以将视频存储到相机胶卷中。这可以使用 ALAssetsLibrary
。我已尝试采用您的示例代码并对其进行调整以使用 ALAssetsLibrary
,希望这可以帮助您使其正常工作。
import AssetsLibrary
...
...
func downloadVideoToCameraRoll() {
// Local variable pointing to the local file path for the downloaded video
var localFileUrl: String?
// A closure for generating the local file path for the downloaded video. This will be pointing to the Documents directory with a unique UDID file name.
let destination: (NSURL, NSHTTPURLResponse) -> (NSURL) = {
(temporaryURL, response) in
if let directoryURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] as? NSURL {
let finalPath = directoryURL.URLByAppendingPathComponent("\(NSUUID()).\(response.suggestedFilename!)")
localFileUrl = finalPath.absoluteString
return finalPath
}
return temporaryURL
}
// The media post which should be downloaded
let postURL = NSURL(string: "https://api.instagram.com/v1/media/" + "952201134785549382_250131908" + "?access_token=" + InstagramEngine.sharedEngine().accessToken)!
// Then some magic happens that turns the postURL into the videoURL, which is the actual url of the video media:
let videoURL = NSURL(string: "https://scontent.cdninstagram.com/hphotos-xfp1/t50.2886-16/11104555_1603400416544760_416259564_s.mp4")!
// Download starts
let request = Alamofire.download(.GET, videoURL, destination)
// Completion handler for the download
request.response { (request, response, data, error) -> Void in
if let path = localFileUrl {
let isVideoCompatible = UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(path)
println("bool: \(isVideoCompatible)") // This logs out "bool: false"
let library = ALAssetsLibrary()
library.writeVideoAtPathToSavedPhotosAlbum(NSURL(string: path), completionBlock: { (url, error) -> Void in
// Done! Go check your camera roll
})
}
}
}
以下是使用 Alamofire 下载和保存视频的方法。代码在 Swift 4. 请注意,我们需要使用 Photos
框架,因为 AssetsLibrary
已被弃用
import UIKit
import Alamofire
import Photos
/// Download and save video to camera roll
final class VideoFetcher {
private let fileManager: FileManager
init(fileManager: FileManager = FileManager.default) {
self.fileManager = fileManager
}
func downloadAndSave(videoUrl: URL, completion: @escaping (Bool) -> Void) {
let destination: (URL, HTTPURLResponse) -> (URL, DownloadRequest.DownloadOptions) = {
tempUrl, response in
let option = DownloadRequest.DownloadOptions()
let finalUrl = tempUrl.deletingPathExtension().appendingPathExtension(videoUrl.pathExtension)
return (finalUrl, option)
}
Alamofire.download(videoUrl, to: destination)
.response(completionHandler: { [weak self] response in
guard response.error == nil,
let destinationUrl = response.destinationURL else {
completion(false)
return
}
self?.save(videoFileUrl: destinationUrl, completion: completion)
})
}
private func save(videoFileUrl: URL, completion: @escaping (Bool) -> Void) {
PHPhotoLibrary.shared().performChanges({
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: videoFileUrl)
}, completionHandler: { succeeded, error in
guard error == nil, succeeded else {
completion(false)
return
}
completion(true)
})
}
}