Android反向地理编码调用失败,API密钥权限受限问题求助
问题解决:Google Geocoding API 请求被拒绝(REQUEST_DENIED)
核心问题分析
你遇到的问题主要来自两个方面:
- Retrofit参数注解误用:你把Google API要求的查询参数(
latlng、key)用了@Path注解,但@Path是用来替换URL路径中的占位符的,会导致请求URL格式完全错误——Google服务器无法正确识别密钥和坐标参数,直接触发权限验证失败。 - Android应用限制的验证逻辑:当API密钥设置为Android应用限制时,Google需要验证请求来自指定包名+SHA1签名的应用,但Retrofit发起的普通HTTP请求不会自动携带这些验证信息(这部分是Google Maps SDK内部自动处理的),所以服务器无法确认请求合法性,返回拒绝。
解决步骤
1. 先修正Retrofit接口方法
把@Path替换为@Query,确保参数以查询参数的形式传递,符合Google API的URL规范:
@GET(ApiRoute.GEOCODE) suspend fun getAddress( @Query("latlng") latLng: String?, @Query("key") apiKey: String, ): Response<ReverseGeocodeEntity>
假设ApiRoute.GEOCODE的值是"geocode/json",修正后生成的URL会是正确的格式:https://maps.googleapis.com/maps/api/geocode/json?latlng=xxx&key=xxx。
2. 适配Android应用限制的验证(二选一)
如果要保留API密钥的Android应用限制(推荐,更安全),可以选下面任意一种方案:
方案A:使用Google Maps SDK内置的Geocoder
直接用SDK提供的地理编码工具,它会自动处理API密钥的验证(完全符合Android应用限制的要求),无需手动调用HTTP接口:
val geocoder = Geocoder(context, Locale.getDefault()) // 传入纬度、经度,获取1条地址结果 val addresses = geocoder.getFromLocation(latitude, longitude, 1) if (addresses?.isNotEmpty() == true) { val fullAddress = addresses[0].getAddressLine(0) // 处理获取到的地址数据 }
注意:这个类依赖设备上的Google Play服务,部分地区可能需要特殊网络环境。
方案B:通过后端代理请求
自己搭建一个后端接口,由后端调用Google Geocoding API(后端使用IP限制的API密钥),你的Android应用只需要调用自己的后端接口。这种方式既保证了密钥的安全性,又避开了移动端直接调用的验证问题。
额外检查项
- 确认Google Cloud控制台中,API密钥的Android应用限制里的包名完全匹配你的应用包名(注意大小写和拼写)。
- 通过
./gradlew signingReport命令重新获取调试和发布版本的SHA1,对比控制台中的记录,确保没有填错。 - 清除应用缓存并重启设备,保证Google Play服务的验证信息同步更新。
内容的提问来源于stack exchange,提问作者Maardev
相关产品推荐
相关产品推荐

