Android自签名证书导致AdMob激励广告加载失败求助
解决AdMob激励广告Precache阶段SSL握手异常问题
问题分析
- 触发异常:
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found - 异常场景:横幅、插屏广告可正常加载,仅激励广告加载时出现该错误;此前无异常,近期突发
- 核心冲突:自定义的
trustSelfSignedCertificate方法全局替换了SSL信任策略,仅信任自身自签名证书,导致AdMob激励广告请求Google服务器时,无法验证公共CA颁发的证书合法性
原因拆解
AdMob激励广告的Precache环节需要请求Google的广告服务器,这些服务器使用公共CA签发的SSL证书。而你的代码中覆盖了全局的SSLSocketFactory和HostnameVerifier,丢弃了系统默认的信任链,仅保留自签名证书的信任规则,导致Google服务器的证书无法通过验证,进而触发SSL握手失败。
横幅、插屏广告因请求通道或缓存机制差异,未受全局SSL配置影响,所以能正常加载。
解决方案
不要全局替换系统默认SSL配置,仅针对自家服务器域名应用自定义证书信任策略,保留系统默认信任链用于第三方服务(如AdMob)。
修改后的代码实现
fun getCustomOkHttpClientForMyServer(): OkHttpClient { val inStream = resources.openRawResource(R.raw.domain) val cf: CertificateFactory = CertificateFactory.getInstance("X.509") val ca: Certificate = cf.generateCertificate(inStream) inStream.close() // 创建包含自签名证书的KeyStore val ks: KeyStore = KeyStore.getInstance(KeyStore.getDefaultType()) ks.load(null, null) ks.setCertificateEntry("ca", ca) // 生成仅信任自签名证书的TrustManager val customTmf: TrustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) customTmf.init(ks) val customTrustManagers = customTmf.trustManagers // 获取系统默认的TrustManager(用于验证第三方服务证书) val systemTmf: TrustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) systemTmf.init(null as KeyStore?) val systemTrustManagers = systemTmf.trustManagers // 合并自定义与系统TrustManager,优先验证自签名证书,失败则回退到系统规则 val combinedTrustManager = object : X509TrustManager { override fun checkClientTrusted(chain: Array<out X509Certificate>?, authType: String?) { try { (customTrustManagers.first { it is X509TrustManager } as X509TrustManager) .checkClientTrusted(chain, authType) } catch (e: CertificateException) { (systemTrustManagers.first { it is X509TrustManager } as X509TrustManager) .checkClientTrusted(chain, authType) } } override fun checkServerTrusted(chain: Array<out X509Certificate>?, authType: String?) { try { (customTrustManagers.first { it is X509TrustManager } as X509TrustManager) .checkServerTrusted(chain, authType) } catch (e: CertificateException) { (systemTrustManagers.first { it is X509TrustManager } as X509TrustManager) .checkServerTrusted(chain, authType) } } override fun getAcceptedIssuers(): Array<X509Certificate> { val customIssuers = (customTrustManagers.first { it is X509TrustManager } as X509TrustManager).acceptedIssuers val systemIssuers = (systemTrustManagers.first { it is X509TrustManager } as X509TrustManager).acceptedIssuers return customIssuers + systemIssuers } } // 创建合并后的SSLContext val sslContext: SSLContext = SSLContext.getInstance("TLS") sslContext.init(null, arrayOf(combinedTrustManager), null) // 仅针对自家域名跳过主机名验证,其他域名使用系统默认规则 val hostnameVerifier = HostnameVerifier { hostname, session -> if (hostname == "your-server-domain.com") { // 替换为你的服务器域名 true } else { HttpsURLConnection.getDefaultHostnameVerifier().verify(hostname, session) } } return OkHttpClient.Builder() .sslSocketFactory(sslContext.socketFactory, combinedTrustManager) .hostnameVerifier(hostnameVerifier) .build() }
后续操作步骤
- 移除原代码中全局替换SSL配置的代码:
- 删除
HttpsURLConnection.setDefaultSSLSocketFactory(sslSocketFactory) - 删除
setDefaultHostnameVerifier(myHostnameVerifier)
- 删除
- 仅在访问自家服务器时使用上述自定义
OkHttpClient:// 示例:访问自家API时使用自定义客户端 val request = Request.Builder().url("https://your-server-domain.com/api").build() getCustomOkHttpClientForMyServer().newCall(request).enqueue(...) - 保留AdMob的默认请求配置,不要对其应用自定义SSL策略
重要提醒
全局替换SSL配置属于高危操作,会导致所有第三方服务(如AdMob、Firebase、支付SDK等)的SSL请求都强制使用你的自定义信任规则,极易引发兼容性问题。必须使用自签名证书时,务必仅针对特定域名应用自定义逻辑,避免影响其他服务。
内容的提问来源于stack exchange,提问作者lastpeony4
相关产品推荐
相关产品推荐

