在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 (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...