Android Studio中如何通过Google Maps API实现跨App传定位并显最短路径
实现步骤拆解
一、发起应用(发送位置)
1. 申请位置权限
在AndroidManifest.xml中添加定位权限:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Android 6.0+需动态请求权限:
private val REQUEST_LOCATION_PERMISSION = 1001 private fun requestLocationPermission() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ) { ActivityCompat.requestPermissions( this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), REQUEST_LOCATION_PERMISSION ) } else { getCurrentLocation() } } override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<out String>, grantResults: IntArray ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == REQUEST_LOCATION_PERMISSION && grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED ) { getCurrentLocation() } }
2. 获取当前位置
使用Google官方推荐的FusedLocationProviderClient获取最新位置:
private lateinit var fusedLocationClient: FusedLocationProviderClient override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) fusedLocationClient = LocationServices.getFusedLocationProviderClient(this) } private fun getCurrentLocation() { fusedLocationClient.lastLocation.addOnSuccessListener { location: Location? -> location?.let { sendLocationToReceiverApp(it.latitude, it.longitude) } ?: run { Toast.makeText(this, "无法获取当前位置,请检查定位设置", Toast.LENGTH_SHORT).show() } } }
3. 点击按钮发送位置
定义自定义Action(需与目标应用保持一致),通过隐式Intent传递经纬度:
// 按钮点击事件绑定 btn_send_location.setOnClickListener { requestLocationPermission() } private fun sendLocationToReceiverApp(lat: Double, lng: Double) { val intent = Intent().apply { action = "com.example.SHOW_ROUTE_TO_TARGET_LOCATION" putExtra("DEST_LAT", lat) putExtra("DEST_LNG", lng) addCategory(Intent.CATEGORY_DEFAULT) } // 检查是否有应用能处理该Intent,避免崩溃 if (intent.resolveActivity(packageManager) != null) { startActivity(intent) } else { Toast.makeText(this, "未找到目标应用", Toast.LENGTH_SHORT).show() } }
二、目标应用(接收位置并显示路线)
1. 配置Intent Filter接收数据
在AndroidManifest.xml的目标Activity中添加Intent Filter,匹配发起应用的自定义Action:
<activity android:name=".RouteDisplayActivity"> <intent-filter> <action android:name="com.example.SHOW_ROUTE_TO_TARGET_LOCATION" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
2. 接收并解析位置数据
在目标Activity中获取Intent传递的经纬度:
private lateinit var fusedLocationClient: FusedLocationProviderClient private var destLat: Double = 0.0 private var destLng: Double = 0.0 private val API_KEY = "你的Google Maps API密钥" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_route_display) fusedLocationClient = LocationServices.getFusedLocationProviderClient(this) intent?.let { destLat = it.getDoubleExtra("DEST_LAT", 0.0) destLng = it.getDoubleExtra("DEST_LNG", 0.0) if (destLat != 0.0 && destLng != 0.0) { initMapAndFetchRoute() } else { Toast.makeText(this, "位置数据无效", Toast.LENGTH_SHORT).show() } } }
3. 集成Google Maps SDK
3.1 配置API密钥
在Google Cloud Console启用Maps SDK for Android和Directions API,获取密钥后添加到AndroidManifest.xml:
<meta-data android:name="com.google.android.geo.API_KEY" android:value="你的Google Maps API密钥" />
3.2 布局添加地图组件
使用SupportMapFragment嵌入地图:
<fragment android:id="@+id/map_fragment" android:name="com.google.android.gms.maps.SupportMapFragment" android:layout_width="match_parent" android:layout_height="match_parent" />
4. 获取起点位置并绘制路线
4.1 获取目标应用用户当前位置(起点)
复用发起应用的位置获取逻辑,获取用户当前位置后发起路线请求。
4.2 调用Directions API获取路线数据
添加Retrofit依赖到build.gradle:
implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
定义API接口和数据类:
interface DirectionsApi { @GET("maps/api/directions/json") suspend fun getRoute( @Query("origin") origin: String, @Query("destination") destination: String, @Query("key") apiKey: String ): DirectionsResponse } data class DirectionsResponse(val routes: List<Route>) data class Route(val overview_polyline: OverviewPolyline) data class OverviewPolyline(val points: String)
4.3 在地图上绘制最短路线
private lateinit var map: GoogleMap private fun initMapAndFetchRoute() { val mapFragment = supportFragmentManager.findFragmentById(R.id.map_fragment) as SupportMapFragment mapFragment.getMapAsync { googleMap -> map = googleMap getCurrentUserLocation() } } private fun getCurrentUserLocation() { fusedLocationClient.lastLocation.addOnSuccessListener { location: Location? -> location?.let { origin -> val originStr = "${origin.latitude},${origin.longitude}" val destStr = "$destLat,$destLng" CoroutineScope(Dispatchers.IO).launch { try { val retrofit = Retrofit.Builder() .baseUrl("https://maps.googleapis.com/") .addConverterFactory(GsonConverterFactory.create()) .build() val api = retrofit.create(DirectionsApi::class.java) val response = api.getRoute(originStr, destStr, API_KEY) withContext(Dispatchers.Main) { response.routes.firstOrNull()?.let { route -> drawRouteOnMap(route.overview_polyline.points) } ?: run { Toast.makeText(this@RouteDisplayActivity, "未找到可行路线", Toast.LENGTH_SHORT).show() } } } catch (e: Exception) { withContext(Dispatchers.Main) { Toast.makeText(this@RouteDisplayActivity, "路线请求失败: ${e.message}", Toast.LENGTH_SHORT).show() } } } } ?: run { Toast.makeText(this, "无法获取你的位置,请检查定位设置", Toast.LENGTH_SHORT).show() } } } private fun drawRouteOnMap(polylinePoints: String) { val polylineOptions = PolylineOptions() .color(Color.parseColor("#1A73E8")) .width(12f) .addAll(decodePolyline(polylinePoints)) map.addPolyline(polylineOptions) // 自动调整地图视野到路线范围 val bounds = LatLngBounds.builder() .include(LatLng(destLat, destLng)) .include(LatLng(map.cameraPosition.target.latitude, map.cameraPosition.target.longitude)) .build() map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 100)) } // 解码Polyline坐标点的工具方法 private fun decodePolyline(encoded: String): List<LatLng> { val poly = ArrayList<LatLng>() var index = 0 val len = encoded.length var lat = 0 var lng = 0 while (index < len) { var b: Int var shift = 0 var result = 0 do { b = encoded[index++].code - 63 result = result or (b and 0x1f shl shift) shift += 5 } while (b >= 0x20) val dlat = if (result and 1 != 0) (result shr 1).inv() else result shr 1 lat += dlat shift = 0 result = 0 do { b = encoded[index++].code - 63 result = result or (b and 0x1f shl shift) shift += 5 } while (b >= 0x20) val dlng = if (result and 1 != 0) (result shr 1).inv() else result shr 1 lng += dlng poly.add(LatLng(lat.toDouble() / 1E5, lng.toDouble() / 1E5)) } return poly }
关键注意事项
- 两个应用的自定义Action必须完全一致,否则无法传递数据。
- 确保Google Cloud Console已启用所需API,且API密钥配置正确,否则路线请求会返回权限错误。
- 处理定位权限拒绝、位置获取失败等异常场景,给用户明确提示。
- Directions API有调用配额限制,需根据实际使用情况调整配额。
内容的提问来源于stack exchange,提问作者user12206363
相关产品推荐
相关产品推荐

