从Android 9 开始 APP默认访问的URL 必须是HTTPS协议的,虽然可以配置回支持HTTP,但这种做法不建议使用,已经0202年了,HTTPS早已经是主流。既然要使用HTTPS协议,就少不了CA证书,这个证书是收费的,也有些平台可以什么一年有效期的免费证书,但作为个人开发者,自己建个项目,开发用,完全没必要,我们使用JDK下的keytool生成 https证书。具体方法网上有很多,在此不再叙述。
由于是自建证书,它是不被浏览器或是系统认可的,在Android中使用OkHttp访问时,会报如下错误:
W/System.err: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
2020-03-31 12:27:58.570 26059-26059/com.s W/System.err: at com.android.org.conscrypt.ConscryptFileDescriptorSocket.startHandshake(ConscryptFileDescriptorSocket.java:231)
2020-03-31 12:27:58.570 26059-26059/com.s W/System.err: at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.kt:367)
2020-03-31 12:27:58.570 26059-26059/com.s W/System.err: at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.kt:325)
2020-03-31 12:27:58.571 26059-26059/com.s W/System.err: at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:197)
2020-03-31 12:27:58.571 26059-26059/com.s W/System.err: at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:233)
2020-03-31 12:27:58.571 26059-26059/com.s W/System.err: at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:107)
2020-03-31 12:27:58.571 26059-26059/com.s W/System.err: at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:75)
2020-03-31 12:27:58.571 26059-26059/com.s W/System.err: at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:245)
2020-03-31 12:27:58.571 26059-26059/com.s W/System.err: at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
2020-03-31 12:27:58.571 26059-26059/com.s W/System.err: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
2020-03-31 12:27:58.571 26059-26059/com.s W/System.err: at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:82)
2020-03-31 12:27:58.571 26059-26059/com.s W/System.err: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
2020-03-31 12:27:58.571 26059-26059/com.s W/System.err: at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
2020-03-31 12:27:58.571 26059-26059/com.s W/System.err: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
2020-03-31 12:27:58.572 26059-26059/com.s W/System.err: at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:74)
2020-03-31 12:27:58.572 26059-26059/com.s W/System.err: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
我们需要让OkHttp忽略掉证书校验,网上有很多做法都是:
/**
* OkHttpClient客户端
*/
private fun newClient(): OkHttpClient = OkHttpClient.Builder().apply {
connectTimeout(30, TimeUnit.SECONDS)// 连接时间:30s超时
readTimeout(10, TimeUnit.SECONDS)// 读取时间:10s超时
writeTimeout(10, TimeUnit.SECONDS)// 写入时间:10s超时
// 忽略证书验证 start
val x509 = MyX509()
sslSocketFactory(getSSLFactory(x509), x509)
hostnameVerifier(HostnameVerifier { _, _ -> true })
// 忽略证书验证 end
}.build()
private fun getSSLFactory(x509TrustManager: X509TrustManager): SSLSocketFactory {
val trustAllCerts = arrayOf<TrustManager>(x509TrustManager)
val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, trustAllCerts, java.security.SecureRandom())
return sslContext.socketFactory
}
class MyX509 : X509TrustManager {
override fun getAcceptedIssuers(): Array<X509Certificate> {
return arrayOf()
}
@Throws(CertificateException::class)
override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {
}
@Throws(CertificateException::class)
override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {
}
}
如果这么配置后在Android 10 上会报如下错误:
08:20:04 V/InstrumentationResultParser: java.lang.IllegalArgumentException: Required method checkServerTrusted(X509Certificate[], String, String, String) missing
08:20:04 V/InstrumentationResultParser: at android.net.http.X509TrustManagerExtensions.(X509TrustManagerExtensions.java:71)
08:20:04 V/InstrumentationResultParser: at okhttp3.internal.platform.android.Android10CertificateChainCleaner.(Android10CertificateChainCleaner.kt:36)
08:20:04 V/InstrumentationResultParser: at okhttp3.internal.platform.Android10Platform.buildCertificateChainCleaner(Android10Platform.kt:62)
08:20:04 V/InstrumentationResultParser: at okhttp3.internal.tls.CertificateChainCleaner$Companion.get(CertificateChainCleaner.kt:42)
08:20:04 V/InstrumentationResultParser: at okhttp3.OkHttpClient$Builder.sslSocketFactory(OkHttpClient.kt:751)
08:20:04 V/InstrumentationResultParser: at okhttp.android.test.OkHttpTest.testCustomTrustManager(OkHttpTest.kt:437)
08:20:04 V/InstrumentationResultParser: at java.lang.reflect.Method.invoke(Native Method)
08:20:04 V/InstrumentationResultParser: at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
08:20:04 V/InstrumentationResultParser: at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
08:20:04 V/InstrumentationResultParser: at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
08:20:04 V/InstrumentationResultParser: at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
08:20:04 V/InstrumentationResultParser: at okhttp3.OkHttpClientTestRule$apply$1.evaluate(OkHttpClientTestRule.kt:111)
08:20:04 V/InstrumentationResultParser: at okhttp3.testing.PlatformRule$apply$1.evaluate(PlatformRule.kt:66)
其实这个问题已经有人在OkHttp的GitHub中提了issues,具体的解决方案是把X509TrustManager的实现类换成X509ExtendedTrustManager实现类即可。
@RequiresApi(Build.VERSION_CODES.N)
class MyX509 : X509ExtendedTrustManager() {
override fun checkClientTrusted(
chain: Array<out X509Certificate>?,
authType: String?,
socket: Socket?
) {
}
override fun checkClientTrusted(
chain: Array<out X509Certificate>?,
authType: String?,
engine: SSLEngine?
) {
}
override fun checkClientTrusted(chain: Array<out X509Certificate>?, authType: String?) {
}
override fun checkServerTrusted(
chain: Array<out X509Certificate>?,
authType: String?,
socket: Socket?
) {
}
override fun checkServerTrusted(
chain: Array<out X509Certificate>?,
authType: String?,
engine: SSLEngine?
) {
}
override fun checkServerTrusted(chain: Array<out X509Certificate>?, authType: String?) {
}
override fun getAcceptedIssuers(): Array<X509Certificate> {
return arrayOf()
}
}
相关issues地址