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 aCatalogConfigurationisnull, 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:
SDKNativeEngine sdkNativeEngine = SDKNativeEngine.getSharedInstance();
if (sdkNativeEngine != null) {
// Create MapUpdater in background to not block the UI thread.
MapUpdater.fromEngineAsync(sdkNativeEngine, mapUpdater -> {
// mapUpdater created.
});
}
else {
Log.e("Error: ", "SDKNativeEngine not initialized.");
}
sdkNativeEngine?.let { engine ->
// Create MapUpdater in background to not block the UI thread.
MapUpdater.fromEngineAsync(engine) { mapUpdater ->
// mapUpdater created.
}
} ?: run {
Log.e("Error:", "SDKNativeEngine not initialized.")
}
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:
SDKNativeEngine sdkNativeEngine = SDKNativeEngine.getSharedInstance();
if (sdkNativeEngine != null) {
// Create MapUpdater in background to not block the UI thread.
MapUpdater.fromEngineAsync(sdkNativeEngine, mapUpdater -> {
try {
MapVersionHandle mapVersionHandle = mapUpdater.getCurrentMapVersion();
String versionInfo = mapVersionHandle.stringRepresentation(",");
Log.d("Info: ", "Current Map Version: " + versionInfo);
} catch (MapLoaderException e) {
Log.e("Map Error: ", "Get current map version failed: " + e.error.name());
}
});
}
else {
Log.e("Error: ", "SDKNativeEngine not initialized.");
}
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 void checkForMapUpdates() {
if (mapUpdater == null) {
String message = "MapUpdater instance not ready. Try again.";
snackbar.setText(message).show();
return;
}
mapUpdater.retrieveCatalogsUpdateInfo(new CatalogsUpdateInfoCallback() {
@Override
public void apply(@Nullable MapLoaderError mapLoaderError, @Nullable List<CatalogUpdateInfo> catalogList) {
if (mapLoaderError != null) {
Log.e("CatalogUpdateCheck", "Error: " + mapLoaderError.name());
return;
}
// When error is null, then the list is guaranteed to be not null.
if (catalogList.isEmpty()) {
Log.d("CatalogUpdateCheck", "No map updates are available.");
}
logCurrentSDKVersion();
logCurrentMapVersion();
// Usually, only one global catalog is available that contains regions for the whole world.
// For some regions like Japan only a base map is available, by default.
// If your company has an agreement with HERE to use a detailed Japan map, then in this case you
// can install and use a second catalog that references the detailed Japan map data.
// All map data is part of downloadable regions. A catalog contains references to the
// available regions. The map data for a region may differ based on the catalog that is used
// or on the version that is downloaded and installed.
for (CatalogUpdateInfo catalogUpdateInfo : catalogList) {
Log.d("CatalogUpdateCheck", "Catalog name:" + catalogUpdateInfo.installedCatalog.catalogIdentifier.hrn);
Log.d("CatalogUpdateCheck", "Installed map version:" + catalogUpdateInfo.installedCatalog.catalogIdentifier.version);
Log.d("CatalogUpdateCheck", "Latest available map version:" + catalogUpdateInfo.latestVersion);
performMapUpdate(catalogUpdateInfo);
}
}
});
}
private fun checkForMapUpdates() {
if (!this::mapUpdater.isInitialized) {
val message = "MapUpdater instance not ready. Try again."
snackbar.show(message)
return
}
mapUpdater.retrieveCatalogsUpdateInfo(object : CatalogsUpdateInfoCallback {
override fun apply(
error: MapLoaderError?,
catalogs: List<CatalogUpdateInfo>?
) {
if (error != null) {
Log.e("CatalogUpdateCheck", "Error: " + error.name)
return
}
// When error is null, then the list is guaranteed to be not null.
if (catalogs!!.isEmpty()) {
Log.d("CatalogUpdateCheck", "No map updates are available.")
}
logCurrentMapVersion()
// Usually, only one global catalog is available that contains regions for the whole world.
// For some regions like Japan only a base map is available, by default.
// If your company has an agreement with HERE to use a detailed Japan map, then in this case you
// can install and use a second catalog that references the detailed Japan map data.
// All map data is part of downloadable regions. A catalog contains references to the
// available regions. The map data for a region may differ based on the catalog that is used
// or on the version that is downloaded and installed.
for (catalogUpdateInfo in catalogs) {
Log.d(
"CatalogUpdateCheck",
"Catalog name:" + catalogUpdateInfo.installedCatalog.catalogIdentifier.hrn
)
Log.d(
"CatalogUpdateCheck",
"Installed map version:" + catalogUpdateInfo.installedCatalog.catalogIdentifier.version
)
Log.d(
"CatalogUpdateCheck",
"Latest available map version:" + catalogUpdateInfo.latestVersion
)
performMapUpdate(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 void performMapUpdate(CatalogUpdateInfo catalogUpdateInfo) {
if (mapUpdater == null) {
String message = "MapUpdater instance not ready. Try again.";
snackbar.setText(message).show();
return;
}
// This method conveniently updates all installed regions for a catalog if an update is available.
// Optionally, you can use the CatalogUpdateTask to pause / resume or cancel the update.
CatalogUpdateTask task = mapUpdater.updateCatalog(catalogUpdateInfo, new CatalogUpdateProgressListener() {
@Override
public void onProgress(@NonNull RegionId regionId, int percentage) {
Log.d("CatalogUpdate", "Downloading and installing a map update. Progress for " + regionId.id + ": " + percentage);
}
@Override
public void onPause(@Nullable MapLoaderError mapLoaderError) {
if (mapLoaderError == null) {
String message = "The map update was paused by the user calling catalogUpdateTask.pause().";
Log.e("CatalogUpdate", message);
} else {
String message = "Map update onPause error. The task tried to often to retry the update: " + mapLoaderError;
Log.d("CatalogUpdate", message);
}
}
@Override
public void onResume() {
String message = "A previously paused map update has been resumed.";
Log.d("CatalogUpdate", message);
}
@Override
public void onComplete(@Nullable MapLoaderError mapLoaderError) {
if (mapLoaderError != null) {
String message = "Map update completion error: " + mapLoaderError;
Log.d("CatalogUpdate", message);
return;
}
String message = "One or more map update has been successfully installed.";
Log.d("CatalogUpdate", message);
logCurrentMapVersion();
// 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.
}});
}
// Downloads and installs map updates for any of the already downloaded regions.
// Note that this example only shows how to download one region.
private fun performMapUpdate(catalogUpdateInfo: CatalogUpdateInfo) {
if (!this::mapUpdater.isInitialized) {
val message = "MapUpdater instance not ready. Try again."
snackbar.show(message)
return
}
// This method conveniently updates all installed regions for a catalog if an update is available.
// Optionally, you can use the CatalogUpdateTask to pause / resume or cancel the update.
val task =
mapUpdater.updateCatalog(catalogUpdateInfo, object : CatalogUpdateProgressListener {
override fun onProgress(regionId: RegionId, percentage: Int) {
Log.d(
"CatalogUpdate",
"Downloading and installing a map update. Progress for " + regionId.id + ": " + percentage
)
}
override fun onPause(mapLoaderError: MapLoaderError?) {
if (mapLoaderError == null) {
val message =
"The map update was paused by the user calling catalogUpdateTask.pause()."
Log.e("CatalogUpdate", message)
} else {
val message =
"Map update onPause error. The task tried to often to retry the update: $mapLoaderError"
Log.d("CatalogUpdate", message)
}
}
override fun onResume() {
val message = "A previously paused map update has been resumed."
Log.d("CatalogUpdate", message)
}
override fun onComplete(mapLoaderError: MapLoaderError?) {
if (mapLoaderError != null) {
val message = "Map update completion error: $mapLoaderError"
Log.d("CatalogUpdate", message)
return
}
val message = "One or more map update has been successfully installed."
Log.d("CatalogUpdate", message)
logCurrentMapVersion()
// 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.
}
})
}
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], available in both Java and Kotlin.
Updated yesterday