HTTP Live Streaming
(HLS)) Is an ideal way to provide media for playback applications . use HLS, You can provide multiple media streams at different bit rates , And your playback client will dynamically select the appropriate stream as the network bandwidth changes . This ensures that you always provide the best quality content based on the user's current network conditions . This chapter describes how to use it in playback applications HLS The unique function of .

from iOS 10 start , You can use the AVFoundation take HTTP Live
Streaming Download resources to iOS equipment . This new feature allows users to quickly access , Reliable network when downloading and storing on its device HLS film , And you can watch it later without a network connection . By introducing this feature ,HLS It can minimize the impact of inconsistent network availability on user experience .

use AVAssetDownloadURLSession
<https://developer.apple.com/documentation/avfoundation/avassetdownloadurlsession>
To realize the resource download function , He is NSURLSession Subclasses of , It is mainly used to create and execute resource download tasks .
func setupAssetDownload() { // Create new background session configuration.
configuration = URLSessionConfiguration.background(withIdentifier:
downloadIdentifier) // Create a new AVAssetDownloadURLSession with background
configuration, delegate, and queue downloadSession =
AVAssetDownloadURLSession(configuration: configuration, assetDownloadDelegate:
self, delegateQueue: OperationQueue.main) }
  Configuration complete URLSession in the future , establish AVAssetDownloadTask
<https://developer.apple.com/documentation/avfoundation/avassetdownloadtask>
Instance to start the download task
func setupAssetDownload() { ... // Previous AVAssetDownloadURLSession
configuration ... let url = // HLS Asset URL let asset = AVURLAsset(url: url)
// Create new AVAssetDownloadTask for the desired asset let downloadTask =
downloadSession.makeAssetDownloadTask(asset: asset, assetTitle: assetTitle,
assetArtworkData: nil, options: nil) // Start task and begin download
downloadTask?.resume() }

 options The model selection can be passed in one Dictionary Used to select different bits and media types . If Nil, The highest quality audio and video content will be downloaded by default . Because it can be downloaded in the background , When App When terminated , You need to resume the last download task for the next startup , At this time, you can use the  
NSURLSessionConfiguration Configured in identifier To create a new one NSURLSessionConfiguration object , Recreate
AVAssetDownloadURLSession object , use session Of getTasksWithCompletionHandler:
<https://developer.apple.com/documentation/foundation/nsurlsession/1411578-gettaskswithcompletionhandler>
Method to get the terminated task , To resume the download task .
func restorePendingDownloads() { // Create session configuration with ORIGINAL
download identifier configuration =
URLSessionConfiguration.background(withIdentifier: downloadIdentifier) //
Create a new AVAssetDownloadURLSession downloadSession =
AVAssetDownloadURLSession(configuration: configuration, assetDownloadDelegate:
self, delegateQueue: OperationQueue.main) // Grab all the pending tasks
associated with the downloadSession downloadSession.getAllTasks { tasksArray in
// For each task, restore the state in the app for task in tasksArray { guard
let downloadTask = task as? AVAssetDownloadTask else { break } // Restore
asset, progress indicators, state, etc... let asset = downloadTask.urlAsset } }
}
  You can monitor the progress of the download through the proxy method :
func urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask,
didLoad timeRange: CMTimeRange, totalTimeRangesLoaded loadedTimeRanges:
[NSValue], timeRangeExpectedToLoad: CMTimeRange) { var percentComplete = 0.0 //
Iterate through the loaded time ranges for value in loadedTimeRanges { //
Unwrap the CMTimeRange from the NSValue let loadedTimeRange =
value.timeRangeValue // Calculate the percentage of the total expected asset
duration percentComplete += loadedTimeRange.duration.seconds /
timeRangeExpectedToLoad.duration.seconds } percentComplete *= 100 // Update UI
state: post notification, update KVO state, invoke callback, etc. }
Called when the download is complete or failed session Proxy method for , You can set the file save location in this method , And NSURLSessionDownloadDelegate in
URLSession:downloadTask:didFinishDownloadingToURL:
<https://developer.apple.com/documentation/foundation/urlsessiondownloaddelegate/1411575-urlsession>
When the method is different , Users should not fix the location of the downloaded resource , It's under the control of the system , Incoming URL, Represents the final location of the download resource on the disk .
func urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask,
didFinishDownloadingTo location: URL) { // Do not move the asset from the
download location UserDefaults.standard.set(location.relativePath, forKey:
"assetPath") }
You can update the downloaded resources , For example, in the past, the server did not provide HD resources or some   Resource options . When the server has a resource update  session Proxy method for
URLSession:assetDownloadTask:didResolveMediaSelection:
<https://developer.apple.com/documentation/avfoundation/avassetdownloaddelegate/1621023-urlsession>
Will be called , preservation AVMediaSelection object , For subsequent download tasks
func urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask,
didResolve resolvedMediaSelection: AVMediaSelection) { // Store away for later
retrieval when main asset download is complete // mediaSelectionMap is defined
as: [AVAssetDownloadTask : AVMediaSelection]()
mediaSelectionMap[assetDownloadTask] = resolvedMediaSelection }
Get content that is not cached locally by
func nextMediaSelection(_ asset: AVURLAsset) -> (mediaSelectionGroup:
AVMediaSelectionGroup? mediaSelectionOption: AVMediaSelectionOption?) { // If
the specified asset has not associated asset cache, return nil tuple guard let
assetCache = asset.assetCache else { return (nil, nil) } // Iterate through
audible and legible characteristics to find associated groups for asset for
characteristic in [AVMediaCharacteristicAudible, AVMediaCharacteristicLegible]
{ if let mediaSelectionGroup =
asset.mediaSelectionGroup(forMediaCharacteristic: characteristic) { //
Determine which offline media selection options exist for this asset let
savedOptions = assetCache.mediaSelectionOptions(in: mediaSelectionGroup) // If
there are still media options to download... if savedOptions.count <
mediaSelectionGroup.options.count { for option in mediaSelectionGroup.options {
if !savedOptions.contains(option) { // This option hasn't been downloaded.
Return it so it can be. return (mediaSelectionGroup, option) } } } } } // At
this point all media options have been downloaded. return (nil, nil) }
The following code checks and downloads all the optional media resources  
func urlSession(_ session: URLSession, task: URLSessionTask,
didCompleteWithError error: Error?) { guard error == nil else { return } guard
let task = task as? AVAssetDownloadTask else { return } // Determine the next
available AVMediaSelectionOption to download let mediaSelectionPair =
nextMediaSelection(task.urlAsset) // If an undownloaded media selection option
exists in the group... if let group = mediaSelectionPair.mediaSelectionGroup,
option = mediaSelectionPair.mediaSelectionOption { // Exit early if no
corresponding AVMediaSelection exists for the current task guard let
originalMediaSelection = mediaSelectionMap[task] else { return } // Create a
mutable copy and select the media selection option in the media selection group
let mediaSelection = originalMediaSelection.mutableCopy() as!
AVMutableMediaSelection mediaSelection.select(option, in: group) // Create a
new download task with this media selection in its options let options =
[AVAssetDownloadTaskMediaSelectionKey: mediaSelection] let task =
downloadSession.makeAssetDownloadTask(asset: task.urlAsset, assetTitle:
assetTitle, assetArtworkData: nil, options: options) // Start media selection
download task?.resume() } else { // All media selection downloads complete } }
Once the download starts , And you can start syncing
func downloadAndPlayAsset(_ asset: AVURLAsset) { // Create new
AVAssetDownloadTask for the desired asset // Passing a nil options value
indicates the highest available bitrate should be downloaded let downloadTask =
downloadSession.makeAssetDownloadTask(asset: asset, assetTitle: assetTitle,
assetArtworkData: nil, options: nil)! // Start task downloadTask.resume() //
Create standard playback items and begin playback let playerItem =
AVPlayerItem(asset: downloadTask.urlAsset) player = AVPlayer(playerItem:
playerItem) player.play() }
You can also play the downloaded offline resources , Use to specify the resource location after the download is complete
func playOfflineAsset() { guard let assetPath =
UserDefaults.standard.value(forKey: "assetPath") as? String else { // Present
Error: No offline version of this asset available return } let baseURL =
URL(fileURLWithPath: NSHomeDirectory()) let assetURL =
baseURL.appendingPathComponent(assetPath) let asset = AVURLAsset(url: assetURL)
if let cache = asset.assetCache, cache.isPlayableOffline { // Set up player
item and player and begin playback } else { // Present Error: No playable
version of this asset exists offline } }
  Delete file :
func deleteOfflineAsset() { do { let userDefaults = UserDefaults.standard if
let assetPath = userDefaults.value(forKey: "assetPath") as? String { let
baseURL = URL(fileURLWithPath: NSHomeDirectory()) let assetURL =
baseURL.appendingPathComponent(assetPath) try
FileManager.default.removeItem(at: assetURL) userDefaults.removeObject(forKey:
"assetPath") } } catch { print("An error occured deleting offline asset:
\(error)") } }
AVPlayerItem Of accessLog
<https://developer.apple.com/documentation/avfoundation/avplayeritem/1388499-accesslog>
 and errorLog
<https://developer.apple.com/documentation/avfoundation/avplayeritem/1387573-errorlog>
Property is used to read the log file . 

<>