# Download Offline Maps package

Maps Package is the actual downloadable and installable map content for a region. This guide covers how to register the download progress listener, monitor progress and handle any errors.

## Register the progress listener

It is recommended to register progress listeners before enqueueing a download. Register the progress listener before starting a download:

```swift
private var progressToken: NGLRegionalOfflineListenerToken?
private var selectedRegionId: Int?
 
func observeDownloadProgress() {
    progressToken = NGLRegionalOffline.addDownloadProgressListener {
        [weak self] progressByRegionId in
        guard let self, let regionId = selectedRegionId else { return }
 
        let key = NSNumber(value: regionId)
        guard let progress = progressByRegionId[key] else { return }
 
        progressView.progress = Float(progress.percent) / 100.0
        statusLabel.text = NGLRegionalOfflineDownloadStateLabel(progress.state)
 
        switch progress.state {
        case .completed:
            statusLabel.text = "Download complete"
 
        case .failed, .failedStorage:
            handleRegionalOfflineError(progress.error)
 
        default:
            break
        }
    }
}
```

The initial listener snapshot is delivered on the main thread and may run before registration returns when called from the main thread. Subsequent callbacks are also delivered on the main thread.

> _Treat_ `.completed` _as the only successful terminal download state._

## Enqueue a download

```swift
func download(regionId: Int, replacingExistingData: Bool = false) {
    NGLRegionalOffline.downloadRegion(
        withId: regionId,
        clearBefore: replacingExistingData
    ) { [weak self] error in
        guard let self else { return }
 
        if let error {
            // Shared resource preparation, region detail, or enqueue failure.
            handleRegionalOfflineError(error)
            return
        }
 
        // nil means that the task was enqueued. It does not mean that the
        // regional package has finished downloading.
    }
}
```

Note that the enqueue completion only reports whether the task was accepted, it does not report the final download result. Use the progress listener to determine the final result.

Also, it is recommended to handle enqueue and transfer errors separately.

> _Use_ `clearBefore: false` _for first downloads, retries, and downloads that should preserve existing regional data. Use_ `clearBefore: true` _only when the user explicitly replaces an installed region, such as during a version update._

## Understanding the two error paths

| Stage | Notification path | Example failures |
| --- | --- | --- |
| Before enqueue | The `Error?` passed to the _downloadRegion_ completion | Invalid region, region detail request failure, or duplicate active request |
| After enqueue | _NGLRegionalOfflineDownloadProgress.error_ | Network, HTTP, filesystem, insufficient storage, invalid package, decompression, installation, or Preview validation failure |

## Remove the progress listener

```swift
func removeDownloadProgressObserver() {
    if let progressToken {
        NGLRegionalOffline.removeDownloadProgressListener(progressToken)
        self.progressToken = nil
    }
}
```
