Once an instance of AVAssetDownloadURLSession is created, It is not possible to directly change properties including the underlying URLSessionConfiguration with which the session is created. However, we can create a new session and move our download tasks to that new session. This is done in four steps:

  1. Keep track of which download tasks need to be recreated.
  2. Remove any strong reference to the current session.
  3. Invalidate the session.
  4. Create a new AVAssetDownloadURLSession with an updated URLSessionConfiguration

Keep track of the download tasks we want to restore

When we reconfigure our AVAssetDownloadURLSession we want to recreate the downloads tasks which state is currently .running or .suspended. To do this we need to keep track of which these download tasks, because on invalidating the session the state of each download task will change to .completed. There are two ways to do that:

  1. Before invalidating the session we check the state of all the download tasks and keep a reference to the ones we want to recreate later.
  2. After invalidating the session we will receive a callback on func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) for each.

Allthough both ways are equally valid, I prefer option 1, because this gives us a bit more control and does not require adding logic to an already complex implementation of func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?). So I will explain the steps necessary for this option.

Lets say we track our download tasks by keeping an array of Download, where Download is:

struct Download {
    /// Human-readable title to identify the download
    let title: String
    /// Remote url of the HLS
    let url: URL
    /// Location the HLS is downloaded to
    let localURL: URL?
    /// Weak reference to the download task
    weak var downloadTask: AVAggregateAssetDownloadTask?
    /// State of the download derived from the underlying download task.
    var state: URLSessionTask.State { downloadTask.state ?? .completed }
}

We iterate through our downloads and store the ones we want to restore in a dedicated array:

let downloadsToRestore: [Download] = []

for download in currentDownloads {
    switch download.state {
    case .running, .suspended:
        downloadsToRestore.append(download)
    default:
    continue
    }
}

Invalidating the AVAssetDownloadURLSession

To invalidate our current session, AVAssetDownloadURLSession offers two methods to invalidate the session: func finishTasksAndInvalidate() and func invalidateAndCancel(). We are interested in func invalidateAndCancel(). But first, we need to remove any reference to our current session. So, our method will look something like:

/// Reference to the current download session
var downloadSession: AVAssetDownloadURLSession?

func invalidateDownloadSession() {
    /// Set up temporary reference
    let session = downloadSession

    /// Remove reference to the download session from our class
    downloadSession = nil

    // Invalidate the current session.
    session?.invalidateAndCancel()
}


As mentioned earlier, upon calling invalidating our session will fail all current download tasks. Once the session is invalidated, you will get a callback on:

func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?)

Creating a new AVAssetDownloadURLSession

We are now ready to create a new AVAssetDownloadURLSession, in exactly the same way we have created our initial session:

// We can reuse our initial identifier
let identifier = "hlsURLSessionIdentifier"

// Create a new `URLSessionConfiguration`
let updatedConfiguration = URLSessionConfiguration.background(withIdentifier: identifier)

// Adjust our `URLSessionConfiguration`
configuration.allowCellularAccess = true // We now allow downloading over cellular.
configuration.isDiscretionary = true // We now do want the device to check for optimal battery conditions.
configuration.networkServiceType = .video

// Create a the `AVAssetDownloadURLSession`
downloadSession = AVAssetDownloadURLSession(configuration: updatedConfiguration,
                                            assetDownloadDelegate: self,
                                            delegateQueue: .main)

// Restore our pending download tasks
for download in downloadsToRestore {
    startDownload(url: download.url)
}