I am implementing HLS streaming as per Apple Docs
But the problem that I am facing is for resuming the download when the user kills the app. If a download is in progress and say its 50% done and the user kills the app or app is killed by the system due to any reason and when the app is alive again then the URL session delegate of didCompleteWithError
is called
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
}
and here I dont have the partially downloaded file path or ability to resume the task.
The only location for the downloaded file is called when the download is complete via the following delegate call
func urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask, didFinishDownloadingTo location: URL) {
}
Now doc says to use
downloadSession.getAllTasks { tasksArray in }
but unfortunately, it does not resume the download
So my problem is
Actually, you can use getAllTasks(completionHandler:)]
to get pending tasks which are not completed at the previous launch but somehow these tasks will be cancelled immediately after download session is created which leads to urlSession(_:task:didCompleteWithError:)
is called as you see.
Luckily, I found another way to resume AVAssetDownloadTask
AVAssetDownloadTask provides the ability to resume previously stopped downloads under certain circumstances. To do so, simply instantiate a new AVAssetDownloadTask with an AVURLAsset instantiated with a file NSURL pointing to the partially downloaded bundle with the desired download options, and the download will continue restoring any previously downloaded data.
It means that if you want to resume a pending AVAssetDownloadTask
, you have to save location
from urlSession(_:assetDownloadTask:didFinishDownloadingTo:)
when download task is stopped. After that, create another download task base on the partially downloaded file.
func urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask, didFinishDownloadingTo location: URL) {
destinationURL = location
}
func resumeDownloadTask() {
let urlAsset = AVURLAsset(url: destinationURL)
downloadTask = assetDownloadURLSession.makeAssetDownloadTask(asset: urlAsset, assetTitle: "title", assetArtworkData: nil, options: nil)
downloadTask.resume()
}
urlSession(_:assetDownloadTask:didFinishDownloadingTo:)
will always be called before urlSession(_:task:didCompleteWithError:)
so you can get destinationURL
in both case when app is terminated and relaunch or download task is cancelled.
Note that you shouldn't create new download task inside urlSession(_:task:didCompleteWithError:)
, somehow it will lead to an infinity loop.
With your second question, simply delete the file by using destinationURL
.
For more detail, I created a sample repo at the below link. There is still some bug but it can run in normal case. Try to start download task, let it runs for a while and terminated the app. Relaunch and resume the task, you will see the result.
https://github.com/trungducc/stackoverflow/tree/hls-download-resuming
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With