如何解决在SwiftUI中下载视频的实际麻烦
我很难在后台为SwiftUI下载文件。我是一个真正的白痴,还是很难?
我可能有一个错误的概念,即具有配置为后台的会话的downloadTasks如何工作。我尝试了很多方法;这是我目前正在做的事情:
import Foundation
import Combine
class BackgroundDownloadTasks: ObservableObject{
/// This method is called from each download button in a row of a List in the Listings SwiftUI View
/// This call is authenticated with a bearer token
/// parameter downloadVideo with a Download model
func downloadVideoInBackground(downloadVideo: Download) {
let vimeoHeaders = mmHeaders(
ContentType: "application/json",HttpMethod: "GET",Authorization: "Bearer <-- Token Here -->"
)
let ST = SessionTasks(url: downloadVideo.url)
let vimeodownloadLinksRequest = ST.getRequest(mmHeaders: vimeoHeaders)
let screenWidth = UIScreen.main.bounds.width
let screenHeight = UIScreen.main.bounds.height
print( screenWidth,screenHeight)
// This fetch successfully retrieves the Vimeo objects with the limited time download links
ST.fetch(from: vimeodownloadLinksRequest) { result in
switch result {
case .success(let data):
dispatchQueue.main.async {
do {
let response = try JSONDecoder().decode(Vimeodownload.self,from: data)
// The SessionTasks is reinstantiated with nil as the url is set through setter injection
var SDV = SessionTasks(url: nil)
var BkgD = BkgDownloader()
var downloadLinkForIPAD: URL?
var downloadLinkForIPHONE: URL?
// Get the and set the iphone and ipad video sizes and set to their download link
for videoFields in response.download {
switch videoFields.public_name {
case "SD 540p":
downloadLinkForIPAD = URL( string: String(videoFields.link) )
case "SD 360p":
downloadLinkForIPHONE = URL( string: String(videoFields.link) )
default:
break
}
}
if ( nil != downloadLinkForIPAD || nil != downloadLinkForIPHONE ) {
if UIDevice.current.model.hasPrefix("iPad") {
print("iPad")
// download 540p video
SDV.setUrl(url: downloadLinkForIPAD)
// unauthenticated url so we don't pass a request and just a URL
SDV.downloadedFile(url: downloadLinkForIPAD!)
} else {
print("iPhone or iPod Touch")
// download 360p video
SDV.setUrl(url: downloadLinkForIPHONE)
// unauthenticated url so we don't pass a request and just a URL
SDV.downloadedFile(url: downloadLinkForIPHONE!)
}
}
}
catch (let error ) {
print(error.localizedDescription)
}
}
case .failure(let error):
dispatchQueue.main.async {
print(error.localizedDescription)
}
}
}
}
}
这是会话代码:
mutating func getSession(identifier: String = "unique-identifier-here",isdisretionary: Bool = false,useBackgroundMode: Bool = true ) -> URLSession? {
// Check if 3 background sessions exist then don't allow the download of more videos until they complete
if ( 3 == self.tasksArray.count ) {
return nil
}
// No existing session so create it
let config = URLSessionConfiguration.background(withIdentifier: identifier)
config.isdiscretionary = isdisretionary
config.shouldUseExtendedBackgroundIdleMode = useBackgroundMode
config.sessionSendsLaunchEvents = true
let delegateQueue = OperationQueue()
delegateQueue.qualityOfService = .userInitiated
let session = URLSession(
configuration: config,delegate: nil,delegateQueue: delegateQueue
)
return session
}
这是简单的downloadedFile()方法。我了解我可能需要真正更改它,因为它无法得知视频是否正在下载,并且无法加载进度:
mutating func downloadedFile(url: URL) {
let task = Self.self.session?.downloadTask(with: url)
self.tasksArray.append(task!.taskIdentifier)
print(task?.taskIdentifier)
task?.resume()
}
mutating func urlSession(_ session: URLSession,downloadTask: URLSessionDownloadTask,didFinishDownloadingTo location: URL) {
do {
let manager = FileManager.default
let destinationURL = try manager.url(for: .documentDirectory,in: .userDomainMask,appropriateFor: nil,create: true)
.appendingPathComponent(downloadTask.originalRequest!.url!.lastPathComponent)
print( destinationURL)
try? manager.removeItem(at: destinationURL)
try manager.moveItem(at: location,to: destinationURL)
print(destinationURL)
} catch {
print(error)
}
if let index = self.tasksArray.firstIndex(of: downloadTask.taskIdentifier) {
self.tasksArray.remove(at: index)
print(self.tasksArray.count)
}
let taskCount = self.tasksArray.count
dispatchQueue.main.async() {
if taskCount == 0 {
//Do whatever you want,all downloads are completed
//the dispatchQueue is for what I use this for...maybe not needed in you case
}
}
}
我在一次尝试中将此添加到了appDelegate文件中;它与这里的其他代码无关,尽管我只想表明它是为了表明我知道只能使用完成处理程序,而我们需要触发委托:
var bgSessionCompletionHandler: (() -> Void)?
func application(_ application: UIApplication,handleEventsForBackgroundURLSession identifier: String,completionHandler: @escaping () -> Void) {
bgSessionCompletionHandler = completionHandler
}
这是我在运行代码并在视图中选择要下载的视频时打印的内容。您可以看到已选择要下载的链接以及放置下载任务的数组:
https://player.vimeo.com/play/1616389087?s=364371142_f3d382751a98e6bba8525af9f025b3e6&loc=external&context=Vimeo%5CController%5CApi%5CResources%5CUser%5CVideoController.&download=1&filename=Sample.mp4 [BackgroundDownloadTask 。]
单击后,无论是在前景还是背景中,我都要等待25秒钟才能通过网络下载视频,然后检查应用程序文档和tmp,并且没有文件;就像dameon有后台会话,但它没有运行。
我可以使用默认的URLSession下载视频,尽管不应在生产中使用该视频,因为它会浪费用户的内存。
视频范围从200MB到1.5GB,因此显然不是内存下载的选项。
请让我知道是否需要其他详细信息。
感谢您的帮助。
最好, 史蒂夫
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。