Downloads

The Download to go(D2G) feature allows you to download VODs and play them back offline and is managed with DiceShield class. First of all it needs to be setup properly

// import module responsible for D2G
import dice_shield_ios

// Configure internal network requests manager to fetch all required data for downloading from DICE api having VOD id
let config = APIConfig(baseURL: "<base url without backslash in the end>",
                                apiKey: "<api key>",
                                realm: "<realm>",
                                deviceId: "<device id>",
                                headers: "<any extra headers to include with all api calls>")

DiceShield.sharedProvider.setup(config: config)

Before downloading set auth token, this needs to be updated every time token is expired, if token is expired DiceShield will return an error that should be handled with refresh token and call this method again with a fresh token

DiceShield.sharedProvider.setToken(newToken: "<authorisationToken>")

You will also need to observe downloads updates like download progress/state etc. This method will be called for all downloads after it was added with DiceShield.sharedProvider.addDownload(asset: DownloadableAsset)

DiceShield.sharedProvider.delegate = self

func downloadDidUpdate(withData data: DownloadUpdateInfo) {
    DispatchQueue.main.async {
        //update UI
        for viewModel in self.viewModels {
            if viewModel.id == data.assetId {
                viewModel.progress = data.progress
                viewModel.downloadState = data.state
                viewModel.expiryDate = data.expiryDate //if this date is expired (data.expiryDate < Date.current) you should renew it with corresponding method: DiceShield.sharedProvider.renewLicense
            }
        }
    }        
}

Start downloading certain content

Important

all previous downloads with same ID will be removed and replaced with the new one

let asset = DownloadableAsset(
    itemId: "<VOD id>",
    title: "Video title", // video title
    extraData: nil, //any other data you want to store assosiated with this content
    images: nil, //any images you want to store assisiated with this content
    quality: .HIGH, //desired quality to download
    language: "eng" //language of VOD to download in ISO 639-3 format
)

DiceShield.sharedProvider.addDownload(asset: asset) { [weak self] result in
    DispatchQueue.main.async {
        switch result {
        case .success:
            //at this point download was added to downloading queue and you can observe download updates with a delegate method DownloadProviderDelegate.downloadDidUpdate(withData: DownloadUpdateInfo) see above
            break
        case .failure(let error):
            //You can cast all errors to DiceShieldError to get an underlying reason of it is possible
            if let error = error as? DiceShieldError, error.kind == .unauthorized {
                //here for example refresh token and provide valid one
                self?.refreshToken() { token in
                    DiceShield.sharedProvider.setToken(newToken: token)
                }
            }
        }
    }
}

Get all downloads that were added to the queue

DiceShield.sharedProvider.getAllDownloads() { [weak self] result in
    DispatchQueue.main.async {
        guard let self = self else { return }
        switch result {
        case .success(let assets):
            //update UI here with all downloaded/downloading assets
        default:
            break
        }
    }
}

All downloads will have assosiated license with expiration date, when it is expired you will no longer be able to playback that content until license is renewed.

DiceShield.sharedProvider.renewLicense(id: "<VOD id>") { [weak self] (result) in
    DispatchQueue.main.async {
        switch result {
        case .success:
            //license was renewed, you should be able to observe this change through delegate method
        case .failure(let error):
            //You can cast all errors to DiceShieldError to get an underlying reason of it is possible
            if let error = error as? DiceShieldError, error.kind == .unauthorized {
                //here for example refresh token and provide valid one
                self?.refreshToken() { token in
                    DiceShield.sharedProvider.setToken(newToken: token)
                }
            }
        }
    }
}

To playback downloaded content

DiceShield.sharedProvider.downloadProvider.getDownload(forId: "<VOD id>") { [weak self] result in
    DispatchQueue.main.async {
        switch result {
        case .success(let data):
            guard let localUrl = data.localFileUrl else { return }
            let source = DorisSource(playerItem: AVPlayerItem(url: localUrl))
            source.drm = DorisDRMSource(contentUrl: filePath.absoluteString, croToken: nil, licensingServerUrl: nil)
            doris?.load(source: source, initialSeek: nil)
        case .failure(let error):
            self?.view?.showError(error.localizedDescription)
        }
    }
}

You will also have controll over downloads with these methods

    func getDownloads(forStates states: [AssetDownloadState], completion: @escaping (Swift.Result<[AssetData], Error>) -> Void)
    func removeDownloads(itemIds: [String], completion: @escaping (Swift.Result<Void, Error>) -> Void)
    func removeDownload(itemId: String, completion: @escaping (Swift.Result<Void, Error>) -> Void)
    func pauseDownload(itemID: String, completion: @escaping (Swift.Result<Void, Error>) -> Void)
    func resumeDownload(itemID: String, completion: @escaping (Swift.Result<Void, Error>) -> Void)
    func pauseAllDownloads(completion: @escaping (Swift.Result<Void, Error>) -> Void)
    func resumeAllDownloads(completion: @escaping (Swift.Result<Void, Error>) -> Void)
    func cancelAllDownloads(completion: @escaping (Swift.Result<Void, Error>) -> Void)

Important!: If your application was closed while downloading content, it won’t automatically resume on relaunch. You will have to resume all downloads manually, call this method from your AppDelagate to achieve that

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    DiceShield.sharedProvider.restoreSuspendedDownloads()
    return true
}

Doris