1. 問題の説明:
中国本土におけるファーウェイの地図サービスの「現在地」機能は、地図上の現在位置がユーザーの実際の位置から大きく乖離していることをユーザーに表示します。
具体的な違いは以下の図で確認できます。
2. 大きな逸脱の理由:
-
中国本土で Huawei Map SDK が使用する地理座標系は GCJ02 です。
-
「現在地」コントロールをクリックすると、取得される経度と緯度の地理座標系は WGS-84 になります。
-
上記 2 つの理由、つまり、マップ ビューで使用される地理座標系と「現在地」の位置情報ソースが一致していないため、「現在地」の位置が不正確になるという問題が発生します。
3. 解決策:
-
まず、Huawei Location SDKを使用して、測位(GCJ02地理座標系)を通じてユーザーの現在位置の緯度と経度情報を取得します。
-
HUAWEI Map SDK が提供する huaweiMap.setLocationSource(LocationSource locationSource) メソッドを使用して、「現在地」レイヤーの位置情報ソースを設定します。
4. 注意すべき事項:
Location SDK を使用して GCJ-02 座標系の緯度と経度を直接取得する方法は、SDK バージョン 6.7.0.300 以降にのみ適用できます。これは、Location SDK のバージョン 6.7.0.300 より前のバージョンでは緯度および経度の直接取得がサポートされていないためです。 GCJ-02 座標系の。
5 つの具体的な実装手順:
- 現在地をオンにしてマップ インスタンスを作成する
a. アクティビティのレイアウト ファイルにマップ コントロールを追加し、マップ プロパティを設定します。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
android:id="@+id/mapfragment_mapfragmentdemo"
class="com.huawei.hms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
map:cameraTargetLat="48.893478"
map:cameraTargetLng="2.334595"
map:cameraZoom="16" />
</androidx.constraintlayout.widget.ConstraintLayout>
b. アクティビティで SDK を初期化し、マップをロードします。
public class HwMyLocationActivity extends AppCompatActivity implements OnMapReadyCallback {
private HuaweiMap huaweiMap;
private SupportMapFragment mSupportMapFragment;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//初始化SDK
MapsInitializer.initialize(this);
setContentView(R.layout.activity_mylocation);
mSupportMapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.mapfragment_mapfragmentdemo);
//加载地图
mSupportMapFragment.getMapAsync(this);
}
@Override
public void onMapReady(HuaweiMap huaweiMap) {
//地图数据加载完成,展示成功。
this.huaweiMap = huaweiMap;
huaweiMap.setMyLocationEnabled(true);
}
}
c. マップを表示し、[現在地 UI コントロール] をクリックします。3 つのスクリーンショットから、「現在地」と「ユーザーの実際の場所」の間に大きな乖離があることがわかります。
- Huawei Location SDK を使用してユーザーの現在位置を取得する
a. FusedLocationProviderClient オブジェクトを宣言します。
// 声明fusedLocationProviderClient对象
private FusedLocationProviderClient fusedLocationProviderClient;
b. 位置更新コールバック用の LocationCallback を作成します。
/**
* 定义位置更新回调
*/
LocationCallback mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult != null) {
// TODO: 处理位置回调结果
Log.d("LOG_HwMyLocation", "Latitude" + locationResult.getLastHWLocation().getLatitude() +
" ; Longitude:" + locationResult.getLastHWLocation().getLongitude());
}
}
};
c. FusedLocationProviderClient オブジェクトを初期化し、位置タイプと GCJ02 座標タイプを設定して、位置を有効にします。
private void initLocationClient() {
// 实例化fusedLocationProviderClient对象
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
LocationRequest mLocationRequest = new LocationRequest();
// 设置位置更新的间隔(单位:毫秒)
mLocationRequest.setInterval(1000);
// 设置定位类型
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// 设置回调次数为1
mLocationRequest.setNumUpdates(10);
//设置坐标类型。
//默认传入COORDINATE_TYPE_WGS84返回WGS84坐标位置,
//传入COORDINATE_TYPE_GCJ02,返回GCJ02坐标位置。
mLocationRequest.setCoordinateType(LocationRequest.COORDINATE_TYPE_GCJ02);
//开启定位
fusedLocationProviderClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.getMainLooper())
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
// TODO: 接口调用成功的处理
Log.d("LOG_HwMyLocation", "定位开启成功");
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
// TODO: 接口调用失败的处理
Log.d("LOG_HwMyLocation", "定位开启失败:"+e.getMessage());
}
});
}
d. ユーザーの現在位置 (WGS-84 座標系) を取得するために測位を開始すると、次の結果が得られます。
e. Location の位置をマークするマーカーを作成します。このメソッドは、LocationCallback コールバックで呼び出すことができます。
private Marker locationMarker;
//添加定位位置标记
public void addLocationMarker(double Latitude, double Longitude) {
if (null != locationMarker) {
locationMarker.remove();
}
MarkerOptions options = new MarkerOptions()
.position(new LatLng(Latitude, Longitude))
.title("定位位置")
.snippet("定位所在位置");
locationMarker = this.huaweiMap.addMarker(options);
}
f. 以下の図 2 から、Location SDK の測位によって取得された GCJ02 の座標位置は、ユーザーの実際の位置から偏差がないことがわかります。
-
huaweiMap.setLocationSource(LocationSouce locationSouce) メソッドを使用して、Location SDK によって取得された GCJ-02 座標系の緯度と経度を、位置レイヤーの位置ソースとして設定します。具体的な実装は次のとおりです。
-
新しい MyLocationSouce クラスを作成して、位置情報ソースを定義します。
private class MyLocationSouce implements LocationSource {
private OnLocationChangedListener listener;
@Override
public void activate(OnLocationChangedListener onLocationChangedListener) {
listener = onLocationChangedListener;
}
@Override
public void deactivate() {
}
/**
* 改变我的位置图层的定位源
* @param lat_gcj02 GCJ-02
* @param log_gcj02 GCJ-02
*/
public void changeMyLocationSouce(double lat_gcj02, double log_gcj02) {
Location location = new Location("Provider");
location.setLatitude(lat_gcj02);
location.setLongitude(log_gcj02);
//设置精度
location.setAccuracy(200);
//当获取到新的用户位置时,调用此方法,设置定位源
listener.onLocationChanged(location);
}
}
- MyLocationSouce クラスを初期化し、MyLocationSouce を位置レイヤーの位置ソースとして設定します。
private MyLocationSouce myLocationSouce;
@Override
public void onMapReady(HuaweiMap huaweiMap) {
this.huaweiMap = huaweiMap;
huaweiMap.setMyLocationEnabled(true);
//初始化LocationSouce并设置我的位置图层的位置源
if (null == myLocationSouce){
myLocationSouce = new MyLocationSouce();
}
huaweiMap.setLocationSource(myLocationSouce);
}
- LocationCallback コールバック メソッドの位置ソースとして GCJ-02 座標系の緯度と経度を設定します。
/**
* 定义位置更新回调
*/
LocationCallback mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult != null) {
// TODO: 处理位置回调结果
Log.d("LOG_HwMyLocation", "Latitude" + locationResult.getLastHWLocation().getLatitude() +
" ; Longitude:" + locationResult.getLastHWLocation().getLongitude());
//将Location SDK获取的GCJ02坐标系的经纬度 标记在地图上
addLocationMarker(locationResult.getLastHWLocation().getLatitude(), locationResult.getLastHWLocation().getLongitude());
//设置定位源
if (null != myLocationSouce) {
myLocationSouce.changeMyLocationSouce(locationResult.getLastHWLocation().getLatitude(), locationResult.getLastHWLocation().getLongitude());
}
}
}
};
- 結果を示す:
以下の 2 つの図からわかるように、位置レイヤーはユーザーの実際の位置とずれることなく一致しています。
6. Map SDK と Location SDK で必要な権限のリストは次のとおりです。
- Map SDK が追加する必要がある権限のリスト:
<!-- 您调用地图服务能力,必须在“AndroidManifest”中为您的应用添加下列权限: -->
<!--允许程序访问网络连接-->
<uses-permission android:name="android.permission.INTERNET"/>
<!--允许程序获取网络信息状态-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!--自定义权限,允许程序读取公共数据-->
<uses-permission android:name="com.huawei.appmarket.service.commondata.permission.GET_COMMON_DATA"/>
<!--允许改变WLAN状态的开关-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<!-- 获取设备当前位置需要在“AndroidManifest”中增加以下权限,且Android 6.0以后需动态申请: -->
<!--允许程序通过Wi-Fi或移动基站的方式获取用户粗略的经纬度信息-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<!--允许程序通过GPS芯片接收卫星的定位信息-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
- Location SDK が追加する必要がある権限のリスト (権限の部分リスト):
<!-- Android提供了两种位置权限: ACCESS_COARSE_LOCATION(粗略的位置权限)和ACCESS_FINE_LOCATION(精确的位置权限)。
需要在“AndroidManifest.xml”文件中配置权限,且Android 6.0以后需动态申请: -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
7. 参考資料:
- Huawei Map SDK アクセスガイド:
https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides/android-sdk-brief-introduction-0000001061991343?ha_source=hms1
- マップ インスタンスを作成します。
https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides/android-sdk-map-instance-creation-0000001062881706?ha_source=hms1
- 現在地機能をオンにします。
https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides/android-sdk-my-location-0000001061775973?ha_source=hms1
- マーカー タグを作成して設定します。
https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides/android-sdk-map-instance-creation-0000001062881706?ha_source=hms1
- 位置レイヤーの位置ソースを設定します。
https://developer.huawei.com/consumer/cn/doc/development/HMSCore-References/huaweimap-0000001050151757#section1664916820220?ha_source=hms1
- Huawei Location SDK アクセスガイド:
https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides/android-introduction-0000001121930588?ha_source=hms1
- ユーザーの現在位置を取得するための融合測位開発:
https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides/location-develop-steps-0000001050746143?ha_source=hms1
- 位置測位設定座標系
https://developer.huawei.com/consumer/cn/doc/development/HMSCore-References/locationrequest-0000001050986189#section17806162191712?ha_source=hms1
さらに詳しく>>
Map Service Alliance の公式 Web サイトにアクセスしてください
HMS コア アライアンスの公式 Web サイトにアクセスしてください
HMS コア開発ガイダンス ドキュメントを入手する
私たちをフォローして、HMS Coreの最新技術情報を初めて学びましょう~