You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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()
}

后续操作步骤

  1. 移除原代码中全局替换SSL配置的代码:
    • 删除HttpsURLConnection.setDefaultSSLSocketFactory(sslSocketFactory)
    • 删除setDefaultHostnameVerifier(myHostnameVerifier)
  2. 仅在访问自家服务器时使用上述自定义OkHttpClient:
    // 示例:访问自家API时使用自定义客户端
    val request = Request.Builder().url("https://your-server-domain.com/api").build()
    getCustomOkHttpClientForMyServer().newCall(request).enqueue(...)
    
  3. 保留AdMob的默认请求配置,不要对其应用自定义SSL策略

重要提醒

全局替换SSL配置属于高危操作,会导致所有第三方服务(如AdMob、Firebase、支付SDK等)的SSL请求都强制使用你的自定义信任规则,极易引发兼容性问题。必须使用自签名证书时,务必仅针对特定域名应用自定义逻辑,避免影响其他服务。

内容的提问来源于stack exchange,提问作者lastpeony4

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 11:03:11