工作中在使用高德和Mapbox地图,遇到了证书问题,大概错误如下:java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
网上查阅了不少资料,这里整理一下有效的解决方案:
高德地图
在使用这个api方法时候:
fun addMeteorologyLayer(tileUrl: String): TileOverlay {
LogUtils.e("tileUrl=$tileUrl")
val provider = object : UrlTileProvider(256, 256) {
override fun getTileUrl(x: Int, y: Int, zoom: Int): URL {
try {
var url = tileUrl
// 根据瓦片坐标和缩放级别生成对应的 URL 地址
url = url.replace("{z}", java.lang.String.valueOf(zoom))
.replace("{x}", java.lang.String.valueOf(x))
.replace("{y}", java.lang.String.valueOf(y))
//Log.i("tileUrl", "getTileUrl: url=$url")
return URL(url)
} catch (e: MalformedURLException) {
e.printStackTrace()
}
return URL(String.format(tileUrl, x, y, zoom))
}
}
val tileOverlayOptions = TileOverlayOptions()
.tileProvider(provider)
.diskCacheEnabled(false)
.memoryCacheEnabled(true)
.zIndex(999F)
return mAMap.addTileOverlay(tileOverlayOptions)
}
由于传进来的tileUrl是自己的公司的地址,https开头,由于证书问题,就会提示文章开头中的错误,解决方案如下:
private fun handleSSLHandshake() {
try {
val trustAllCerts: Array<TrustManager> = arrayOf(object : X509TrustManager {
override fun checkClientTrusted(
chain: Array<out X509Certificate>?, authType: String?
) = Unit
override fun checkServerTrusted(
chain: Array<out X509Certificate>?, authType: String?
) = Unit
override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
})
val sc: SSLContext = SSLContext.getInstance("TLS")
// trustAllCerts信任所有的证书
sc.init(null, trustAllCerts, SecureRandom())
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory())
HttpsURLConnection.setDefaultHostnameVerifier(object : HostnameVerifier {
override fun verify(hostname: String?, session: SSLSession?): Boolean {
return true
}
})
} catch (ignored: Exception) {
ignored.printStackTrace()
}
}
Mapbox 地图
在使用下面的api方法时:
fun addWgs84Layer(wgs84title: String) {
val tileSet =
TileSet.Builder("3.0.0", listOf(wgs84title))
.name("Wgs84Layer2")
.minZoom(0)
.maxZoom(18)
.version("2.0.0")
.scheme(Scheme.XYZ)
.build()
mapboxMap.getStyle { style ->
style.addSource(
rasterSource("84Layer2") {
tileSet(tileSet)
tileSize(128L)
}
)
style.addLayer(rasterLayer("84Layer2", "84Layer2") {
style.getSourceAs<RasterSource>("84Layer2")?.apply {
tileNetworkRequestsDelay(0.0)
}
})
}
}
由于传进来的tileUrl是自己的公司的地址,https开头,由于证书问题,就会提示文章开头中的错误,解决方案如下:
(1)在res文件夹下新建一个raw 文件夹,将证书xxx_mapbox.der文件放置于此文件夹下。关于证书的获取方法,网上资料很多不在细说。大概是这样:访问你传进来的 tileUrl地址,在浏览器 --》安全–》证书,最后导出你想要的格式即可。
如图:
(2)在res文件夹下新建xml文件夹,并新增一个xml文件用于配置网络安全参数(即额外证书指向),此处我是用的是network_security_config.xml
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="@raw/xxx_mapbox" />
<certificates src="system" />
</trust-anchors>
</base-config>
</network-security-config>
(3)最后一步需要在 AndroidMainifest.xml(主配置) 文件中添加 android:networkSecurityConfig ,表示变更网络配置。
这种方式需要定期更换一下证书文件才行,不过一般一年半载不会更换。也尝试过高德地图上面的处理方法但是不行。
总结
至于为什么会出现这种问题,有说是提供的访问的这个url证书不全导致,等等原因吧。目前我也是没有安全搞明白,有知道的小伙伴欢迎留言评论。
参考文章:
Https证书验证相关;security.cert.CertPathValidatorException: Trust anchor for certification path not found.