Android 整合高德地图

语言: CN / TW / HK

文章目录

demo的使用

如果想要在自己的项目中整合进高德,第一步就是要看看人家写的demo,所以首先

下载高德的demo

下载地址

下载完以后包含4个文件夹,其中2DMap包含了我们平时用到的很多功能\ 这里写图片描述

我们运行在手机上的时候,使用某些功能会提示\ 这里写图片描述

这是SHA1值的问题,我们可以进行如下操作来暂时使用高德的demo

如何正常使用高德demo

1、获取 SHA1 值\ 进入cmd

cd .android keytool -list -v -keystore debug.keystore

提示输入密钥库密码,编译器提供的debug keystore默认密码是 android\ 这里写图片描述\ 此时可在控制台显示的信息中获取 SHA1 值\ 这里写图片描述

2、登录高德开放平台\ 高德开放平台

创建应用,并添加新key\ 这里写图片描述

3、复制应用的key\ 这里写图片描述

填写到AndroidManifest.xml中的如下位置

这里写图片描述

这样高德的demo就可以正常使用了\ 这里写图片描述

在自己 app 整合高德,仿钉钉打卡

在这里插入图片描述

1、按照上面的步骤在高德开放平台添加 release 的 签名文件获取新的 key\ 2、要实现仿钉钉打卡,需要利用高德的定位 SDK 的地理围栏功能,参见 示例中心:移动端地理围栏,根据 开发指南:Android Studio 配置工程 引入定位依赖

kotlin implementation 'com.amap.api:3dmap:latest.integration' implementation 'com.amap.api:location:5.2.0'

3、build.gradle 确认使用的 key\ 为了调试,可以把 debug 和 release 用一个签名文件

kotlin signingConfigs { debug { storeFile file('../app/key.jks') storePassword '123456' keyAlias "key0" keyPassword '123456' } release { storeFile file('../app/key.jks') storePassword '123456' keyAlias "key0" keyPassword '123456' } }

4、确认 build.gradle 中的 applicationId 是否是刚才申请 key 时填的一样\ 5、AndroidManifest 中配置 高德 key,并添加权限

```kotlin //地图包、搜索包需要的基础权限

    <!-- 设置key -->
    <meta-data
        android:name="com.amap.api.v2.apikey"
        android:value="设置刚才申请的key"/>
    <!-- 定位需要的服务 适配Android Q需要加上android:foregroundServiceType="location"-->
    <service
        android:name="com.amap.api.location.APSService"
        android:foregroundServiceType="location" />

```

6、因为我们要用到 地理围栏,所以可以先看下官方的demo,在下载的实例中找到 Amap_Android_API_Location_Demo 并运行\ 在这里插入图片描述\ 7、把 Demo 项目中的页面 plugin_geofence_map.xml 拿到自己项目中

```xml

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.amap.api.maps.MapView
        android:id="@+id/map"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    </com.amap.api.maps.MapView>

    <ScrollView
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:background="#D999"
            android:layout_alignParentBottom="true">
    <TextView
        android:id="@+id/tv_result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    </ScrollView>
</RelativeLayout>

```

代码直接把 GeoFence_Round_Activity 拿过来就行了

其中 CheckPermissionsActivity 是检查以下权限

java protected String[] needPermissions = { Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.READ_PHONE_STATE };

```java /* * 圆形地理围栏 * * @author hongming.wang * @since 3.2.0 / public class GeoFence_Round_Activity extends CheckPermissionsActivity implements OnClickListener, GeoFenceListener, OnMapClickListener, LocationSource, AMapLocationListener, OnCheckedChangeListener {

private View lyOption;

private TextView tvGuide;
private TextView tvResult;

private EditText etCustomId;
private EditText etRadius;

private CheckBox cbAlertIn;
private CheckBox cbAlertOut;
private CheckBox cbAldertStated;

private Button btAddFence;
private Button btOption;

/**
 * 用于显示当前的位置
 * <p>
 * 示例中是为了显示当前的位置,在实际使用中,单独的地理围栏可以不使用定位接口
 * </p>
 */
private AMapLocationClient mlocationClient;
private OnLocationChangedListener mListener;
private AMapLocationClientOption mLocationOption;

private MapView mMapView;
private AMap mAMap;

// 中心点坐标
private LatLng centerLatLng = null;
// 中心点marker
private Marker centerMarker;
private BitmapDescriptor ICON_YELLOW = BitmapDescriptorFactory
        .defaultMarker(BitmapDescriptorFactory.HUE_YELLOW);
private BitmapDescriptor ICON_RED = BitmapDescriptorFactory
        .defaultMarker(BitmapDescriptorFactory.HUE_RED);
private MarkerOptions markerOption = null;
private List<Marker> markerList = new ArrayList<Marker>();
// 当前的坐标点集合,主要用于进行地图的可视区域的缩放
private LatLngBounds.Builder boundsBuilder = new LatLngBounds.Builder();

// 地理围栏客户端
private GeoFenceClient fenceClient = null;
// 要创建的围栏半径
private float fenceRadius = 0.0F;
// 触发地理围栏的行为,默认为进入提醒
private int activatesAction = GeoFenceClient.GEOFENCE_IN;
// 地理围栏的广播action
private static final String GEOFENCE_BROADCAST_ACTION = "com.example.geofence.round";

// 记录已经添加成功的围栏
private HashMap<String, GeoFence> fenceMap = new HashMap<String, GeoFence>();

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_geofence_new);
    setTitle(R.string.roundGeoFence);
    // 初始化地理围栏
    fenceClient = new GeoFenceClient(getApplicationContext());

    lyOption = findViewById(R.id.ly_option);
    btAddFence = (Button) findViewById(R.id.bt_addFence);
    btOption = (Button) findViewById(R.id.bt_option);
    tvGuide = (TextView) findViewById(R.id.tv_guide);
    tvResult = (TextView) findViewById(R.id.tv_result);
    tvResult.setVisibility(View.GONE);
    etCustomId = (EditText) findViewById(R.id.et_customId);
    etRadius = (EditText) findViewById(R.id.et_radius);

    cbAlertIn = (CheckBox) findViewById(R.id.cb_alertIn);
    cbAlertOut = (CheckBox) findViewById(R.id.cb_alertOut);
    cbAldertStated = (CheckBox) findViewById(R.id.cb_alertStated);

    mMapView = (MapView) findViewById(R.id.map);
    mMapView.onCreate(savedInstanceState);
    markerOption = new MarkerOptions().draggable(true);
    init();
}

void init() {
    if (mAMap == null) {
        mAMap = mMapView.getMap();
        mAMap.getUiSettings().setRotateGesturesEnabled(false);
        mAMap.moveCamera(CameraUpdateFactory.zoomBy(6));
        setUpMap();
    }

    btOption.setVisibility(View.VISIBLE);
    btOption.setText(getString(R.string.hideOption));
    resetView_round();

    btAddFence.setOnClickListener(this);
    btOption.setOnClickListener(this);
    cbAlertIn.setOnCheckedChangeListener(this);
    cbAlertOut.setOnCheckedChangeListener(this);
    cbAldertStated.setOnCheckedChangeListener(this);

    IntentFilter filter = new IntentFilter();
    filter.addAction(GEOFENCE_BROADCAST_ACTION);
    registerReceiver(mGeoFenceReceiver, filter);

    /**
     * 创建pendingIntent
     */
    fenceClient.createPendingIntent(GEOFENCE_BROADCAST_ACTION);
    fenceClient.setGeoFenceListener(this);
    /**
     * 设置地理围栏的触发行为,默认为进入
     */
    fenceClient.setActivateAction(GeoFenceClient.GEOFENCE_IN);
}

/**
 * 设置一些amap的属性
 */
private void setUpMap() {
    mAMap.setOnMapClickListener(this);
    mAMap.setLocationSource(this);// 设置定位监听
    mAMap.getUiSettings().setMyLocationButtonEnabled(true);// 设置默认定位按钮是否显示
    // 自定义系统定位蓝点
    MyLocationStyle myLocationStyle = new MyLocationStyle();
    // 自定义定位蓝点图标
    myLocationStyle.myLocationIcon(
            BitmapDescriptorFactory.fromResource(R.drawable.gps_point));
    // 自定义精度范围的圆形边框颜色
    myLocationStyle.strokeColor(Color.argb(0, 0, 0, 0));
    // 自定义精度范围的圆形边框宽度
    myLocationStyle.strokeWidth(0);
    // 设置圆形的填充颜色
    myLocationStyle.radiusFillColor(Color.argb(0, 0, 0, 0));
    // 将自定义的 myLocationStyle 对象添加到地图上
    mAMap.setMyLocationStyle(myLocationStyle);
    mAMap.setMyLocationEnabled(true);// 设置为true表示显示定位层并可触发定位,false表示隐藏定位层并不可触发定位,默认是false
    // 设置定位的类型为定位模式 ,可以由定位、跟随或地图根据面向方向旋转几种
    mAMap.setMyLocationType(AMap.LOCATION_TYPE_LOCATE);
}

/**
 * 方法必须重写
 */
@Override
protected void onResume() {
    super.onResume();
    mMapView.onResume();
}

/**
 * 方法必须重写
 */
@Override
protected void onPause() {
    super.onPause();
    mMapView.onPause();
    deactivate();
}

/**
 * 方法必须重写
 */
@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    mMapView.onSaveInstanceState(outState);
}

/**
 * 方法必须重写
 */
@Override
protected void onDestroy() {
    super.onDestroy();
    mMapView.onDestroy();
    try {
        unregisterReceiver(mGeoFenceReceiver);
    } catch (Throwable e) {
    }

    if (null != fenceClient) {
        fenceClient.removeGeoFence();
    }
    if (null != mlocationClient) {
        mlocationClient.onDestroy();
    }
}

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.bt_addFence :
            addFence();
            break;
        case R.id.bt_option :
            if (btOption.getText().toString()
                    .equals(getString(R.string.showOption))) {
                lyOption.setVisibility(View.VISIBLE);
                btOption.setText(getString(R.string.hideOption));
            } else {
                lyOption.setVisibility(View.GONE);
                btOption.setText(getString(R.string.showOption));
            }
            break;
        default :
            break;
    }
}

private void drawFence(GeoFence fence) {
    switch (fence.getType()) {
        case GeoFence.TYPE_ROUND :
        case GeoFence.TYPE_AMAPPOI :
            drawCircle(fence);
            break;
        case GeoFence.TYPE_POLYGON :
        case GeoFence.TYPE_DISTRICT :
            drawPolygon(fence);
            break;
        default :
            break;
    }

    // // 设置所有maker显示在当前可视区域地图中
    // LatLngBounds bounds = boundsBuilder.build();
    // mAMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 150));

    removeMarkers();
}

private void drawCircle(GeoFence fence) {
    LatLng center = new LatLng(fence.getCenter().getLatitude(),
            fence.getCenter().getLongitude());
    // 绘制一个圆形
    mAMap.addCircle(new CircleOptions().center(center)
            .radius(fence.getRadius()).strokeColor(Const.STROKE_COLOR)
            .fillColor(Const.FILL_COLOR).strokeWidth(Const.STROKE_WIDTH));
    boundsBuilder.include(center);
}

private void drawPolygon(GeoFence fence) {
    final List<List<DPoint>> pointList = fence.getPointList();
    if (null == pointList || pointList.isEmpty()) {
        return;
    }
    for (List<DPoint> subList : pointList) {
        List<LatLng> lst = new ArrayList<LatLng>();

        PolygonOptions polygonOption = new PolygonOptions();
        for (DPoint point : subList) {
            lst.add(new LatLng(point.getLatitude(), point.getLongitude()));
            boundsBuilder.include(
                    new LatLng(point.getLatitude(), point.getLongitude()));
        }
        polygonOption.addAll(lst);

        polygonOption.strokeColor(Const.STROKE_COLOR)
                .fillColor(Const.FILL_COLOR).strokeWidth(Const.STROKE_WIDTH);
        mAMap.addPolygon(polygonOption);
    }
}

Object lock = new Object();
void drawFence2Map() {
    new Thread() {
        @Override
        public void run() {
            try {
                synchronized (lock) {
                    if (null == fenceList || fenceList.isEmpty()) {
                        return;
                    }
                    for (GeoFence fence : fenceList) {
                        if (fenceMap.containsKey(fence.getFenceId())) {
                            continue;
                        }
                        drawFence(fence);
                        fenceMap.put(fence.getFenceId(), fence);
                    }
                }
            } catch (Throwable e) {

            }
        }
    }.start();
}

Handler handler = new Handler() {
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case 0 :
                StringBuffer sb = new StringBuffer();
                sb.append("添加围栏成功");
                String customId = (String)msg.obj;
                if(!TextUtils.isEmpty(customId)){
                    sb.append("customId: ").append(customId);
                }
                Toast.makeText(getApplicationContext(), sb.toString(),
                        Toast.LENGTH_SHORT).show();
                drawFence2Map();
                break;
            case 1 :
                int errorCode = msg.arg1;
                Toast.makeText(getApplicationContext(),
                        "添加围栏失败 " + errorCode, Toast.LENGTH_SHORT).show();
                break;
            case 2 :
                String statusStr = (String) msg.obj;
                tvResult.setVisibility(View.VISIBLE);
                tvResult.append(statusStr + "\n");
                break;
            default :
                break;
        }
    }
};

List<GeoFence> fenceList = new ArrayList<GeoFence>();
@Override
public void onGeoFenceCreateFinished(final List<GeoFence> geoFenceList,
        int errorCode, String customId) {
    Message msg = Message.obtain();
    if (errorCode == GeoFence.ADDGEOFENCE_SUCCESS) {
        fenceList.addAll(geoFenceList);
        msg.obj = customId;
        msg.what = 0;
    } else {
        msg.arg1 = errorCode;
        msg.what = 1;
    }
    handler.sendMessage(msg);
}

/**
 * 接收触发围栏后的广播,当添加围栏成功之后,会立即对所有围栏状态进行一次侦测,如果当前状态与用户设置的触发行为相符将会立即触发一次围栏广播;
 * 只有当触发围栏之后才会收到广播,对于同一触发行为只会发送一次广播不会重复发送,除非位置和围栏的关系再次发生了改变。
 */
private BroadcastReceiver mGeoFenceReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        // 接收广播
        if (intent.getAction().equals(GEOFENCE_BROADCAST_ACTION)) {
            Bundle bundle = intent.getExtras();
            String customId = bundle
                    .getString(GeoFence.BUNDLE_KEY_CUSTOMID);
            String fenceId = bundle.getString(GeoFence.BUNDLE_KEY_FENCEID);
            //status标识的是当前的围栏状态,不是围栏行为
            int status = bundle.getInt(GeoFence.BUNDLE_KEY_FENCESTATUS);
            StringBuffer sb = new StringBuffer();
            switch (status) {
                case GeoFence.STATUS_LOCFAIL :
                    sb.append("定位失败");
                    break;
                case GeoFence.STATUS_IN :
                    sb.append("进入围栏 ");
                    break;
                case GeoFence.STATUS_OUT :
                    sb.append("离开围栏 ");
                    break;
                case GeoFence.STATUS_STAYED :
                    sb.append("停留在围栏内 ");
                    break;
                default :
                    break;
            }
            if(status != GeoFence.STATUS_LOCFAIL){
                if(!TextUtils.isEmpty(customId)){
                    sb.append(" customId: " + customId);
                }
                sb.append(" fenceId: " + fenceId);
            }
            String str = sb.toString();
            Message msg = Message.obtain();
            msg.obj = str;
            msg.what = 2;
            handler.sendMessage(msg);
        }
    }
};

@Override
public void onMapClick(LatLng latLng) {
    markerOption.icon(ICON_YELLOW);
    centerLatLng = latLng;
    addCenterMarker(centerLatLng);
    tvGuide.setBackgroundColor(getResources().getColor(R.color.gary));
    tvGuide.setText("选中的坐标:" + centerLatLng.longitude + ","
            + centerLatLng.latitude);
}

/**
 * 定位成功后回调函数
 */
@Override
public void onLocationChanged(AMapLocation amapLocation) {
    if (mListener != null && amapLocation != null) {
        if (amapLocation != null && amapLocation.getErrorCode() == 0) {
            tvResult.setVisibility(View.GONE);
            mListener.onLocationChanged(amapLocation);// 显示系统小蓝点
        } else {
            String errText = "定位失败," + amapLocation.getErrorCode() + ": "
                    + amapLocation.getErrorInfo();
            Log.e("AmapErr", errText);
            tvResult.setVisibility(View.VISIBLE);
            tvResult.setText(errText);
        }
    }
}

/**
 * 激活定位
 */
@Override
public void activate(OnLocationChangedListener listener) {
    mListener = listener;
    if (mlocationClient == null) {
        mlocationClient = new AMapLocationClient(this);
        mLocationOption = new AMapLocationClientOption();
        // 设置定位监听
        mlocationClient.setLocationListener(this);
        // 设置为高精度定位模式
        mLocationOption.setLocationMode(AMapLocationMode.Hight_Accuracy);
        // 只是为了获取当前位置,所以设置为单次定位
        mLocationOption.setOnceLocation(true);
        // 设置定位参数
        mlocationClient.setLocationOption(mLocationOption);
        mlocationClient.startLocation();
    }
}

/**
 * 停止定位
 */
@Override
public void deactivate() {
    mListener = null;
    if (mlocationClient != null) {
        mlocationClient.stopLocation();
        mlocationClient.onDestroy();
    }
    mlocationClient = null;
}

private void addCenterMarker(LatLng latlng) {
    if (null == centerMarker) {
        centerMarker = mAMap.addMarker(markerOption);
    }
    centerMarker.setPosition(latlng);
    markerList.add(centerMarker);
}

private void removeMarkers() {
    if(null != centerMarker){
        centerMarker.remove();
        centerMarker = null;
    }
    if (null != markerList && markerList.size() > 0) {
        for (Marker marker : markerList) {
            marker.remove();
        }
        markerList.clear();
    }
}

@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
    switch (buttonView.getId()) {
        case R.id.cb_alertIn :
            if (isChecked) {
                activatesAction |= GeoFenceClient.GEOFENCE_IN;
            } else {
                activatesAction = activatesAction
                        & (GeoFenceClient.GEOFENCE_OUT
                                | GeoFenceClient.GEOFENCE_STAYED);
            }
            break;
        case R.id.cb_alertOut :
            if (isChecked) {
                activatesAction |= GeoFenceClient.GEOFENCE_OUT;
            } else {
                activatesAction = activatesAction
                        & (GeoFenceClient.GEOFENCE_IN
                                | GeoFenceClient.GEOFENCE_STAYED);
            }
            break;
        case R.id.cb_alertStated :
            if (isChecked) {
                activatesAction |= GeoFenceClient.GEOFENCE_STAYED;
            } else {
                activatesAction = activatesAction
                        & (GeoFenceClient.GEOFENCE_IN
                                | GeoFenceClient.GEOFENCE_OUT);
            }
            break;
        default :
            break;
    }
    if (null != fenceClient) {
        fenceClient.setActivateAction(activatesAction);
    }
}

private void resetView_round() {
    etRadius.setHint("围栏半径");
    etRadius.setVisibility(View.VISIBLE);
    tvGuide.setBackgroundColor(getResources().getColor(R.color.red));
    tvGuide.setText("请点击地图选择围栏的中心点");
    tvGuide.setVisibility(View.VISIBLE);
}

/**
 * 添加围栏
 * 
 * @since 3.2.0
 * @author hongming.wang
 *
 */
private void addFence() {
    addRoundFence();
}

/**
 * 添加圆形围栏
 * 
 * @since 3.2.0
 * @author hongming.wang
 *
 */
private void addRoundFence() {
    String customId = etCustomId.getText().toString();
    String radiusStr = etRadius.getText().toString();
    if (null == centerLatLng
            || TextUtils.isEmpty(radiusStr)) {
        Toast.makeText(getApplicationContext(), "参数不全", Toast.LENGTH_SHORT)
                .show();
        return;
    }

    DPoint centerPoint = new DPoint(centerLatLng.latitude,
            centerLatLng.longitude);
    fenceRadius = Float.parseFloat(radiusStr);
    fenceClient.addGeoFence(centerPoint, fenceRadius, customId);
}

} ```

调试

我们可以直接在网页测试或验证:

高德搜索关键字获取坐标

其他调试