美文网首页高德技术 | 实践安卓集中营
利用高德地图API打造基于LBS的Android应用

利用高德地图API打造基于LBS的Android应用

作者: RumbleTsc | 来源:发表于2016-11-25 18:15 被阅读2089次

    最近做了一个小的项目,主要功能是获取用户的定位等相关数据用于分析,在开发过程中使用了高德地图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.png

    2、在弹出的控制台窗口中输入 cd .android 定位到 .android 文件夹。

    Paste_Image.png

    3、继续在控制台输入命令。

    调试版本使用命令为: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的使用,这里直接贴出官网上关于配置工程方面的相关文档。

    Android Studio中使用定位SDK前的配置

    Android Studio中使用3D地图SDK前的配置

    可以看到,地图SDK配置相对来说多了so库的添加。

    AndroidManifest.xml文件配置完成后如下所示,注意uses-permissionmeta-dataservice三个地方:

    <?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服务,完善应用的功能,如果有更多别的需要,大家可以到官网上根据文档选择使用。

    相关文章

      网友评论

      • 简_安:请问调试版和发布版的SHA1码都要填写是吗?
        简_安: @Carole00谢谢,已解决😀
        布吉岛原住民:可以不填写调试版的SHA1码,只是方便你测试。
      • ZRay111:你好,最近发现高德地图的UiSettings.setRotateGesturesEnabled(boolean)方法无法使用,不知道你有没有遇到过?
      • JayDragon:AndroidManifest.xml文件里添加 meta-data信息
        AndroidManifest.xml文件里添加 service
        AndroidManifest.xml文件里添加 权限
        这3个能不能贴出来啊?不知道怎么配置
        RumbleTsc:@JayDragon http://lbs.amap.com/api/android-sdk/download/ 这里可以下载的
        JayDragon:@尘语凡心 感谢,还想问一下,那个搜索的SDK是哪来的
        RumbleTsc: @JayDragon 好,已经更新

      本文标题:利用高德地图API打造基于LBS的Android应用

      本文链接:https://www.haomeiwen.com/subject/hcvppttx.html