谷歌地图对接记录(Android)
来源:互联网 发布:淘宝商城百丽旗舰店 编辑:程序博客网 时间:2024/06/05 07:08
一、背景
对于国内的安卓开发者来说,对谷歌地图的对接应该是很少见的(国内墙了谷歌,而且国内的手机系统也几乎都是阉割版安卓系统),大家一般使用百度地图、高德地图进行地图开发。但是总有人会不幸的需要做国外市场的app,需要使用到谷歌地图,比如我。
鉴于网上很少有教程来详细讲解谷歌地图的对接,而我在入门了解的时候也是过程坎坷。在此记录下谷歌地图的一些简单东西,后续若还有接触会持续更新。
二、准备工作
如果你使用的是国外的安卓手机,而并非国内各大厂商定制之后的阉割版安卓手机,那么恭喜你,你开发起来要方便很多。但是如果你身处国内,即使有国外的安卓手机,也还需要能翻墙。
2.1 翻墙
本人也是翻墙小白,就不过多介绍了。本人使用过蓝灯免费版和影梭付费版,在手机上安装对应软件后开启翻墙,均能实现效果。国内的网络是无法强调用谷歌地图的api等接口的,所以,在进行调试开发的时候,手机必须能翻墙。
2.2 谷歌大礼包安装
之前说了,因为谷歌在国内被墙的原因,国内的安卓手机,几乎都是阉割版安卓系统,Google Services、Google Store等都是没有的。而谷歌地图,需要手机内有这些应用,否则无法使用,如下图。
那么如何安装呢?按照网上的说法,要安装好几个谷歌应用,还说除了小米手机可以免root在小米手机商店安装谷歌安装器小米版,然后这个软件可以一次性自动安装好所有谷歌全家桶。
本人是使用本就root了的魅蓝手机,在魅族的应用商店内下载安装了谷歌安装器魅族专版,然后通过这个app安装好了谷歌全家桶。所以其他的不是很清楚。
另外,本人遇到的一个小插曲是,在安装好了谷歌全家桶之后,再次打开应用,还是出来了类似的提示。提示谷歌服务必须更新才能使用,提示文字的下方显示了一个更新按钮,在手机翻墙的情况下,点击更新,自动打开了谷歌商店的app,登录谷歌帐号,自动跳到了升级的界面,进行升级即可。
2.3 谷歌地图嵌入
谷歌官方介绍
在手机里面有谷歌对应的服务与app,且手机能访问外网的情况下。按照如如上网址的谷歌官方文档的入门指南进行开发,且申请了密钥之后。app在手机内运行的时候能看到打开了地图,但是界面上没有任何可操作的东西(除了移动地图,放大缩小等),也没有定位到当前位置。这时候可以松口气了,集成的差不多了。
三、谷歌地图API使用
官方文档和支持,以及使用百度与谷歌搜索,可以解决我们大部分问题。所以这里也只是记录本人使用谷歌地图时使用到的一个东西,仅作记录用途。
3.1 定位到当前位置
根据入门介绍,已经在app内集成了谷歌地图,但是此时没有定位到当前位置的操作。可以看到代码里面有一个onMapReady的回调方法,当地图初始化之后,会进入该方法,我们可以在此方法内做一些基础操作,比如,显示地图自带的定位到当前位置的功能。
googleMap.setMyLocationEnabled(true); // 开启定位到当前位置的功能
在onMapReady方法内使用如上代码,再次运行app的时候,可以看到在地图右上角有一个定位按钮,点击之后就可以定位且显示到当前位置了。
因为项目中,定位当前位置的按钮要显示在左下角且要定制图标,而且在点击定位的同时还需要做其他操作,所以,我们这里虽然要开启定位功能,但是要隐藏右上角的图标,且要自定义按钮事件实现定位到当前位置。不显示右上角图片的代码如下。
googleMap.getUiSettings().setMyLocationButtonEnabled(false); // 右上角不显示定位图标
在这种情况下,没有按钮来点击定位到当前位置。我们需要做的是在进入app的时候就自动定位到当前位置。代码如下(也写在onMapReady方法内):
GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build();mGoogleApiClient.connect();
该方法有一个回调方法onConnected,在该方法内我们能拿到定位到的位置,然后调用api显示当前定位出来。如下代码,则打开app之后,定位到当前位置后会记录当前位置,且移动显示当前位置。
@Override public void onConnected(Bundle bundle) { try { mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); } catch (SecurityException e) { e.printStackTrace(); } if (mLastLocation != null) { latLng = new LatLng(mLastLocation.getLatitude(), mLastLocation.getLongitude()); mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(latLng.latitude, latLng.longitude), 15)); Log.i("位置", mLastLocation + "1111111"); Log.i("位置", "最新的位置 getProvider " + mLastLocation.getProvider()); Log.i("位置", "最新的位置 getAccuracy " + mLastLocation.getAccuracy()); Log.i("位置", "最新的位置 getAltitude " + mLastLocation.getAltitude()); Log.i("位置", "最新的位置 Bearing() " + mLastLocation.getBearing()); Log.i("位置", "最新的位置 Extras() " + mLastLocation.getExtras()); Log.i("位置", "最新的位置 Latitude() " + mLastLocation.getLatitude()); Log.i("位置", "最新的位置 Longitude()() " + mLastLocation.getLongitude()); Log.i("位置", " ============= "); } mLocationRequest = LocationRequest.create(); mLocationRequest.setInterval(5000); //5 seconds mLocationRequest.setFastestInterval(3000); //3 seconds mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY); LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, new LocationCallback() { @Override public void onLocationResult(LocationResult locationResult) { super.onLocationResult(locationResult); } }); }
用户如果后续移动了地图,点击自定义的定位按钮时,我们使用mGoogleApiClient.reconnect();
方法,就可以再次定位且显示到当前所在位置上了。
定位的时候,手机需要开启了定位服务。本人没找到谷歌地图app那样的直接打开定位的方法,所以只能在进行定位之前,判断当前是否开启了定位,没有的话给提示,跳转到设置里面让用户手动开启定位权限(国内大部分应用,包括ofo的app也是如此)。
有一个现象就是,我用魅蓝手机测试的时候,打开定位的时候,会再次弹出是否使用谷歌定位服务,如果选择否,则还是无法获取到定位,用户必须选择同意使用谷歌定位服务。而在使用国外安卓手机做测试的时候,则没有这个弹框选择,开启定位的时候默认就是使用的谷歌定位服务。
3.2 添加标记
类似于共享单车,在地图上需要在某些位置上添加标记。如下代码,可以为标记设置位置、图标、标题、描述内容等信息且添加到地图内。
mMap.addMarker(new MarkerOptions() .position(new LatLng(mLastLocation.getLatitude() + 0.0011111, mLastLocation.getLongitude() + 0.0011111)) .title("title") .snippet("desc") .icon(BitmapDescriptorFactory.fromResource(R.mipmap.icon_marker_gray)));
标记有默认点击事件,点击的时候会在右下角弹出导航图标,点击之后,若手机内安装了谷歌地图会自动打开谷歌地图app进行导航,若手机内无谷歌地图app则会给出相应的提示。我们也可以自定义标记的点击事件,屏蔽掉默认行为。代码如下:
mMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() { @Override public boolean onMarkerClick(Marker marker) { // TODO return false; // 返回false,点击的时候会将点击标记移至界面中间;true,不移動中心位置 } });
3.3 显示路线
一般情况下,我们点击某个标记或者位置,要进行导航的时候是跳转到谷歌地图,就如默认的方式那样。由地图进行专业的导航是最佳的,但是也许你也会遇到这样的奇葩需求,需要先在自己的app内也能显示过去的路线(自己app内集成谷歌地图如何进行导航包括语音,这我就不知道了,那也太变态了),那么如下工具类能帮到你(网上找的)。
public class GoogleMapUtils { /** * 通过起点终点,组合成url * * @param origin * @param dest * @return */ public static String getDirectionsUrl(LatLng origin, LatLng dest) { // Origin of route String str_origin = "origin=" + origin.latitude + "," + origin.longitude; // Destination of route String str_dest = "destination=" + dest.latitude + "," + dest.longitude; // Sensor enabled String sensor = "sensor=false"; // Travelling Mode String mode = "mode=driving"; //waypoints,116.32885,40.036675 String waypointLatLng = "waypoints=" + "40.036675" + "," + "116.32885"; // Building the parameters to the web service String parameters = str_origin + "&" + str_dest/* + "&" + sensor + "&" + mode + "&" + waypointLatLng*/; // Output format String output = "json"; // Building the url to the web service String url = "https://maps.googleapis.com/maps/api/directions/" + output + "?" + parameters; System.out.println("getDerectionsURL--->: " + url); return url; } /** * A method to download json data from url */ public static String downloadUrl(String strUrl) throws IOException { String data = ""; InputStream iStream = null; HttpURLConnection urlConnection = null; try { URL url = new URL(strUrl); // Creating an http connection to communicate with url urlConnection = (HttpURLConnection) url.openConnection(); // Connecting to url urlConnection.connect(); // Reading data from url iStream = urlConnection.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader( iStream)); StringBuffer sb = new StringBuffer(); String line = ""; while ((line = br.readLine()) != null) { sb.append(line); } data = sb.toString(); br.close(); } catch (Exception e) { Log.e("Excep downloading url", e.toString()); } finally { iStream.close(); urlConnection.disconnect(); } System.out.println("url:" + strUrl + "----> downloadurl:" + data); return data; } // Fetches data from url passed @SuppressLint("NewApi") public static class DownloadTask extends AsyncTask<String, Void, String> { // Downloading data in non-ui thread @Override protected String doInBackground(String... url) { // For storing data from web service String data = ""; try { // Fetching the data from web service data = downloadUrl(url[0]); } catch (Exception e) { Log.d("Background Task", e.toString()); } return data; } // Executes in UI thread, after the execution of // doInBackground() @Override protected void onPostExecute(String result) { super.onPostExecute(result); ParserTask parserTask = new ParserTask(); // Invokes the thread for parsing the JSON data parserTask.execute(result); } } /** * A class to parse the Google Places in JSON format */ @SuppressLint("NewApi") public static class ParserTask extends AsyncTask<String, Integer, List<List<HashMap<String, String>>>> { // Parsing the data in non-ui thread @Override protected List<List<HashMap<String, String>>> doInBackground( String... jsonData) { JSONObject jObject; List<List<HashMap<String, String>>> routes = null; try { jObject = new JSONObject(jsonData[0]); DirectionsJSONParser parser = new DirectionsJSONParser(); // Starts parsing data routes = parser.parse(jObject); System.out.println("do in background:" + routes); } catch (Exception e) { e.printStackTrace(); } return routes; } // Executes in UI thread, after the parsing process @Override protected void onPostExecute(List<List<HashMap<String, String>>> result) { ArrayList<LatLng> points = null; PolylineOptions lineOptions = null; MarkerOptions markerOptions = new MarkerOptions(); // Traversing through all the routes if (null != result) { for (int i = 0; i < result.size(); i++) { points = new ArrayList<LatLng>(); lineOptions = new PolylineOptions(); // Fetching i-th route List<HashMap<String, String>> path = result.get(i); // Fetching all the points in i-th route for (int j = 0; j < path.size(); j++) { HashMap<String, String> point = path.get(j); double lat = Double.parseDouble(point.get("lat")); double lng = Double.parseDouble(point.get("lng")); LatLng position = new LatLng(lat, lng); points.add(position); } // Adding all the points in the route to LineOptions lineOptions.addAll(points); lineOptions.width(Util.dp2px(LBoxApplication.getContext(), 3)); // Changing the color polyline according to the mode lineOptions.color(Color.parseColor("#4b98ff")); } // Drawing polyline in the Google Map for the i-th route MainActivity.mMap.addPolyline(lineOptions); } } }}
使用的时候只需要传值两个位置就行,表明从这个位置到另一个位置。
new GoogleMapUtils.DownloadTask().execute(GoogleMapUtils.getDirectionsUrl(new LatLng(mLastLocation.getLatitude(), mLastLocation.getLongitude()), new LatLng(mLastLocation.getLatitude() + 0.00222222, mLastLocation.getLongitude() - 0.00222222)));
该工具类的原理是调用谷歌的api接口,根据某些参数查询路线(代码中我注释掉了一些参数,使用默认值也就是步行的最优方案),然后根据查到的路线的结果调用googleMap.addPolyline方法,设置好线的颜色、宽度等即可。在本地测试的时候发现该api访问较慢。
3.4 主界面的代码
目前大概了解且实现了,定位、添加标记、地图上画线表明如何从当前位置走到指定位置。主要代码如下(布局界面参考官方入门指南):
public class MainActivity extends BaseActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener, OnMapReadyCallback { private Location mLastLocation = null; public static GoogleMap mMap; public static boolean showRoute = false; Marker mCurrLocation; LatLng latLng; LocationRequest mLocationRequest; GoogleApiClient mGoogleApiClient; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager() .findFragmentById(map); mapFragment.getMapAsync(this); } @OnClick({R.id.location_iv}) public void onClick(View view) { switch (view.getId()) { case R.id.location_iv: // 重新定位,会重新获取附近充电宝实况 mGoogleApiClient.reconnect(); break; } } @Override public void onMapReady(GoogleMap googleMap) { mMap = googleMap; mMap.setMyLocationEnabled(true); mMap.getUiSettings().setMyLocationButtonEnabled(false); // 右上角不显示定位图标 mMap.getUiSettings().setMapToolbarEnabled(false); // 点击标记底部右下角不出来控件 mMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() { @Override public boolean onMarkerClick(Marker marker) { // TODO return false; // 返回false,点击的时候会将点击标记移至界面中间;true,不移動中心位置 } }); buildGoogleApiClient(); mGoogleApiClient.connect(); } private void addMarkersToMap() { mMap.addMarker(new MarkerOptions() .position(new LatLng(mLastLocation.getLatitude() + 0.0011111, mLastLocation.getLongitude() + 0.0011111)) .title("title") .snippet("desc") .icon(BitmapDescriptorFactory.fromResource(R.mipmap.icon_marker_gray))); } @Override protected void onResume() { super.onResume(); if (showRoute) { new GoogleMapUtils.DownloadTask().execute(GoogleMapUtils.getDirectionsUrl(new LatLng(mLastLocation.getLatitude(), mLastLocation.getLongitude()), new LatLng(mLastLocation.getLatitude() + 0.00222222, mLastLocation.getLongitude() - 0.00222222))); showRoute = false; } } /** * * 离开界面时,断开连接 */ @Override protected void onStop() { super.onStop(); if (null != mGoogleApiClient && mGoogleApiClient.isConnected()) { mGoogleApiClient.disconnect(); } } protected synchronized void buildGoogleApiClient() { mGoogleApiClient = new GoogleApiClient.Builder(this) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build(); } @SuppressLint("NewApi") @Override public void onConnected(Bundle bundle) { try { mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient); } catch (SecurityException e) { e.printStackTrace(); } if (mLastLocation != null) { latLng = new LatLng(mLastLocation.getLatitude(), mLastLocation.getLongitude()); mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(latLng.latitude, latLng.longitude), 15)); Log.i("位置", mLastLocation + "1111111"); Log.i("位置", "最新的位置 getProvider " + mLastLocation.getProvider()); Log.i("位置", "最新的位置 getAccuracy " + mLastLocation.getAccuracy()); Log.i("位置", "最新的位置 getAltitude " + mLastLocation.getAltitude()); Log.i("位置", "最新的位置 Bearing() " + mLastLocation.getBearing()); Log.i("位置", "最新的位置 Extras() " + mLastLocation.getExtras()); Log.i("位置", "最新的位置 Latitude() " + mLastLocation.getLatitude()); Log.i("位置", "最新的位置 Longitude()() " + mLastLocation.getLongitude()); Log.i("位置", " ============= "); } mLocationRequest = LocationRequest.create(); mLocationRequest.setInterval(5000); //5 seconds mLocationRequest.setFastestInterval(3000); //3 seconds mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY); LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, new LocationCallback() { @Override public void onLocationResult(LocationResult locationResult) { super.onLocationResult(locationResult); } }); } @Override public void onConnectionSuspended(int i) { Toast.makeText(this, "onConnectionSuspended", Toast.LENGTH_SHORT).show(); } @Override public void onConnectionFailed(ConnectionResult connectionResult) { Toast.makeText(this, "onConnectionFailed", Toast.LENGTH_SHORT).show(); } /** * 当位置发生改变 **/ @Override public void onLocationChanged(Location location) { } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @Override public void onProviderEnabled(String provider) { } @Override public void onProviderDisabled(String provider) { }}
- 谷歌地图对接记录(Android)
- Unity3d对接谷歌地图(iOS篇)
- 模仿android谷歌地图功能开发记录
- 对接地图边界
- 地图对接汇总(百度地图)
- Android app调用第三方地图(百度地图,高德地图,谷歌地图)导航
- 联通sp对接记录
- 谷歌地图API相关记录
- PHP版:地图对接汇总
- PHP版:地图对接汇总
- PHP版:地图对接汇总(百度地图)
- android加入谷歌地图(1)
- android加入谷歌地图(2)
- android学习记录(三)百度地图错误---手机显示只有一个框架,没有地图内容。
- 记录百度地图开发(android)百度地图定位返回4.9E-324的解决方案
- Android谷歌地图+定位
- android集成谷歌地图
- Android招行一网通对接
- java的GC机制--java的内存区域
- tr和td标签
- Matlab读取图片引发的思考
- AntDesign 的 Table 组件的 expandedRowRender 属性失效的问题
- 11月19日总结
- 谷歌地图对接记录(Android)
- 内存对齐
- kdump 的亲密战友 crash 4
- redis安装
- 2015寒假计划
- 小心,异步数据
- 2014年12月26日
- 线程和进程、程序、应用程序之间的关系
- 为什么要将模拟地和数字地分开,如何分开?