最近做了一个小的项目,主要功能是获取用户的定位等相关数据用于分析,在开发过程中使用了高德地图SDK,这里结合自己遇到的问题总结一些常见的API的用法,方便以后参考使用。
一、申请Key
二、配置工程
三、定位SDK的使用
四、地图SDK的使用
五、总结
使用高德地图SDK的步骤主要如下:
- 高德开放平台 注册成为开发者
- 创建新应用并添加key
- 下载需要的SDK,配置工程
- 编写代码,具体使用
高德开放平台上注册成为开发者很简单,容易出现问题的是key的获取,下面具体来说。
一、申请Key
在使用高德地图相关SDK前,我们必须先申请Key。这步如果获取不正确,那么后面肯定会出现问题。
申请Key上面这张图是申请Key时的界面,Package是我们应用的包名,其中容易出现问题的是SHA1码的获取。
官网上面给出的获取SHA1码的方法有好几种,我使用的是第三种。需要注意的是,调试版本(debug)和发布版本(release)下的 SHA1 值是不同的,发布 apk 时需要根据发布 apk 对应的 keystore 重新配置 Key。如果我们的App没有进行签名,那么就获取调试版本下的SHA1码。
使用 keytool(jdk自带工具)获取 SHA1码的过程如下:
1、运行进入控制台
Paste_Image.png2、在弹出的控制台窗口中输入 cd .android 定位到 .android 文件夹。
Paste_Image.png3、继续在控制台输入命令。
调试版本使用命令为:keytool -list -v -keystore debug.keystore
发布版本使用命令为:keytool -list -v -keystore apk的keystore
4、提示输入密钥库密码,开发模式默认密码是android,发布模式的密码是为apk的keystore设置的密码。输入密钥后回车(如果没设置密码,可直接回车),此时可在控制台显示的信息中获取 Sha1 值。
到这里,我们已经获取到SHA1码了,填好后点击提交即可获取到Key。
二、配置工程
总的来说,配置工程需要以下几步:
- 下载需要的SDK 并在工程里添加** jar 包 **
- 如果用到地图SDK 添加** so库 **
- AndroidManifest.xml文件里添加** meta-data信息**
- AndroidManifest.xml文件里添加** service **
- AndroidManifest.xml文件里添加** 权限 **
高德地图的SDK有好几种,我们根据自己的需要来选择下载然后配置到工程里,如果只是单纯地需要定位的功能,而不需要展示地图界面,那么可以只下载使用定位SDK,否则就需要添加3D地图的SDK。
在下面的内容中,主要是介绍高德地图定位SDK和地图SDK的使用,这里直接贴出官网上关于配置工程方面的相关文档。
可以看到,地图SDK配置相对来说多了so库的添加。
AndroidManifest.xml文件配置完成后如下所示,注意uses-permission、meta-data和service三个地方:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tsc.mydemomap">
<!--用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--用于访问GPS定位-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!--用于获取运营商信息,用于支持提供运营商信息相关的接口-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--用于访问wifi网络信息,wifi信息会用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!--用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!--用于访问网络,网络定位需要上网-->
<uses-permission android:name="android.permission.INTERNET" />
<!--用于读取手机当前的状态-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!--用于写入缓存数据到扩展存储卡-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--用于申请调用A-GPS模块-->
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<meta-data
android:name="com.amap.api.v2.apikey"
android:value="填入申请的Key值" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".LocActivity" />
<activity android:name=".MapActivity"></activity>
<service android:name="com.amap.api.location.APSService" />
</application>
</manifest>
三、定位SDK的使用
在上面Key申请完并成功配置好工程后,我们就正式进入了具体的编码过程。下面首先看一个例子,我们在界面上输出当前的定位结果,运行结果如下图所示:
定位成功布局界面很简单,主要就是一个显示定位结果的TextView。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:padding="16dp">
<TextView
android:id="@+id/tv_location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="定位结果" />
</LinearLayout>
Activity里的代码如下:
public class LocActivity extends AppCompatActivity implements AMapLocationListener {
private TextView tvLocation;
//定位服务类
private AMapLocationClient locationClient = null;
//定位参数类
private AMapLocationClientOption locationClientOption = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_loc);
tvLocation = (TextView) findViewById(R.id.tv_location);
//初始化定位
locationClient = new AMapLocationClient(getApplicationContext());
locationClient.setLocationListener(this);
//定位参数设置
locationClientOption = new AMapLocationClientOption();
locationClientOption.setLocationMode(AMapLocationMode.Hight_Accuracy);
locationClient.setLocationOption(locationClientOption);
locationClient.startLocation();
}
@Override
public void onLocationChanged(AMapLocation aMapLocation) {
if (aMapLocation != null) {
if (aMapLocation.getErrorCode() == 0) {
tvLocation.setText("纬度 " + aMapLocation.getLatitude() + "\n" +
"经度 " + aMapLocation.getLongitude() + "\n" +
aMapLocation.getAddress());
} else {
tvLocation.setText("定位失败, ErrCode:"
+ aMapLocation.getErrorCode() + ", errInfo:"
+ aMapLocation.getErrorInfo());
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (locationClient != null) {
locationClient.onDestroy();
locationClient = null;
locationClientOption = null;
}
}
}
定位SDK使用小结
在上面的LocActivity中,主要有两个类需要关注,AMapLocationClient和AMapLocationClientOption,其中AMapLocationClient是定位服务类,可以启动定位、停止定位以及销毁定位,而AMapLocationClientOption主要用于对定位的相关参数进行设置。
AMapLocationClient调用方法startLocation()后,开始异步获取定位数据,定位结果在回调方法onLocationChanged中,通过解析AMapLocation,得到需要的数据。
四、地图SDK的使用
在我们的开发中,如果有需要展示一张地图,那么我们就需要使用3D地图的SDK。下面是另外一个例子,主要逻辑是展示一张完整的地图,并显示当前的定位,长按地图时可以弹出对话框显示长按的位置点的详细信息。这里需要说明一下,长按地图时会得到长按的位置的经纬度,这里需要高德地图的搜索SDK,进行逆地理编码。
运行结果如图所示:
运行结果首先是布局文件,比较简单:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_map"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.amap.api.maps.MapView
android:id="@+id/mv_test"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.amap.api.maps.MapView>
</LinearLayout>
下面是Activity里的代码:
public class MapActivity extends AppCompatActivity implements LocationSource, AMapLocationListener, AMap.OnMapLongClickListener, GeocodeSearch.OnGeocodeSearchListener {
private MapView mapView;
private AMap map;
private OnLocationChangedListener locationChangedListener;
private AMapLocationClient locationClient;
private AMapLocationClientOption locationClientOption;
private int cLocation = 0;
//选中位置的数据
private double zLongtitude;
private double zLatitude;
private String zAddress = "";
private int cMapLongClick = 0;
private Marker marker;
private GeocodeSearch geocodeSearch;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
mapView = (MapView) findViewById(R.id.mv_test);
mapView.onCreate(savedInstanceState);
initMap();
}
private void initMap() {
if (map == null) {
map = mapView.getMap();
map.setLocationSource(this);// 设置定位监听
map.getUiSettings().setMyLocationButtonEnabled(true);// 设置默认定位按钮是否显示
map.setMyLocationEnabled(true);// 表示显示定位层并可触发定位
// 定位的类型为定位模式 ,可以由定位、跟随或地图根据面向方向旋转几种
map.setMyLocationType(AMap.LOCATION_TYPE_LOCATE);
map.setOnMapLongClickListener(this);
}
geocodeSearch = new GeocodeSearch(this);
geocodeSearch.setOnGeocodeSearchListener(this);
}
@Override
public void activate(OnLocationChangedListener onLocationChangedListener) {
locationChangedListener = onLocationChangedListener;
if (locationClient == null) {
locationClient = new AMapLocationClient(this);
locationClientOption = new AMapLocationClientOption();
locationClient.setLocationListener(this);
locationClientOption.setLocationMode(AMapLocationMode.Hight_Accuracy);
locationClient.setLocationOption(locationClientOption);
locationClient.startLocation();
}
}
@Override
public void deactivate() {
locationChangedListener = null;
if (locationClient != null) {
locationClient.stopLocation();
locationClient.onDestroy();
}
locationClient = null;
}
@Override
public void onLocationChanged(AMapLocation aMapLocation) {
if (locationChangedListener != null && aMapLocation != null) {
if (locationClient != null && aMapLocation.getErrorCode() == 0) {
locationChangedListener.onLocationChanged(aMapLocation);// 显示系统小蓝点
//如果是第一次定位成功 就缩放到级别18
if (cLocation == 0) {
map.moveCamera(CameraUpdateFactory.zoomTo(12));
cLocation++;
}
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
if (null != locationClient) {
locationClient.onDestroy();
}
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
deactivate();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
public void onMapLongClick(LatLng latLng) {
zLatitude = latLng.latitude;
zLongtitude = latLng.longitude;
BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromResource(R.mipmap.marker_location_center);
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.icon(bitmapDescriptor);
markerOptions.position(latLng);
if (cMapLongClick == 0) {
marker = map.addMarker(markerOptions);
cMapLongClick++;
} else {
}
marker.setPosition(latLng);
// 长按时中心点切换
map.animateCamera(CameraUpdateFactory.changeLatLng(latLng), 500, null);
LatLonPoint latLonPoint = new LatLonPoint(zLatitude, zLongtitude);
RegeocodeQuery query = new RegeocodeQuery(latLonPoint, 200,
GeocodeSearch.AMAP);
// 第一个参数表示一个Latlng,第二参数表示范围多少米,第三个参数表示是火系坐标系还是GPS原生坐标系
geocodeSearch.getFromLocationAsyn(query);// 设置异步逆地理编码请求
}
@Override
public void onRegeocodeSearched(RegeocodeResult regeocodeResult, int code) {
if (code == AMapException.CODE_AMAP_SUCCESS) {
if (regeocodeResult != null && regeocodeResult.getRegeocodeAddress() != null
&& regeocodeResult.getRegeocodeAddress().getFormatAddress() != null) {
zAddress = regeocodeResult.getRegeocodeAddress().getFormatAddress()
+ "附近";
} else {
zAddress = "未知位置";
}
} else {
zAddress = "未知位置";
}
showLocationInfo();
}
@Override
public void onGeocodeSearched(GeocodeResult geocodeResult, int i) {
}
private void showLocationInfo() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setIcon(R.mipmap.ic_launcher);
builder.setTitle("长按的位置信息");
String mess = "经度:" + zLongtitude + "\n纬度:" + zLatitude + "\n地址:" + zAddress;
builder.setMessage(mess);
builder.setPositiveButton("是", null);
builder.setNegativeButton("否", null);
builder.create().show();
}
}
五、总结
上面地图SDK的Activity部分代码比较长,下面总结其中的过程:
首先,我们是通过MapView来完成地图的展示的,在代码里类AMap是地图对象,通过MapView的getMap()方法可以实例化地图类。
在得到地图类的实例后我们可以进行一些初始化操作,比如setLocationSource方法设置定位监听,设置定位模式等等。
在地图有关的操作中,一定需要注意根据Activity的不同生命周期进行不同的状态处理。
根据位置的经纬度进行逆地理编码时需要用到搜索SDK的方法,异步获取具体地址时在回调方法onRegeocodeSearched()中获得结果,解析出来即可。
这里简单介绍了高德地图定位SDK和地图SDK的使用,利用好这些API,可以很方便地在应用中集成LBS服务,完善应用的功能,如果有更多别的需要,大家可以到官网上根据文档选择使用。
网友评论
AndroidManifest.xml文件里添加 service
AndroidManifest.xml文件里添加 权限
这3个能不能贴出来啊?不知道怎么配置