Update map data
With the MapUpdater class you can check if newer map versions are available and - if available - update the already installed regions. Each HERE SDK version comes hardcoded with a specific map version. This defines the map data in the cache and the downloaded regions (if any).
Note that certain HERE SDK features may require a specific map version - as indicated in the related API Reference documentation or in this guide.
NoteIncremental map updates are supported, by default: instead of downloading an entire region, only the parts that have changed will be installed. This results in a faster update process and less downloaded data. If the
patchHrnfield of aCatalogConfigurationisnil, then incremental updates will be disabled and the map data is downloaded still incrementally to some extent, but in larger bundles resulting in more bandwidth consumption. Usually, this is handled internally by the HERE SDK and developers do not need to create aCatalogConfigurationon their own.In general, we provide weekly map updates. For the first-time usage, a user must download the full region(s). Any update after the first download can be done incrementally. Note that the decision if a full download or only an incremental update is executed is done automatically by the HERE SDK.
Incremental map updates (also called "patching") will result in a smaller download size for approximately 8 OCM map versions. For example, if a new map version has been installed with OCM version x.y.7, you will benefit from incremental updates up to x.y.15. Starting with OCM version x.y.16, even when versions have been skipped, more map data is required again.
With weekly OCM map updates, this means that after approximately 8 weeks, theMapUpdaterwill download more data whenmapUpdater.updateCatalog(...)is executed. Note that before performing the update,CatalogUpdateInfoprovides information about how much map data will be updated.
Use the MapUpdater
When an app update is installed that integrates a new HERE SDK version, it will most likely also feature a new map version. However, the installed regions will not be automatically updated, unless the MapUpdater is used to perform this task. Of course, map updates can also be installed for older HERE SDK versions.
- Check the currently used map version by calling
mapUpdater.getCurrentMapVersion(). - Check if an update is available by calling
mapUpdater.retrieveCatalogsUpdateInfo().
The class needs to be created asynchronously to not block the UI thread - in the same manner as the MapDownloader:
guard let sdkNativeEngine = SDKNativeEngine.sharedInstance else {
fatalError("SDKNativeEngine not initialized.")
}
// Create MapUpdater in background to not block the UI thread.
MapUpdater.fromEngineAsync(sdkNativeEngine, { mapUpdater in
let mapUpdaterInstance = mapUpdater
// Use the instance ...
})
Get current map version
Sometimes, it may be useful to know the map version used for the map cache and the installed Region data. You can use the following code snippet to log the currently used map version:
guard let sdkNativeEngine = SDKNativeEngine.sharedInstance else {
fatalError("SDKNativeEngine not initialized.")
}
// Create MapUpdater in background to not block the UI thread.
MapUpdater.fromEngineAsync(sdkNativeEngine, { mapUpdater in
let mapUpdaterInstance = mapUpdater
do {
let mapVersionHandle = try mapUpdaterInstance.getCurrentMapVersion()
let versionInfo = mapVersionHandle.stringRepresentation(separator: ",")
print("Info: \(String(describing: versionInfo))")
} catch let mapLoaderException {
fatalError("Get current map version failed: \(mapLoaderException.localizedDescription)")
}
})
This information is mostly useful for debugging purposes. Note that the map version is also logged by the HERE SDK when the map view is shown for the first time.
It has the format [cache-version].[offline-maps-version],[japan-cache-version].[japan-offline-maps-version]. An example result my look like "47.47,47.47". It is not possible to get different versions for the map cache and offline maps.
Check for map updates
Map update checks can be performed at each application start. However, when region data has been installed, this may become a lengthy operation, so users should be informed. Usually, you first check for an update by calling retrieveCatalogsUpdateInfo() - this provides one or more CatalogUpdateInfo items that can be used to call updateCatalog():
private func checkForMapUpdates() {
guard let mapUpdater = mapUpdater else {
showMessage("MapUpdater instance not ready. Try again.")
return
}
_ = mapUpdater.retrieveCatalogsUpdateInfo(callback: onCatalogUpdateCompleted)
}
// Completion handler to get notified whether a catalog update is available or not.
private func onCatalogUpdateCompleted(mapLoaderError: MapLoaderError?, catalogList: [CatalogUpdateInfo]?) {
if let error = mapLoaderError {
print("CatalogUpdateCheck Error: \(error)")
return
}
// When error is nil, then the list is guaranteed to be not nil.
if catalogList!.isEmpty {
print("CatalogUpdateCheck: No map updates are available.");
}
logCurrentSDKVersion();
logCurrentMapVersion();
for catalogUpdateInfo in catalogList! {
print("CatalogUpdateCheck - Catalog name:" + catalogUpdateInfo.installedCatalog.catalogIdentifier.hrn);
print("CatalogUpdateCheck - Installed map version: \(String(describing: catalogUpdateInfo.installedCatalog.catalogIdentifier.version))");
print("CatalogUpdateCheck - Latest available map version: \(catalogUpdateInfo.latestVersion)");
performMapUpdate(catalogUpdateInfo: catalogUpdateInfo);
}
}
Update map data and map version
As a next step we implement the code to perform the map update. This will also raise the map version:
// Downloads and installs map updates for any of the already downloaded regions.
// Note that this example only shows how to download one region.
private func performMapUpdate(catalogUpdateInfo: CatalogUpdateInfo) {
guard let mapUpdater = mapUpdater else {
showMessage("MapUpdater instance not ready. Try again.")
return
}
// This method conveniently updates all installed regions if an update is available.
// Optionally, you can use the returned CatalogUpdateTask to pause / resume or cancel the update.
_ = mapUpdater.updateCatalog(catalogInfo: catalogUpdateInfo, completion: catalogUpdateListenerImpl)
}
private let catalogUpdateListenerImpl = CatalogUpdateListenerImpl()
private class CatalogUpdateListenerImpl : CatalogUpdateProgressListener {
// Conform to the CatalogUpdateProgressListener protocol.
func onPause(error: heresdk.MapLoaderError?) {
if let mapLoaderError = error {
print("Catalog update onPause error. The task tried to often to retry the update: \(mapLoaderError).")
} else {
print("CatalogUpdate: The map update was paused by the user calling catalogUpdateTask.pause().")
}
}
// Conform to the CatalogUpdateProgressListener protocol.
func onProgress(region: RegionId, percentage: Int32) {
print("CatalogUpdate: Downloading and installing a map update. Progress for \(region.id): \(percentage)%.")
}
// Conform to the CatalogUpdateProgressListener protocol.
func onComplete(error: MapLoaderError?) {
if let mapLoaderError = error {
print("CatalogUpdate completion error: \(mapLoaderError)")
return
}
print("CatalogUpdate: One or more map update has been successfully installed.")
// It is recommend to call now also `getDownloadableRegions()` to update
// the internal catalog data that is needed to download, update or delete
// existing `Region` data. It is required to do this at least once
// before doing a new download, update or delete operation.
}
// Conform to the CatalogUpdateProgressListener protocol.
func onResume() {
print("MapUpdate: A previously paused map update has been resumed.")
}
}
Note that calling updateCatalog() is internally optimized to update only the parts of a Region that actually have changed. This means that for most cases an update does not require a user to redownload all packages and instead, each region is divided into several internal bundles that are only downloaded again when there was a map data change in it. This procedure is also known as incremental map updates.
- If no offline maps have been installed, calling
mapUpdater.updateCatalog()will only clear the cache and the cache will be subsequently filled with new data for the latest available map version. - The cache will always use the same map version as offline maps. If offline maps are updated, the cache will be also updated. The cache version will never be older than the offline maps version.
NoteIt is not possible to enforce a map update by uninstalling all downloaded regions via
deleteRegions()and then downloading the desired regions again. In that case, the same map version would be downloaded. However, ifupdateCatalog()is executed beforehand then a map update may be indicated and can be installed.
Please ensure the following when updating maps:
- Once
mapUpdater.updateCatalog()has completed, it is required to callgetDownloadableRegions()to update the internal catalog data that is needed to download, update or delete existingRegiondata. - During an ongoing map update and related operations, not all
MapDownloaderandMapUpdaterfeatures may be accessible. While many operations can be performed in parallel, in some cases, a failure may be indicated by an error message. If this happens, wait until the current operation succeeds before trying again.
When you call deleteRegions() and you get a retryable error, then there was probably an internet connectivity issue: in this case, DownloadRegionsStatusListener fires an onPause() event - and the affected download is in a paused state. If any download is in a paused state, it is not possible to delete a region, because the storage might be in an inconsistent state: to solve this issue, unpause the download or cancel it - then try again.
For more information, take a look at the "OfflineMaps" example app on GitHub.
Updated 10 hours ago