Download To Go
HLS/Fairplay Downloads feature is available from iOS 10.3+.
Download Manager
The DownloadManager
singleton instance available with Quickplay Player library provides all download functionalities under one umbrella. One could fetch all downloads tasks as well as enqueue and purge download tasks.
Download Task
The DownloadTask
with Quickplay Player library is analogous to a AVAssetDownloadTask
on AVFoundation
. A download task could be created and enqueued with download manager. Upon creating a download task, the task must be resumed to start download.
Download Task States
The following are the download task states
Suspended
- while the task is paused, this is also the initial stateRunning
- while task is executingCancelled
- while the task has been cancelledCompleted
- while the task has completedFailed
- while the task has failedStale
- while the task's asset has been deleted by OS or User
The download task exposes state and progress property which could be observed for state changes.
// Observing on download task's state property
downloadTask.state.add(self) { (oldValue, newValue) in
// handle state change
}
// Remove observers on download task complete, failed or Cancelled
downloadTask.state.remove(self)
Get All Download Tasks
To get all download tasks read allTasks
property with DownloadManager
. To get notified on task additions or removal, the same property can be observed for changes.
let allTasks = FLPlayerFactory.downloadManager.allTasks
Create Download Task
A download task can be created providing content id, name and preferrred bitrate for download. The contentId is to uniquely identify the download task and name is used to show the downloaded asset with the Settings app on iOS. Upon creating a download task, the task must be resumed to start download.
// Creating Player
if let contentURL = URL(string: contentUrl) {
let avURLAsset = AVURLAsset(url: contentURL)
// creating download request
let request = DownloadRequest(contentId: contentId,
contentUrl: avURLAsset.url,
title: name,
preferredVideoBitrate: 50_000)
// enqueue request
let downloadTaskResult = FLPlayerFactory.downloadManager.enqueue(request: request)
switch downloadTaskResult {
case let .success(downloadTask):
// resume task to start download
downloadTask.resume()
case let .failure(error):
// handle failure
}
}
Resume, Pause & Purge
When a download task has been created, it would be in suspended state. The same needs to be resumed to start the download. You could pause or cancel a running task. Purging a download task removes the download task as well its downloaded asset. Please note the persistent drm key if any associated with downloaded asset will not be deleted on purge of download task.
Download Progress
The progress of a download task could be tracked in two ways.
- Observing on
progress
property ofDownloadTask
- Implementing
DownloadManagerDelegate
protocol to get notified on progress and state changes
Listening to Download Task Events
One could listen to download task state changes and downoad task delegate callbacks conforming to DownloadManagerDelegate
protocol and setting the delegate with DownloadManager
.
// yourController must conform to DownloadManagerDelegate protocol
FLPlayerFactory.downloadManager.delegate = yourController;
Offline Playback
To play a downloaded asset, read the avURLAsset
property of the download task, which could be used with Player for playback. While playing fairplay protected downloaded asset, a dummy implementation of LicenseFetcherDelegate
must be updated with LicenseFetcher
to indicate that this content requires a persistent key for playback.
// Offline playback LicenseFetcherDelegate implementation
public class DownloadDelegate: FairplayLicenseFetcherDelegate {
public var skd: String
public var keyDeliveryType: KeyDeliveryType
init(skd: String, keyDeliveryType: KeyDeliveryType) {
self.skd = skd
self.keyDeliveryType = keyDeliveryType
}
public func didProvideApplicationCertificateRequest(for _: FairplayKeyLoadingRequest) {
// No-op
}
public func didProvideLicenseRequest(for _: FairplayKeyLoadingRequest, with _: Data, assetID _: String) {
// No-op
}
}
// delegate creation
let offlinePlaybackDelegate = DownloadDelegate(skd:"<SKD>", keyDeliveryType: .persistentStreamingKey)
// update this delegate instance with license fetcher prior to playback
Progressive Download
To play a downloading asset, use the AVURLAsset
instance available with the download task to instantiate the player.
The download task would be paused on playback start. Similarly the task would be resumed automatically when playback stops.
Managing Persistent Keys for Asset
The license key for offline playback can be fetched and persisted using LicenseFetcher
. It is suggested to persist the key prior to download of an asset. The key management is decoupled from downloaded asset, to facilitate manipulating (add, renew or delete) the keys independently. This is because technically a downloaded asset could be played using a valid key, irrespective of key being a persistent or on-demand key. Also, when a key expires, the asset need not be deleted and a new license could be fetched and persisted for the same asset.
if let contentURL = URL(string: playbackAsset.contentUrl) {
let avURLAsset = AVURLAsset(url: contentURL)
// Create License Fetcher Delegate for download
let delegate = FLPlayerFactory.fairplayLicenseFetcherDelegate(
applicationCertificate: appCert,
licenseUrl: licenseURL,
skd: skd,
keyDeliveryType: .download)
// Update License Fetcher to process persistent key fetching for an AVURLAsset
lf.updateLicenseFetcherDelegate(delegate, for: avURLAsset)
// Fetch persistent license
lf.fetchFairplayLicense(for: skd) { (result: Result<Void, Error>) in
switch result {
case .success:
// create download task and resume
case let .failure(error):
// handle failure
}
}
}
Download in Background
The application must include Background fetch
capability to enable download in background. iOS allows download in background when app is backgrounded or suspended or terminated, but there are certain system limitations on recovery of downloads.
Downloads cannot be recovered in following cases:
- Downloading with XCode Debugger attached
- App killed by pressing home button and swipe up
Concurrent Downloads
There is no limitations on concurrent downloads. But please note the time for download completion depends on various factors like number of concurrent downloads, network bandwidth and bitrate of downloading content.