ガイド変更履歴HERE SDK API references
ガイド

マップ データを更新する

オフラインマップはNavigateライセンスでのみ使用できます。

MapUpdaterクラスを使用すると、新しいマップバージョンが利用できるかを確認でき、利用できる場合は、すでにインストールされている地域を更新できます。HERE SDK の各バージョンには、特定のマップ バージョンがハードコードされています。これにより、キャッシュ内のマップ データとダウンロードされた地域 (存在する場合) が定義されます。

関連する「API リファレンス」ドキュメントまたはこのガイドに記載されているように、一部の HERE SDK 機能には特定の地図のバージョンが必要になる場合があります。

地図の差分更新は、デフォルトでサポートされています。地域全体をダウンロードするのではなく、変更された部分のみがインストールされます。これにより、更新プロセスが高速化され、ダウンロードされるデータが減少します。CatalogConfigurationpatchHrn フィールドが nil の場合、差分更新は無効になり、マップ データはある程度まで増分的にダウンロードされますが、バンドルが大きくなるため、帯域幅の消費量が増加します。通常、これは HERE SDK によって内部的に処理されるため、開発者が独自に CatalogConfiguration を作成する必要はありません。

通常、地図更新は毎週提供されています。初めて使用する場合、ユーザーはリージョン全体をダウンロードする必要があります。初回ダウンロード後の更新では、差分更新を実行できます。全体のダウンロードを実行するか差分更新のみを実行するかは、HERE SDK によって自動的に決定されます。

マップの増分更新 (「パッチ適用」とも呼ばれます) を行うと、約8つのOCMマップバージョンでダウンロードのサイズが小さくなります。たとえば、OCMバージョンx.y.7の新しいマップバージョンをインストールした場合、x.y.15までは増分更新のメリットがあります。OCMバージョンx.y.16以降では、バージョンがスキップされた場合でも、再び多くのマップデータが必要になります。
OCMマップが毎週更新される場合、約8週間後には、mapUpdater.updateCatalog(...)の実行時にMapUpdaterによってさらに多くのデータがダウンロードされます。更新を実行する前に、CatalogUpdateInfoによって更新されるマップデータの量に関する情報が提供されます。

MapUpdater を使用する

新しい HERE SDK バージョンを統合するアプリの更新がインストールされると、ほとんどの場合、新しいマップ バージョンも統合されます。ただし、MapUpdater を使用してこのタスクを実行しない限り、インストール済みの地域は自動的に更新されません。もちろん、古い HERE SDK バージョンの地図更新もインストールできます。

  • mapUpdater.getCurrentMapVersion() を呼び出して、現在使用されている地図のバージョンを確認します。
  • mapUpdater.retrieveCatalogsUpdateInfo() を呼び出して、更新が利用できるかを確認します。

このクラスは、UI スレッドをブロックしないように、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 ...
})

現在のマップ バージョンを取得する

マップ キャッシュに使用されるマップ バージョンとインストールされている Region データを知っておくと役に立つ場合があります。以下のコード スニペットを使用すると、現在使用されているマップ バージョンを記録できます。

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)")
    }
})

バージョン情報は主にデバッグ目的に役立ちます。マップ バージョンは、マップ ビューが初めて表示されたときにも HERE SDK によって記録されます。

形式は [cache-version].[offline-maps-version],[japan-cache-version].[japan-offline-maps-version] です。結果の例は、「47.47,47.47」のようになります。マップ キャッシュとオフライン マップで異なるバージョンを取得することはできません。

地図の更新を確認する

アプリの起動時に、地図に更新があるかを確認できます。ただし、地域データがインストールされている場合は、作業に時間がかかる可能性があるため、ユーザーに通知します。通常、最初にretrieveCatalogsUpdateInfo() を呼び出して更新を確認します。これにより、updateCatalog() の呼び出しに使用できる 1 つ以上の CatalogUpdateInfo 項目が提供されます。

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);
    }
}

マップ データとマップ バージョンを更新する

次のステップとして、地図の更新を実行するコードを実装します。これにより、マップ バージョンも上がります。

// 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.")
    }
}

updateCatalog() の呼び出しは、実際に変更された Region の部分のみを更新するように内部的に最適化されています。つまり、ほとんどの場合、更新ではユーザーがすべてのパッケージを再ダウンロードする必要はなく、各地域がいくつかの内部バンドルに分割され、その中でマップ データに変更があった場合にのみ再ダウンロードされます。この手順は地図の差分更新とも呼ばれます。

  • オフライン マップがインストールされていない場合、mapUpdater.updateCatalog() を呼び出してもキャッシュがクリアされるだけで、その後、キャッシュには利用できる最新の地図バージョンの新しいデータが書き込まれます。
  • キャッシュは常にオフライン マップと同じマップ バージョンを使用します。オフライン マップが更新されると、キャッシュも更新されます。キャッシュのバージョンがオフライン マップのバージョンより古くなることはありません。

deleteRegions() 経由でダウンロードしたすべての地域をアンインストールし、必要な地域を再度ダウンロードすることで地図更新を強制することはできません。その場合、同じマップ バージョンがダウンロードされます。ただし、updateCatalog() を事前に実行すると、地図の更新が表示され、インストールできる場合があります。

地図を更新するときは、次の点を確認してください。

  • mapUpdater.updateCatalog() が完了したら、getDownloadableRegions() を呼び出して、既存の Region データのダウンロード、更新、削除に必要な内部カタログ データを更新する必要があります。
  • 地図の更新と関連する操作が進行している間は、一部の MapDownloaderMapUpdater の機能にアクセスできない場合があります。多くの操作は並行して実行できますが、場合によっては、実行できず、エラー メッセージが表示されることがあります。そのような場合、現在の操作が成功するまで待ってから再試行してください。

deleteRegions() を呼び出して再試行可能なエラーが発生した場合は、インターネット接続に問題があった可能性があります。この場合、DownloadRegionsStatusListeneronPause() イベントを起動し、影響を受けたダウンロードは一時停止状態になります。ダウンロードが一時停止状態にある場合、ストレージが不整合な状態にある可能性があるため、地域を削除できません。この問題を解決するには、ダウンロードの一時停止を解除するか、キャンセルしてから、もう一度試してください。

詳細については、GitHubの「OfflineMaps」サンプルアプリを参照してください。


EN 日本語

HERE documentation

Find answers to your product and technical questions

Documentation

What's new

Videos

EN 日本語

HERE ドキュメント

製品や技術に関する質問の答えを見つけましょう。より多くの内容と最新の情報については、英語版をご覧ください。

ドキュメント

ダイナミックマップ

動的コンテンツ関連のAPIをアプリやサービスに活用して、ドライバーが安全・快適かつ予定どおりに目的地へ到着できるよう支援します。

地図とデータ

世界中を走行する多数のマッピング車両から得られる最新の位置情報データを活用し、精度の高い地図やカスタムレイヤーを構築できます。

最新情報

動画

(function () { const input = document.querySelector('input[data-typeahead]'); if (!input) return; // Prevent the form from submitting/navigating input.closest('form')?.addEventListener('submit', e => e.preventDefault()); input.addEventListener('input', function () { const q = this.value.trim().toLowerCase(); document.querySelectorAll('.nav-group-name').forEach(group => { let anyVisible = false; group.querySelectorAll('.nav-group-task').forEach(task => { const text = task.textContent.trim().toLowerCase(); const show = !q || text.includes(q); task.style.display = show ? '' : 'none'; if (show) anyVisible = true; }); // Hide the whole group header if nothing matches group.style.display = anyVisible || !q ? '' : 'none'; }); }); })(); (function () { function onTokenClick(event) { var link = event.target.closest('.sdk-for-ios .item .token'); if (!link) return; event.preventDefault(); console.log('token clicked', link.textContent.trim()); var item = link.closest('.item'); if (!item) return; var content = item.querySelector('.height-container'); if (!content) { console.log('no .height-container found for item', item); return; } var isHidden = window.getComputedStyle(content).display === 'none'; content.style.display = isHidden ? 'block' : 'none'; link.classList.toggle('token-open', isHidden); var href = link.getAttribute('href'); if (href) { if (history.pushState) history.pushState({}, '', href); else location.hash = href; } } function openHashTarget() { var hash = window.location.hash.slice(1); if (!hash) return; var anchor = document.querySelector('.sdk-for-ios a[name="' + hash + '"]'); if (!anchor) return; var item = anchor.closest('.item'); if (!item) return; var link = item.querySelector('.token'); var content = item.querySelector('.height-container'); if (!link || !content) return; content.style.display = 'block'; link.classList.add('token-open'); } function init() { console.log('HERE SDK accordion init'); openHashTarget(); } document.removeEventListener('click', onTokenClick); document.addEventListener('click', onTokenClick); if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } window.addEventListener('hashchange', openHashTarget); window.addEventListener('pageLoad', init); })();