关于
前几天公司要求调研一下here map地图是否支持等值路由等线图这个功能,然后就去google了一下。因为不是国内的地图,然后在最后下载Android对应的sdk(探索版explore)需要有对应支付的功能,即使不收费,所以也需要有类似PayPal等支付账号。本篇文章即提供最新版的explore 版Android sdk(导入项目的是aar文件)
目前最新版基于时间 2022-5-29
sdk的下载链接我会放到文章末尾,以百度网盘形式。
配置
继续不需要下载,如果你想真正使用到项目而不是仅限于测试的话也需要注册账号然后填写一系列信息,然后创建一个项目如下:
然后会有提示你下载一个文件,文件里面包括对应的项目的id和secret,打开如下图:
然后我们将它写到我们项目的Androidmanifest.xml里面:
<meta-data
android:name="com.here.sdk.access_key_id"
android:value="JqOFpFBmTqMAMn_s49QIVw" />
<meta-data
android:name="com.here.sdk.access_key_secret"
android:value="zHujQuPPQVVxb2aMrUfW-1iXkmVGBUKQ3FBR4Y3Qq7h67RA0zH8Q_PlQ-jO15ph485qlM3ITDJhFfVbDZX2hNw" />
还有就是对应的here map的aar文件导入以及build文件的修改如下:
项目build文件:
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'], exclude : ['*mock*.jar'])
重新sync一下build,然后我们就可以使用here map地图了
简单使用
here map 的几乎所有功能都是基于mapScene,简单实现地图展示。
首先添加地图控件:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".HereMapActivity">
<com.here.sdk.mapview.MapView
android:id="@+id/map_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.here.sdk.mapview.MapView>
</androidx.constraintlayout.widget.ConstraintLayout>
然后在代码里面使用:
private var mapView: MapView? = null
private val locationRequest = registerForActivityResult(ActivityResultContracts.RequestPermission()){
if(it){
loadMapScene()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_here_map)
mapView = findViewById(R.id.map_view)
mapView!!.onCreate(savedInstanceState)
locationRequest.launch(Manifest.permission.ACCESS_FINE_LOCATION)
}
private fun loadMapScene() {
MapView.setPrimaryLanguage(LanguageCode.EN_US) //设置显示语言
mapView!!.mapScene.setLayerVisibility(MapScene.Layers.EXTRUDED_BUILDINGS,VisibilityState.HIDDEN)//一些图层的显示与隐藏
mapView!!.mapScene.setLayerVisibility(MapScene.Layers.LANDMARKS,VisibilityState.HIDDEN)
mapView!!.mapScene.loadScene(
MapScheme.NORMAL_NIGHT//五种模式地图,正常白黑、卫星地图、混合卫星和正常白黑
) { mapError ->
if (mapError == null) {
val distanceInMeters = (1000 * 10).toDouble()
mapView!!.camera.lookAt(
GeoCoordinates(52.530932, 13.384915)
)
} else {
}
}
}
效果图如下:
关于定位
首先是here map的开发文档
第一种方式如下:
新建一个PlatformPositioningProvider类
public class PlatformPositioningProvider implements LocationListener {
public static final String LOG_TAG = PlatformPositioningProvider.class.getName();
public static final int LOCATION_UPDATE_INTERVAL_IN_MS = 100;
private Context context;
private LocationManager locationManager;
@Nullable
private PlatformLocationListener platformLocationListener;
public interface PlatformLocationListener {
void onLocationUpdated(Location location);
}
public PlatformPositioningProvider(Context context) {
this.context = context;
}
@Override
public void onLocationChanged(android.location.Location location) {
if (platformLocationListener != null) {
platformLocationListener.onLocationUpdated(location);
}
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
switch(status){
case LocationProvider.AVAILABLE:
Log.e(LOG_TAG, "PlatformPositioningProvider status: AVAILABLE");
break;
case LocationProvider.OUT_OF_SERVICE:
Log.e(LOG_TAG, "PlatformPositioningProvider status: OUT_OF_SERVICE");
break;
case LocationProvider.TEMPORARILY_UNAVAILABLE:
Log.e(LOG_TAG, "PlatformPositioningProvider status: TEMPORARILY_UNAVAILABLE");
break;
default:
Log.e(LOG_TAG, "PlatformPositioningProvider status: UNKNOWN");
}
}
@Override
public void onProviderEnabled(String provider) {
Log.e(LOG_TAG, "PlatformPositioningProvider enabled.");
}
@Override
public void onProviderDisabled(String provider) {
Log.e(LOG_TAG, "PlatformPositioningProvider disabled.");
}
public void startLocating(PlatformLocationListener locationCallback) {
if (this.platformLocationListener != null) {
throw new RuntimeException("Please stop locating before starting again.");
}
if (ActivityCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(context,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
Log.e(LOG_TAG, "Positioning permissions denied.");
return;
}
this.platformLocationListener = locationCallback;
locationManager = (LocationManager) context.getSystemService(LOCATION_SERVICE);
if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) &&
context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS)) {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, LOCATION_UPDATE_INTERVAL_IN_MS, 1,this);
} else if (locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, LOCATION_UPDATE_INTERVAL_IN_MS, 1,this);
} else {
Log.e(LOG_TAG, "Positioning not possible.");
stopLocating();
}
}
public void stopLocating() {
if (locationManager == null) {
return;
}
locationManager.removeUpdates(this);
platformLocationListener = null;
}
}
然后在刚才初始化地图成功那里修改:
private var locationIndicator: LocationIndicator? = null
mapView!!.mapScene.loadScene(
MapScheme.NORMAL_NIGHT
) { mapError ->
if (mapError == null) {
val distanceInMeters = (1000 * 10).toDouble()
mapView!!.camera.lookAt(
GeoCoordinates(52.530932, 13.384915)
)
val platformPositioningProvide = PlatformPositioningProvide(this)
platformPositioningProvide.startLocating {
addMyLocationToMap(convertLocation(it))
}
} else {
}
}
private fun addMyLocationToMap(myLocation: Location) {
locationIndicator = LocationIndicator()
locationIndicator?.locationIndicatorStyle = LocationIndicator.IndicatorStyle.PEDESTRIAN
locationIndicator?.updateLocation(myLocation)
mapView?.addLifecycleListener(locationIndicator!!)
mapView?.camera?.lookAt(myLocation.coordinates)
}
private fun convertLocation(nativeLocation: android.location.Location): Location {
val geoCoordinates = GeoCoordinates(
nativeLocation.latitude,
nativeLocation.longitude,
nativeLocation.altitude
)
val location = Location(geoCoordinates)
if (nativeLocation.hasBearing()) {
location.bearingInDegrees = nativeLocation.bearing.toDouble()
}
if (nativeLocation.hasSpeed()) {
location.speedInMetersPerSecond = nativeLocation.speed.toDouble()
}
if (nativeLocation.hasAccuracy()) {
location.horizontalAccuracyInMeters = nativeLocation.accuracy.toDouble()
}
return location
}
但是没有定位成功,可能是中国的保护问题。也有可能是因为用的是explore版本的sdk原因。
也可以参考navigate版示例应用:的定位demo,这里因为项目调研目标不是这个,就没有深入研究。
使用自定义地图
首先要有自定义好的地图资源文件放到assets文件夹内,如下:
然后调用方法如下:
private fun loadMapStyle() {
// Place the style into the "assets" directory.
// Full path example: app/src/main/assets/mymapstyle.scene.json
// Adjust file name and path as appropriate for your project.
val fileName = "omv/omv-traffic-traffic-normal-night.scene.json"
val assetManager: AssetManager = assets
try {
assetManager.open(fileName)
} catch (e: IOException) {
Log.e("CustomMapStylesExample", "Error: Map style not found!")
return
}
mapView!!.mapScene.loadScene(
"" + fileName
) { mapError ->
if (mapError == null) {
val distanceInMeters = (1000 * 10).toDouble()
mapView!!.camera.lookAt(
GeoCoordinates(52.530932, 13.384915), distanceInMeters
)
} else {
Log.d("CustomMapStylesExample", "onLoadScene failed: $mapError")
}
}
}
效果图如下:
大致的使用方法就是这样,其他的几乎类似google地图百度地图等,就不做介绍了,文章内使用到的here的sdk以及自定义的地图资源下载链接考虑到百度网盘可能会丢失,所以放到了csdn上面,需要两积分。
到此文章结束,有问题欢迎批评指正,觉得不错的也请点个赞,谢谢