Android 腾讯地图定位功能(以3D地图为例)
前言
总结一下之前用过的腾讯地图定位功能,百度了很多,都是相对零散的东西。今天空自己总结了一下,如有不当,还望各位大佬不吝赐教!!!废话不多说,开始
一、准备环境
1,获取API Key
点击网址https://lbs.qq/console/key.html,申请API Key。
2,导入库文件
点击网址https://lbs.qq/android_v1/log.html,下载.so文件和jar包,放入libs文件夹下,如图
jar文件需手动添加到工程中,右键点击jar文件,Add AsLibrary…
并在app下的build.gradle中引入libs(如果已经引入则可忽略)
android {
...
sourceSets {
main {
jniLibs.srcDir 'libs'
}
}
}
3,配置 manifest
在 AndroidManifest.xml 中添加使用权限:
<!-- 通过GPS得到精确位置 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- 通过网络得到粗略位置 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 访问网络,某些位置信息需要从网络服务器获取 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 访问WiFi状态,需要WiFi信息用于网络定位 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 修改WiFi状态,发起WiFi扫描, 需要WiFi信息用于网络定位 -->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!-- 访问网络状态, 检测网络的可用性,需要网络运营商相关信息用于网络定位 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 访问网络的变化, 需要某些信息用于网络定位 -->
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<!-- 访问手机当前状态, 需要某些信息用于网络定位 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
在application标签中配置API Key
<application>
...
<meta-data android:name="TencentMapSDK" android:value="您申请的Key" />
</application>
ok,至此前期准备工作已完成,接下来到了实践阶段
二、实现功能
权限申请
Android 6.0系统在原有的AndroidManifest.xml声明权限的基础上新增了运行时权限动态检测,定位等权限也包含在其中。如果您的应用程序设置了 targetSdkVersion ≥ 23,则需要在调用定位功能前进行权限检查,权限检查的示例代码如下:
private void initPremis(){
if (Build.VERSION.SDK_INT >= 23) {
String[] permissions = {
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
if (checkSelfPermission(permissions[0]) != PackageManager.PERMISSION_GRANTED)
{
requestPermissions(permissions, 0);
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
//可在此继续其他操作。
// 开始定位
}
在展示地图之前完成权限的申请
xml地图显示
<com.tencent.tencentmap.mapsdk.maps.MapView
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Activity
在MainActivity.java中使用地图的时候需要注意,由于SDK并没有提供用于管理地图生命周期的Activity,因此需要用户继承Activity后管理地图的生命周期,防止内存泄露,示例代码如下:
public class MainActivity extends Activity {
private MapView mMapView;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
@Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
mMapView.onStart();
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
mMapView.onResume();
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
mMapView.onPause();
}
@Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
mMapView.onStop();
}
@Override
protected void onRestart() {
// TODO Auto-generated method stub
super.onRestart();
mMapView.onRestart();
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
mMapView.onDestroy();
}
}
private void init(){
mapView = (MapView) findViewById(R.id.map);
tencentMap = mapView.getMap();
tencentMap.setMapType(TencentMap.MAP_TYPE_NORMAL);
locationSource = new DemoLocationSource(this);
tencentMap.setLocationSource(locationSource);
/**
* 腾讯地图提供了UiSettings类以方便开发者对地图手势及SDK提供的控件的控制,以定制自己想要的视图效果。
* UiSettings类的实例化也是通过TencentMap来获取。
*/
UiSettings mapUiSettings = tencentMap.getUiSettings();
/**
* 可以控制地图的缩放级别,每次点击改变1个级别,此控件默认打开,
* 可以通过UiSettings.setZoomControlsEnabled(boolean)接口控制此控件的显示和隐藏。
*/
mapUiSettings.setZoomControlsEnabled(true);
/**
* 此控件可以指示地图的南北方向,默认的视图状态下不显示,只有在地图的偏航角或俯仰角不为0时才会显示,
* 并且该控件的默认点击事件会将地图视图的俯仰角和偏航角动画到0的位置。
* 可以通过UiSettings.setCompassEnabled(boolean)接口控制此控件的显示和隐藏。
*/
mapUiSettings.setCompassEnabled(true);
/**
* 当通过TencentMap.setLocationSource(locationSource)设置好地图的定位源后,
* 点击此按钮可以在地图上标注一个蓝点指示用户的当前位置。
* 可以通过UiSettings.setMyLocationButtonEnabled()接口设置此控件的显示和隐藏。
*/
mapUiSettings.setMyLocationButtonEnabled(true);
/**
* 旋转手势
*/
mapUiSettings.setRotateGesturesEnabled(false);
tencentMap.setMyLocationEnabled(true);
//当前位置的style样式,有兴趣的同学可自行研究
MyLocationStyle myLocationStyle = new MyLocationStyle();
myLocationStyle.anchor(0.5f, 0.5f);
myLocationStyle.icon(BitmapDescriptorFactory.fromResource(R.mipmap.ic_launcher));
myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE);
tencentMap.setMyLocationStyle(myLocationStyle);
//设置地图点击时间
tencentMap.setOnMapClickListener(clickListener);
}
TencentMap.OnMapClickListener clickListener = new TencentMap.OnMapClickListener() {
@Override
public void onMapClick(LatLng latLng) {
showInfo(latLng);
}
};
private void showInfo(LatLng latLng){
if (marker != null){
marker.remove();
i = i+1;
}
marker = tencentMap.addMarker(new MarkerOptions().
position(latLng).
title("北京" + i).
snippet("DefaultMarker"));
//设置点击图标动画
ScaleAnimation scaleAnimation = new ScaleAnimation(1.5f,1,1.5f,1);//x轴0倍,x轴1倍,y轴0倍,y轴1倍
scaleAnimation.setDuration(300);
marker.setAnimation(scaleAnimation);
marker.startAnimation();
//显示信息窗
marker.showInfoWindow();
marker.setInfoWindowEnable(true);
}
位置监听
class DemoLocationSource implements LocationSource, TencentLocationListener {
private Context mContext;
private OnLocationChangedListener mChangedListener;
private TencentLocationManager locationManager;
private TencentLocationRequest locationRequest;
public DemoLocationSource(Context context) {
// TODO Auto-generated constructor stub
mContext = context;
locationManager = TencentLocationManager.getInstance(mContext);
locationRequest = TencentLocationRequest.create()
.setInterval(1000*30) // 定位周期 (毫秒)
.setRequestLevel(TencentLocationRequest.REQUEST_LEVEL_POI) // 定位要求水准
.setAllowCache(true) // 是否使用缓存
.setQQ(""); // 设置QQ号
}
@Override
public void onLocationChanged(TencentLocation arg0, int arg1,
String arg2) {
// TODO Auto-generated method stub
if (arg1 == TencentLocation.ERROR_OK && mChangedListener != null) {
Log.e("maplocation", "location: " + arg0.getCity() + " " + arg0.getProvider() + " " + arg0.getBearing());
//当前位置信息
Location location = new Location(arg0.getProvider());
location.setLatitude(arg0.getLatitude());
location.setLongitude(arg0.getLongitude());
location.setAccuracy(arg0.getAccuracy());
// 定位 sdk 只有 gps 返回的值才有可能获取到偏向角
location.setBearing(arg0.getBearing());
mChangedListener.onLocationChanged(location);
mDestinationPoint = new LatLng(39.010737 * 1.0001, 115.469589 * 1.0001);//假设公司坐标
//计算两个坐标点的距离(单位m)
mDistance = TencentLocationUtils.distanceBetween(location.getLatitude(), location.getLongitude(),40.007499,116.472209);
Log.d("jl---",mDistance + "" + "\n" + location.getLatitude() + "\n" + location.getLongitude());
}
}
@Override
public void onStatusUpdate(String arg0, int arg1, String arg2) {
// TODO Auto-generated method stub
}
@Override
public void activate(OnLocationChangedListener arg0) {
// TODO Auto-generated method stub
mChangedListener = arg0;
int err = locationManager.requestLocationUpdates(locationRequest, this);
switch (err) {
case 1:
setTitle("设备缺少使用腾讯定位服务需要的基本条件");
break;
case 2:
setTitle("manifest 中配置的 key 不正确");
break;
case 3:
setTitle("自动加载libtencentloc.so失败");
break;
default:
break;
}
}
@Override
public void deactivate() {
// TODO Auto-generated method stub
locationManager.removeUpdates(this);
mContext = null;
locationManager = null;
locationRequest = null;
mChangedListener = null;
}
public void onPause() {
locationManager.removeUpdates(this);
}
public void onResume() {
locationManager.requestLocationUpdates(locationRequest, this);
}
}
还有一个逆向地址解析的功能,通过位置坐标,获取当前地标建筑和周边地理位置信息
String s = "/ws/geocoder/v1/?key=OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77&location=" + location +
"kRAKpzQ5GhVRxbomUmaMWxDyzVdigDH";
String str = md5(s);
String request = "https://apis.map.qq/ws/geocoder/v1/?key=OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77&" +
"location=" + location + "&sig=" + str;
//这里拼接完成的request信息可以直接访问,返回值根据您的联网框架自行解析
public static String md5(String string) {
if (TextUtils.isEmpty(string)) {
return "";
}
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
byte[] bytes = md5.digest(string.getBytes());
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
String temp = Integer.toHexString(b & 0xff);
if (temp.length() == 1) {
temp = "0" + temp;
}
result.append(temp);
}
return result.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
联网成功后的返回值根据您的联网框架自行解析。具体返回信息请参考:
https://lbs.qq/webservice_v1/guide-gcoder.html
PS
值得注意的是,上面所使用到的key值,需要设置WebServiceAPI。
登陆进入腾讯位置服务个人中心,Key管理,选择使用的key进入设置页面,如下图
选中WebServiceAPI,选中签名校验,生成新的sk,点击保存。
开发中就使用此处生成的key。
ok,完事,简单的地图定位功能就实现了,虽说此功能不难,但是还有许多细节需要注意的。在此我只是做了一些简单的定位功能,很多其他功能,比如手势的各种监听,样式等等,给位老哥可以移步:https://lbs.qq/android_v1/guide-3d.html查看,还有官网上的参考手册供各位老哥参考,更加复杂的功能有待您去挖掘。
拜类个拜~多多支持哟
更多推荐
Android 腾讯地图定位功能一二三
发布评论