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

ポジショニングの使用を開始する

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

地図検索アプリケーションを使用する主な理由の1つは、現在地を確認するためです。

HERE SDK が提供する LocationEngine は、包括的な位置情報ソリューションを実装し、GPS やその他の全地球衛星測位システム (GNSS) レシーバー、モバイル ネットワーク信号、Wi-Fi ネットワーク信号などの複数の位置情報ソースと連携して正確な位置を特定します。

HERE SDK の位置情報機能を統合するには、少なくとも次の手順を実行する必要があります。

  1. 必要な Android 権限をマニフェスト ファイルに追加し、ユーザーに権限をリクエストします。
  2. LocationEngineを作成し、1つ以上のLocationListenerを設定します。
  3. アプリを初めて起動する場合、アプリが周辺のモバイルおよびWi-Fiネットワーク信号の特性を収集することをユーザーに通知します。関連するHEREプライバシー通知へのリンクを提供します。これをアプリケーションのプライバシーポリシーに組み込む方法の例は、このサンプルアプリ (Java版およびKotlin版) で利用できます。アプリが子供のみを対象にしている場合は、以下の「HEREプライバシー通知の処理を確認する」セクションの注意事項をご参照ください。
  4. confirmHEREPrivacyNoticeInclusion()メソッドを呼び出して、前の手順が完了したことを確認します。
  5. LocationEngine を一度起動し、希望する精度レベルを設定します。
  6. Locationの更新を受信し、アプリで処理します。

Network Positioningは、ネットワークポジショニングAPI v2に基づいています。Network Positioningに基づくトランザクションの例:LocationEngineで携帯電話のWi-Fiポジショニングを使用して位置情報の更新を取得します。

これらの機能の価格については、「HERE基本プランの価格表」を参照してください。Navigateライセンスを使用している場合、または価格についてご質問がある場合は、お問い合わせください。

権限を追加する

アプリで LocationEngine の使用を開始する前に、アプリの AndroidManifest.xml ファイルに次のように必要な権限を追加する必要があります。

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

アプリケーションが Android SDK バージョン 31 以上を対象としている場合、アプリケーションのユーザーはデバイスの「正確」な位置権限を付与する必要があります。プロンプトが表示されたら、「おおよそ」の精度を選択するだけでは十分ではありません。
したがって、上に示したように、ACCESS_COARSE_LOCATION および ACCESS_FINE_LOCATION 権限がマニフェスト ファイルに存在している必要があります。
HERE Positioning では、GNSS を使用するため、またモバイルおよび WiFi ネットワークのスキャンを行うために詳細な位置情報の許可が必要です。ACCESS_COARSE_LOCATION権限だけでは、おおよその精度となるため、HERE Positioningが機能するには十分ではありません。この場合、LocationEngineMISSING_PERMISSIONS エラーで失敗します。

WAKE_LOCK 権限は HERE SDK において強制ではありません。ただし、この権限がアプリケーションに付与されている場合は、HERE SDK はウェイク ロックを使用して、デバイスが省電力モードに移行してもネットワーク スキャンと位置計算が中断されないようにします。バッテリー消費への影響を可能な限り抑えるために、ウェイク ロックは必要最小限の時間のみ保持されます。ここで注意しなくてはならないのは、Androidオペレーティングシステムではウェイクロックを継続的に維持するアプリケーションやサービスがバッテリー消費の原因となっていることです。そのため、ユーザーのアプリケーションのエクスペリエンスを損なわないように、ウェイクロックがユースケースに必須かどうかを慎重に検討してください。

このユーザーガイドに付属するすべてのサンプルアプリではJava版が提供される、PermissionsRequestorという名前の便利なクラスを使用して、ユーザーの許可をリクエストする手間のかかるタスクを処理します。

すべてのデバイスが同じ性能を有しているわけではなく、特定のハードウェアの制約により、ポジショニングの精度が異なる場合があります。

LocationEngineを使用する前に、デバイスの位置情報機能が有効になっているかどうかを確認することをお勧めします。ほとんどのAndroidデバイスで、ユーザーはデバイスの[Settings](設定) を開いて、[Security & Location](セキュリティと位置情報) セクションから、位置情報サービスをオンにしたり、さらにはその精度を高めたりできます。

LocationEngine を初期化する

新しい LocationEngine の作成は簡単です。

try {
    locationEngine = new LocationEngine();
} catch (InstantiationErrorException e) {
    throw new RuntimeException("Initialization of LocationEngine failed: " + e.getMessage());
}
try {
    locationEngine = LocationEngine()
} catch (e: InstantiationErrorException) {
    throw RuntimeException("Initialization failed: " + e.message)
}

ApplicationonCreate() ライフサイクル中には LocationEngine を初期化できませんそれ以外の時点であれば問題ありません。エンジンを初期化するのに適した場所は、ActivityonCreate() メソッド内などです。

HEREプライバシー通知の処理を確認する

LocationEngineはHERE SDKで使用されるHERE Positioningサービスを維持、改善、提供するために、モバイル機器周辺のモバイルおよびWi-Fiネットワーク信号の特性に関する情報を必要に応じて収集します。たとえば、これには近くの信号の強度などが含まれます。HEREは位置情報サービスの維持、改善、提供のためにこの情報を収集する正当利害関係を有しています。収集された情報からはユーザーを特定せず、HEREは匿名化された情報のみを保持します。詳細については、「HEREプライバシー通知」をご覧ください。

デフォルトで、近くのモバイルおよびWi-Fiネットワーク信号の特性情報の収集が、アプリケーションの利用規約またはプライバシーポリシーに記載されていること、またはHEREプライバシー通知にユーザーがアクセスできることの確認として、アプリはLocationEngine.confirmHEREPrivacyNoticeInclusion()を呼び出す必要があります。詳細およびテキストスニペットの例は、次の「法的要件」セクションを参照してください。

アプリが子供のみをターゲットにしている場合など、HEREが事前に承認している特殊なケースの場合、アプリはLocationEngine.confirmHEREPrivacyNoticeException()を呼び出して、HEREによって例外的な権限が付与されていることを確認する必要があります。その結果、データ収集はされず、HEREプライバシー通知への参照は必要ありません。ご自身のユースケースでデータ収集を無効にする必要があると思われる場合は、HEREにお問い合わせください。

LocationEngineは上記のいずれかのメソッドを呼び出した後で、完全に機能するようになります。

LocationEngineを開始する前に、LocationEngine.confirmHEREPrivacyNoticeInclusion() (または上記の注のとおりHEREが例外を許可している場合はLocationEngine.confirmHEREPrivacyNoticeException()) を呼び出すことによって、HEREプライバシー通知にユーザーがアクセスできることを確認する必要があります。

locationEngine.confirmHEREPrivacyNoticeInclusion();
locationEngine.confirmHEREPrivacyNoticeInclusion()

事前にLocationEngine.confirmHEREPrivacyNoticeInclusion()またはLocationEngine.confirmHEREPrivacyNoticeException()を呼び出すことなく、LocationEnginestart()メソッドを呼び出している場合、エンジンは位置情報の更新を提供しません。LocationEngine.confirmHEREPrivacyNoticeException()を呼び出すと、HERE SDK資格情報を使用して、例外の権限が非同期的に検証されます。権限がない場合、LocationEngineは停止し、登録されたLocationStatusListenerLocationEngineStatus.PRIVACY_NOTICE_UNCONFIRMEDステータスが通知されます。

位置情報を受信する

エンジンが初期化されると、エンジンが以前に少なくとも 1 回起動され、少なくとも 1 つの位置を受信している限り、最後の既知の位置を取得できます。それ以外の場合は、null が返されます。この情報は残るため、アプリケーション セッション間でも最後の既知の位置が利用できます。

Location myLastLocation = locationEngine.getLastKnownLocation();

if (myLastLocation != null) {
    // Log the last known location coordinates.
    Log.d(TAG, "Last known location: " + myLastLocation.coordinates.latitude + ", " + myLastLocation.coordinates.longitude);
}

最後の既知の位置情報を取得するには、LocationEngine を開始する必要も、リスナーを設定する必要もありません。Location オブジェクトにはその位置情報をいつ受信したかを示す timestamp が含まれています。

次に、LocationEngineを開始する前に、エンジンのステータスが変更されたときに通知を受け取れるようにLocationStatusListenerを登録することをお勧めします。これを行うには、LocationStatusListener インターフェースを実装し、それを位置情報エンジンの addLocationStatusListener() メソッドで登録します。さまざまなステータスの詳細については、「API リファレンス」を参照してください。

private final LocationStatusListener locationStatusListener = new LocationStatusListener() {
    @Override
    public void onStatusChanged(@NonNull LocationEngineStatus locationEngineStatus) {
        Log.d(TAG, "LocationEngineStatus: " + locationEngineStatus.name());
    }

    @Override
    public void onFeaturesNotAvailable(@NonNull List<LocationFeature> features) {
        for (LocationFeature feature : features) {
            Log.d(TAG, "Feature not available: " + feature.name());
        }
    }
};

// ...

// Add the listener.
locationEngine.addLocationStatusListener(locationStatusListener);

さらに、リスナーの onFeaturesNotAvailable() コールバックを通じて、利用できない LocationFeature が通知されます。必要な機能が利用できない場合は、HERE 担当者にお問い合わせください

エンジンを開始する前最後の考慮事項は、onLocationUpdated() コールバックを提供して新しい Location が検知されると通知を送る、LocationListener を登録することです。これは、次のように、前述の LocationStatusListener と同様の方法で行うことができます。

private final LocationListener locationListener = new LocationListener() {
    @Override
    public void onLocationUpdated(@NonNull Location location) {
        Log.d(TAG, "Received location: " + location.coordinates.latitude + ", " + location.coordinates.longitude);
    }
};

// ...

// Add the listener.
locationEngine.addLocationListener(locationListener);

他のすべてのコールバックと同様に、コールバック onLocationUpdated() はメイン スレッドで受け取ります。

Location インスタンスには現在の地理座標とは別に、現在の高度、方位、速度、精度など、より多くの有用な情報が含まれる可能性があります。詳細については、以下の「位置情報の精度に対応する」セクションを参照してください。

LocationStatusListenerLocationListener は、それぞれに対応する addLocationStatusListener() メソッドと addLocationListener() メソッドを呼び出すことで必要な数を追加できます。

ポジショニングの問題の詳細については、LocationIssueListener インターフェースを実装し、位置エンジンの addLocationIssueListener() メソッドで登録してください。このインターフェースを介して、位置情報エンジンが実行されているときに、エラーの原因を説明するイベントが配信されます。さまざまな問題の詳細については、「API リファレンス」を参照してください。

これで LocationEnginestart() メソッドを呼び出す準備ができました。

try {
    locationEngine = new LocationEngine();
} catch (InstantiationErrorException e) {
    throw new RuntimeException("Initialization failed: " + e.getMessage());
}

// ...

startLocating();

// ...

private void startLocating() {
    locationEngine.addLocationStatusListener(locationStatusListener);
    locationEngine.addLocationListener(locationListener);
    locationEngine.start(LocationAccuracy.BEST_AVAILABLE);
}
try {
    locationEngine = LocationEngine()
} catch (e: InstantiationErrorException) {
    throw RuntimeException("Initialization failed: " + e.message)
}

// ...

startLocating()

// ...

private fun startLocating() {
    locationEngine.addLocationStatusListener(locationStatusListener)
    locationEngine.addLocationListener(locationListener)
    locationEngine.start(LocationAccuracy.BEST_AVAILABLE)
}

エンジンを開始する最も簡単な方法は、上のコード スニペットのように、事前定義された LocationAccuracy モードの 1 つをエンジンに渡すことです。利用可能なすべてのモードの詳細については、下の表を参照するか、「API リファレンス」を参照してください。

正常に起動すると、LocationStatusListener は常に LocationEngineStatus.ENGINE_STARTEDステータスを受け取り、正常に停止すると、常に LocationEngineStatus.ENGINE_STOPPEDステータスを受け取ります。

LocationEngine が開始された後、最初に stop() を呼び出さずに再度開始しようとすると、LocationEngineStatus.ALREADY_STARTED が返されます。isStarted() メソッドを使用して、エンジンが開始しているかどうかを確認できます。同様に、LocationEngine を起動して、停止せずに別のエンジンを起動しようとすると、LocationEngineStatus.ALREADY_STARTED エラーを取得します。同時に始動できるエンジンは 1 つのみです。

これ以上位置情報の更新を受信する必要がない場合は、stop() メソッドを呼び出してエンジンを停止できます。リスナーが不要になったら、忘れずに削除してください。

public void stopLocating() {
    locationEngine.stop();
}

// ...

locationEngine.removeLocationListener(locationListener);
locationEngine.removeLocationStatusListener(locationStatusListener);

通常、アプリを破棄する場合は、LocationEngine を停止することをお勧めします。

地図に現在地を表示する

LocationIndicator は、デバイスの現在地を地図に表示するために使用します。インジケーターが現在の位置値で更新される前は、デフォルトの Location が設定されます。これは、最後の既知の位置、または最初の位置情報更が届く前にユーザーに表示される任意の場所のどちらかです。デフォルトでは、水平精度は半径 horizontalAccuracyInMetersMapCircle で可視化されます。

//LocationIndicator object to represent current location.
private LocationIndicator locationIndicator;

// ...

private void addMyLocationToMap(@NonNull Location myLocation) {
    //Create and setup location indicator.
    locationIndicator = new LocationIndicator();
    // Enable a halo to indicate the horizontal accuracy.
    locationIndicator.setAccuracyVisualized(true);
    locationIndicator.setLocationIndicatorStyle(LocationIndicator.IndicatorStyle.PEDESTRIAN);
    locationIndicator.updateLocation(myLocation);
    locationIndicator.enable(mapView);
    //Update the map viewport to be centered on the location.
    MapMeasure mapMeasureZoom = new MapMeasure(MapMeasure.Kind.DISTANCE_IN_METERS, CAMERA_DISTANCE_IN_METERS);
    mapView.getCamera().lookAt(myLocation.coordinates, mapMeasureZoom);
}


// ...

private void updateMyLocationOnMap(@NonNull Location myLocation) {
    //Update the location indicator's location.
    locationIndicator.updateLocation(myLocation);
    //Update the map viewport to be centered on the location, preserving zoom level.
    mapView.getCamera().lookAt(myLocation.coordinates);
}

// ...

//Default start-up location.
private final static GeoCoordinates defaultLocation = new GeoCoordinates(52.520798, 13.409408);

final Location myLastLocation = locationEngine.getLastKnownLocation();

if (myLastLocation != null) {
    addMyLocationToMap(myLastLocation);
} else {
    final Location defaultLocation = new Location(defaultCoordinates);
    defaultLocation.time = new Date();
    addMyLocationToMap(defaultLocation);
}

// ...

private final LocationListener locationListener = location -> {
    updateMyLocationOnMap(location);
};
//LocationIndicator object to represent current location.
private var locationIndicator: LocationIndicator

// ...

private fun addMyLocationToMap(myLocation: Location) {
    //Create and setup location indicator.
    locationIndicator = LocationIndicator()
    // Enable a halo to indicate the horizontal accuracy.
    locationIndicator.isAccuracyVisualized = true
    locationIndicator.locationIndicatorStyle = LocationIndicator.IndicatorStyle.PEDESTRIAN
    locationIndicator.updateLocation(myLocation)
    locationIndicator.enable(mapView!!)

    //Update the map viewport to be centered on the location.
    val mapMeasureZoom =
        MapMeasure(MapMeasure.Kind.DISTANCE_IN_METERS, CAMERA_DISTANCE_IN_METERS.toDouble())
    mapView!!.camera.lookAt(myLocation.coordinates, mapMeasureZoom)
}

// ...

private fun updateMyLocationOnMap(myLocation: Location) {
    //Update the location indicator's location.
    locationIndicator.updateLocation(myLocation)
    //Update the map viewport to be centered on the location, preserving zoom level.
    mapView!!.camera.lookAt(myLocation.coordinates)
}

// ...

//Default start-up location.
private val defaultCoordinates = GeoCoordinates(52.520798, 13.409408)

val myLastLocation = locationEngine.lastKnownLocation
if (myLastLocation != null) {
    addMyLocationToMap(myLastLocation)
} else {
    val defaultLocation = Location(defaultCoordinates)
    defaultLocation.time = Date()
    addMyLocationToMap(defaultLocation)
}

// ...

private val locationListener =
    LocationListener { location: Location ->
        updateMyLocationOnMap(location)
    }

上の実装で示したように、updateLocation() を呼び出すことで Location オブジェクトを位置情報インジケーターに渡すことができます。この例では、目的はユーザーの現在地を追跡することです。したがって、マップ ビューポートの中心位置も更新されます。

ポジショニングのサンプルアプリを試す

  • GitHubには、上に示したのコードスニペットのほとんどが含まれたJava版およびKotlin版の「Positioning」サンプルアプリが入手できます。
  • バックグラウンドでの位置情報の更新を示す完全なワークフローは、こちらにある「PositioningWithBackgroundUpdates」サンプルアプリで確認できます。
  • HikingDiary アプリは、GPX トレースを記録する方法を示します。

法的要件

アプリケーション開発者は、近くのモバイルおよびWi-Fiネットワーク信号の特性の収集について、ユーザーに通知する責任があります。また、開発者は関連するHEREプライバシー通知のリンクをユーザーに提示する必要があります。

アプリの利用規約またはプライバシーポリシーにこの情報を含めるか、この情報にユーザーがアクセスできるようにします。次はデータ収集についてユーザーに通知するときのテキストの例です。

「このアプリケーションはHERE Technologiesが提供する位置情報サービスを使用しています。このサービスの維持、改善、提供のため、HERE Technologiesは、随時、近くのネットワーク信号の特性情報を収集します。詳細については、「HEREプライバシー通知」(https://legal.here.com/here-network-positioning-via-sdk) をご覧ください。」