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

バックグラウンド更新を有効にする

ポジショニングはNavigateライセンスでのみ使用できます。

AndroidでアプリケーションUIが表示されていない状態でも位置情報の更新を受信し続けるには、フォアグラウンドサービスを実装する必要があります。このアプローチでは、アプリがバックグラウンドでHERE Positioningをアクティブに使用していることをユーザーに通知します。

  • 権限: ACCESS_FINE_LOCATIONをリクエストし、その権限が付与されていることを確認します。ACCESS_BACKGROUND_LOCATION位置情報の更新にフォアグラウンドサービスを使用する場合、権限は必要ありません
  • Android 14以降の要件: Android 14 (APIレベル34) 以降を対象とするアプリの場合は、実行時にFOREGROUND_SERVICE_LOCATION権限を宣言し、リクエストする必要があります。
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
  • フォアグラウンドサービスの宣言: Android 12 (APIレベル31) 以降を対象とするアプリの場合、AndroidManifest.xmlでサービスを宣言し、foregroundServiceTypeを指定する必要があります。
<service
    android:name=".ForegroundService"
    android:foregroundServiceType="location" >
    ...
</service>

UIが表示されていないときにアプリが位置情報の更新を引き続き受信するには、フォアグラウンドサービスを開始する必要があります。HERE Positioningのフォアグラウンドサービスの使用は、バックグラウンドでの位置情報権限リクエストとは異なることに注意してください。詳細については、「Androidのドキュメント」と「フォアグラウンドサービスのドキュメント」を参照してください。Positioningのサンプルアプリは、すべてのサポートされているAndroidバージョンでのフォアグラウンドサービスの使用を完全に表しているわけではありません。

アプリケーションがAndroid APIレベル28以下を対象にしている場合、アプリが「権限を追加する」セクションで説明した権限をすでにリクエストしている限り、バックグラウンド更新のサポートのために変更を加える必要はありません。

アプリがフォアグラウンドで実行されておらず、アクティブにフォアグラウンドサービスを使用していない場合でも、デバイスの位置情報にアクセスする必要がある場合 (アプリを閉じたときに位置情報の変更に基づいてアクションをトリガーするジオフェンシングのような機能など) は、ACCESS_BACKGROUND_LOCATION権限をリクエストする必要があります。この権限はフォアグラウンド以外でのアクセスも許可します。

  • 必要なケース: この権限が必要になるのは、ユーザーがアプリの使用をやめた後に、アプリが位置情報へのアクセスを必要とし、かつフォアグラウンドサービスを使用して位置情報を使用中であることを通知していない場合のみです。一般的なユースケースとしては、ジオフェンシングや、ユーザーとの継続的なやり取りなしに位置情報を受動的に収集することなどが挙げられます。
  • マニフェストの宣言: 次の権限をアプリのAndroidManifest.xmlファイルに追加します。これはAndroid 10 (APIレベル29) 以降を対象とするアプリで必須です。
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
  • ランタイムリクエスト: バックグラウンドでの位置情報のリクエストは、複数のステップからなるプロセスです。
    1. まず、フォアグラウンドでの位置情報権限 (ACCESS_FINE_LOCATION) をリクエストします。
    2. フォアグラウンドでの権限が付与された後でのみ、別途ACCESS_BACKGROUND_LOCATIONをリクエストできます。多くの場合、このレベルのアクセス権がアプリにとって必要な理由を説明するために、追加のUIの表示が必要となります。
  • 制限とポリシー:
    • ACCESS_BACKGROUND_LOCATIONの付与には、個別の権限ダイアログによる明示的なユーザー承認が必要です。ユーザーはバックグラウンドでのアクセスがリクエストされた場合でも、フォアグラウンドでのアクセスのみを許可することを選択できます。
    • この権限をリクエストするアプリは、Google Playストアでより厳格な審査を受けます。バックグラウンドでの位置情報アクセスの必要性について、許可されているユースケースに沿った明確で十分な根拠を示す必要があります。根拠を説明できなかった場合、アプリの拒否または削除につながる可能性があります。

バックグラウンドでの位置情報権限のリクエストは、位置情報の更新にフォアグラウンドサービスを使用する場合とは大きく異なります。アプリUIが表示されていないときに位置情報を必要とするほとんどのユースケースでは、代わりにフォアグラウンドサービスを使用してください。詳細な実装ガイダンスとポリシー要件については、「バックグラウンドでの位置情報アクセスに関するAndroidのドキュメント」を参照してください。

アプリケーションが SDK バージョン 28 以下を対象にしている場合、アプリが前述の「権限を追加する」セクションで説明した権限をすでにリクエストしていれば、バックグラウンド更新のサポートのために変更を加える必要はありません。

アプリケーションが SDK バージョン 33 以降を対象にしており、フォアグラウンド サービスを使用する場合、アプリは POST_NOTIFICATIONS 権限をリクエストする必要があります。

バックグラウンドでの位置情報の更新を示す完全なワークフローは、GitHub にある PositioningWithBackgroundUpdates サンプル アプリで確認できます。

以下では、このアプリを作成する方法と、バックグラウンド実行中にフォアグラウンド サービスを使用して位置情報の更新を取得する方法について説明します。フォアグラウンド サービスは Android の通知メカニズムを使用して、バックグラウンド アクティビティについてユーザーに通知します。また、ユーザーはサービスを操作できます。

ステップ 1:Service のサブクラスを作成する

Service クラスを継承し、必要なメソッドを上書きします。このチュートリアルでは、クラス ForegroundService を呼び出しました。このクラスの完全な実装は GitHub を参照してください。

public class ForegroundService extends Service {
    private static final String CHANNEL_ID = "ForegroundServiceChannel";

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        String input = intent.getStringExtra("inputExtra");
        createNotificationChannel();
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,
                0, notificationIntent, 0);

        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle("Foreground Service")
                .setContentText(input)
                .setSmallIcon(R.drawable.ic_stat_name)
                .setContentIntent(pendingIntent)
                .build();

        startForeground(1, notification);

        // Here is a good place to confirm HERE legitimate interest privacy notice inclusion.
        // You can already start the LocationEngine here.

        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        // Here is a good place to stop the LocationEngine.
        super.onDestroy();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        // Here we do not use a binder to interact with the foreground service.
        return null;
    }
}

ステップ2:通知チャネルを作成する

通知チャネルを作成するには、次のコードを ForegroundService クラスに追加します。

private void createNotificationChannel() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel serviceChannel = new NotificationChannel(
                CHANNEL_ID,
                "Foreground Service Channel",
                NotificationManager.IMPORTANCE_DEFAULT
        );

        NotificationManager manager = getSystemService(NotificationManager.class);
        manager.createNotificationChannel(serviceChannel);
    }
}

ステップ3:位置情報の処理を挿入する

GitHubまたは「現在地を検索する」セクションに示されているように、HEREプライバシー通知が含まれているかを確認するには、confirmHEREPrivacyNoticeInclusion()メソッドを挿入する必要があります。バックグラウンド更新を有効にしない場合でも、この部分は常に必要です。

また、位置情報の更新を受信するための startLocating() や、アプリが破棄されたときの stopLocating() などのメソッドを必ず実装する必要があります。バックグラウンド更新を有効にしない場合でも、これらのメソッドは常に必要です。コードは GitHub または「現在地を検索する」セクションを参照してください。

同様に、位置の更新を処理するには LocationListener を実装する必要があります。これには、バックグラウンド以外の更新と同じコードを使用できます。

ステップ 4:アクティビティからフォアグラウンド サービスを開始する

バックグラウンド更新の取得を有効にするには、startService() を呼び出します。このサービスは、専用ボタンなどを使用して stopService() を呼び出すことで停止できます。次の 2 つのメソッドを Activity に追加できます。

public void startService() {
    Intent serviceIntent = new Intent(this, ForegroundService.class);
    serviceIntent.putExtra("inputExtra", "Foreground Service Example in Android");
    ContextCompat.startForegroundService(this, serviceIntent);
}

public void stopService() {
    Intent serviceIntent = new Intent(this, ForegroundService.class);
    stopService(serviceIntent);
}

ステップ 5:サービスを宣言し、権限を追加する

AndroidManifest で、Service クラスの名前とフォアグラウンド サービスの型を追加する必要があります。

また、ACCESS_BACKGROUND_LOCATION 権限を追加することによって、バックグラウンド更新の許可をユーザーに明示的に求める必要があります。さらに、FOREGROUND_SERVICE および POST_NOTIFICATIONS 権限が必要です。

Android 14 以降を対象とする場合

Android 14 (API レベル 34) 以降では、フォアグラウンド サービスごとに適切なサービス タイプを宣言する必要があります。つまり、アプリのマニフェストで ForegroundServicelocation サービス タイプを宣言し、FOREGROUND_SERVICE_LOCATION 権限もリクエストする必要があります。フォアグラウンド サービスのタイプについて詳しくは、Android の開発者向けドキュメントを参照してください。

以下に、HERE Positioning に必要な他のすべての権限とともに例を示します。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.foregroundservice">

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <service
            android:name=".ForegroundService"
            android:enabled="true"
            android:exported="true"
            android:foregroundServiceType="location" />

        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

これで、アプリはバックグラウンドで完全に動作し、デバイスがロックされている場合でも位置情報イベントを受信できるようになりました。バックグラウンドでの位置情報の更新処理は秘密事項である場合があるため、この機能が必要な理由をユーザーに必ず伝えてください。また、Android OS はアプリが実行中かつアクティブであることをロック画面でユーザーに通知することに注意してください。不要なときのバッテリー消耗を避けるために、位置情報の更新頻度を低くすることを検討してください。たとえば、HUNDREDS_OF_METERS などの頻度の低い LocationAccuracy を設定します。


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