基于Android的谷歌地图地理围栏功能开发
第一步、Android使用谷歌地图权限
Android上使用谷歌地图
必备条件:、Android设备上安装Google Play Service
由于谷歌在国内已经被墙了,所以我们只能使用软件使用谷歌地图,而使用谷歌地图的同时,我们需要安装Google Play Service,这个之后用google浏览器下载就行了。
接下来是简单的教程:
1、注册账号并登录 https://code.google.com/apis/console/
2、创建项目并选择项目、点击凭据
3、创建凭据、需要提供包名和AS的SHA1指纹证书
AS的SHA1的指纹证书,可以通过命令行打印,在命令行进入jdk的目录,输入:
keytool -list -v -keystore "%USERPROFILE%\.android\debug.keystore" -alias androiddebugkey -storepass android -keypass android
结果如下
最后、保存、将生成的key值写进谷歌地图工程的配置文件中,如下
第二步、开发基于谷歌的地理围栏功能
1、相关权限
以上三个权限为定位和加载地图所用
2、注册监听地理围栏服务
3、创建地理围栏管理器
public class GeofenceManager implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, ResultCallback, LocationListener { private static final String TAG = "Dan"; private static GoogleApiClient googleApiClient; private static GeofenceManager _singleInstance; GeofencingClient geofencingClient; private static Context appContext; private static final String ERR_MSG = "Application Context is not set!! " + "Please call GeofenceSngleton.init() with proper application context"; private PendingIntent mGeofencePendingIntent; private static ArrayList mGeofenceList; private GeofenceManager() { if (appContext == null) throw new IllegalStateException(ERR_MSG); this.googleApiClient = new GoogleApiClient.Builder(this.appContext) .addApi(LocationServices.API) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .build(); this.googleApiClient.connect(); geofencingClient = LocationServices.getGeofencingClient(appContext); mGeofenceList = new ArrayList(); } public static void init(Context applicationContext) { appContext = applicationContext; } public static GeofenceManager getInstance() { if (_singleInstance == null) synchronized (GeofenceManager.class) { if (_singleInstance == null) _singleInstance = new GeofenceManager(); } return _singleInstance; } @Override public void onConnected(Bundle bundle) { createLocationRequest(); } @Override public void onConnectionSuspended(int i) { } @Override public void onConnectionFailed(ConnectionResult connectionResult) { } //添加地理围栏 public void addGeofence(GeofenceInfo geofenceInfo) { mGeofenceList.add(new Geofence.Builder() .setRequestId(geofenceInfo.getUid()) .setCircularRegion( geofenceInfo.getLatitude(), geofenceInfo.getLongitude(), geofenceInfo.getRadius() ) .setExpirationDuration(5000000) .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT) .build()); } /** * 构建地理围栏请求 * */ private GeofencingRequest getGeofencingRequest() { GeofencingRequest.Builder builder = new GeofencingRequest.Builder(); builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER); builder.addGeofences(mGeofenceList); return builder.build(); } /** * 返回地理围栏监听服务的Intent * */ private PendingIntent getGeofencePendingIntent() { if (mGeofencePendingIntent != null) { return mGeofencePendingIntent; } Intent intent = new Intent(appContext, GeofenceIntentService.class); return PendingIntent.getService(appContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); } public void startGeofencing() { if (!googleApiClient.isConnected()) { Log.i(TAG,"无法连接谷歌服务"); return; } if(checkPermission()) geofencingClient.addGeofences(getGeofencingRequest(), getGeofencePendingIntent()).addOnSuccessListener(new OnSuccessListener() { @Override public void onSuccess(Void aVoid) { Log.i(TAG,"add success"); Log.i(TAG,"地理围栏服务开启"); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Log.i(TAG,"add fail"); } }); } public static boolean checkPermission(){ if (ActivityCompat.checkSelfPermission(appContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return false; } return true; } public void removeGeofence() { geofencingClient.removeGeofences(getGeofencePendingIntent()); } @Override public void onResult(Status status) { if (status.isSuccess()) { Log.i(TAG,"执行地理围栏服务"); } else { Log.i(TAG,"地理围栏服务错误"); } } public static long UPDATE_INTERVAL_IN_MILLISECONDS = 10000; public static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = UPDATE_INTERVAL_IN_MILLISECONDS / 2; public LocationRequest mLocationRequest; /** * 创建位置请求对象mLocationRequest,封装监听参数 */ protected void createLocationRequest() { mLocationRequest = new LocationRequest(); if(checkPermission()) LocationServices.GeofencingApi.addGeofences(googleApiClient, getGeofencingRequest(), getGeofencePendingIntent()).setResultCallback(this); mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS); mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS); mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); startLocationUpdates(); } /** * 开始监听位置变化 */ protected void startLocationUpdates() { if (ActivityCompat.checkSelfPermission(appContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(appContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, mLocationRequest, this); } @Override public void onLocationChanged(Location location) { }}
各个函数模块都有注释,不做赘述
3、主Activity调用类
public class MainActivity extends AppCompatActivity implements OnMyLocationButtonClickListener, OnMyLocationClickListener, OnMapReadyCallback, GoogleMap.OnMapClickListener, ActivityCompat.OnRequestPermissionsResultCallback { private static final String TAG = "Dan"; private static final int LOCATION_PERMISSION_REQUEST_CODE = 202; private GoogleMap mMap; private GeofenceManager geofenceManager; private EditText etGeoLatitude,etGeoLongitude,etGeoArea,etGeoRefresh; private String strGgeoLatitude,strGeoLongitude,strGeoArea,strGeoRefresh; private Button btnGeoSubmit; private boolean mPermissionDenied = false; private static final double DEFAULT_RADIUS_METERS = 100; private GeofenceInfo geofenceInfo; private List mCircles = new ArrayList<>(1); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); mapFragment.getMapAsync(this); initData(); doTrans(); } public void initData(){ etGeoLongitude = findViewById(R.id.geo_longitude); etGeoLatitude = findViewById(R.id.geolatitude); etGeoArea = findViewById(R.id.geo_area); etGeoRefresh = findViewById(R.id.geo_refresh); btnGeoSubmit = findViewById(R.id.geo_submit); } public void doTrans(){ btnGeoSubmit.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { strGeoLongitude = etGeoLongitude.getText().toString(); strGgeoLatitude = etGeoLatitude.getText().toString(); strGeoArea = etGeoArea.getText().toString(); strGeoRefresh = etGeoRefresh.getText().toString(); geofenceInfo = new GeofenceInfo(Double.parseDouble(strGeoLongitude),Double.parseDouble(strGgeoLatitude),Integer.parseInt(strGeoArea)); DraggableCircle circle = new DraggableCircle(new LatLng(geofenceInfo.getLatitude(),geofenceInfo.getLongitude()), geofenceInfo.getRadius()); mCircles.add(circle); geofenceManager.addGeofence(geofenceInfo); geofenceManager.startGeofencing(); } }); } /** *添加地理围栏 * */ public void startNewGeofence(GeofenceInfo geofenceInfo){ DraggableCircle circle = new DraggableCircle(new LatLng(geofenceInfo.getLongitude(),geofenceInfo.getLatitude()), geofenceInfo.getRadius()); mCircles.add(circle); Location geofenceCenter = new Location(""); geofenceCenter.setLatitude(geofenceInfo.getLatitude()); geofenceCenter.setLongitude(geofenceInfo.getLongitude()); GeofenceManager.init(this); geofenceManager = GeofenceManager.getInstance(); geofenceManager.addGeofence(geofenceInfo); geofenceManager.startGeofencing(); } /** * 地图加载准备 * */ @Override public void onMapReady(GoogleMap map) { mMap = map; mMap.setOnMyLocationButtonClickListener(this); mMap.setOnMyLocationClickListener(this); mMap.setOnMapClickListener(this); enableMyLocation(); geofenceInfo = new GeofenceInfo(114.00043174,22.5964144312,1); startNewGeofence(geofenceInfo); } /** * 确认获取定位权限 */ private void enableMyLocation() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { XPermission.requestPermissions(this, LOCATION_PERMISSION_REQUEST_CODE, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, new XPermission.OnPermissionListener() { @Override public void onPermissionGranted() { } @Override public void onPermissionDenied() { XPermission.showTipsDialog(MainActivity.this); } }); } else if (mMap != null) { mMap.setMyLocationEnabled(true); } } @Override public boolean onMyLocationButtonClick() { Log.i(TAG, "MyLocation button clicked"); return false; } @Override public void onMyLocationClick(@NonNull Location location) { Toast.makeText(this, "Current location:\n" + location, Toast.LENGTH_LONG).show(); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode != LOCATION_PERMISSION_REQUEST_CODE) { return; } if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { enableMyLocation(); } else { mPermissionDenied = true; } } @Override protected void onResumeFragments() { super.onResumeFragments(); if (mPermissionDenied) { showMissingPermissionError(); mPermissionDenied = false; } } private void showMissingPermissionError() { XPermission.showTipsDialog(MainActivity.this); } @Override public void onMapClick(LatLng latLng) { etGeoLongitude.setText(latLng.longitude+""); etGeoLatitude.setText(latLng.latitude+""); if(tempCircle != null) tempCircle.remove(); tempCircle = new DraggableCircle(latLng,0); } DraggableCircle tempCircle; private class DraggableCircle { private final Marker mCenterMarker; private final Circle mCircle; private double mRadiusMeters; public DraggableCircle(LatLng center, double radiusMeters) { mRadiusMeters = radiusMeters; mCenterMarker = mMap.addMarker(new MarkerOptions() .position(center) .draggable(true)); mCircle = mMap.addCircle(new CircleOptions() .center(center) .radius(radiusMeters) .strokeWidth(2) .strokeColor(R.color.colorPrimaryDark) .fillColor(R.color.colorPrimary) .clickable(false)); } public void remove(){ mCenterMarker.remove(); mCircle.remove(); } public void setStrokePattern(List pattern) { mCircle.setStrokePattern(pattern); } public void setClickable(boolean clickable) { mCircle.setClickable(clickable); } } private static LatLng toRadiusLatLng(LatLng center, double radiusMeters) { double radiusAngle = Math.toDegrees(radiusMeters / 6371009) / Math.cos(Math.toRadians(center.latitude)); return new LatLng(center.latitude, center.longitude + radiusAngle); } private static double toRadiusMeters(LatLng center, LatLng radius) { float[] result = new float[1]; Location.distanceBetween(center.latitude, center.longitude, radius.latitude, radius.longitude, result); return result[0]; }}
4、效果图示例
三、功能开发注意事项
1、一定要确保申请key值得包名和自己Android Studio开发环境得SHA1值是一致的,如果不一致日子里面会有key值不存在的报错
2、由于谷歌在国内被墙了,所以在国内使用地理围栏一定要,而且还要下载谷歌服务,不然会出现地图无法显示、无法定位等异常现象
3、由于大陆采用的定位标准是个国际上定位标准是不一样的,所以谷歌的地位在国内会出现偏移,偏移大概500~1000米,这种现象到香港等地方就变得正常了,当然也可以通过一定的算法转换,让谷歌的地位适应国内的定位
源码下载地址:https://download.csdn.net/download/mldan/11216858
更多相关文章
- android用户界面-组件Widget-地图视图MapView
- android 百度地图3.0+常用操作
- Android(安卓)获取手机本地图片所在的位置
- Android(安卓)AGPS 定位 测试程序
- GridView 加载并显示本地图片
- android 百度地图SDK 获得详细路线信息
- 高德地图Android,绘制自定义定位蓝点、marker、面
- Android(安卓)GPS获取地理位置
- android加载本地图片