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

Android 4.x系统中Glide加载HTTPS自签证书图片失败求助

解决Android 4/5系统中Glide加载自签HTTPS图片的SSL握手问题

我来帮你搞定这个困扰你的问题!你遇到的javax.net.ssl.SSLHandshakeException本质有两个核心原因:一是Android 4.4及以下系统默认不启用TLS 1.2,二是自签证书不在系统信任列表里,导致Glide默认的Http客户端过不了SSL验证。你之前的自定义GlideModule没解决问题,主要是没正确加载自签证书,而且TLS 1.2的兼容实现不够严谨。

完整解决方案

第一步:准备自签证书文件

先把你的自签证书(比如命名为my_cert.crt)放到app/src/main/res/raw目录下——如果没有raw文件夹就自己新建一个。

第二步:替换你的KioskGlideModule代码

把之前的代码完全替换成下面这个版本,我已经修复了证书信任和TLS兼容的问题:

@GlideModule
public class KioskGlideModule extends AppGlideModule {
    @Override
    public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
        super.registerComponents(context, glide, registry);
        // 构建支持自签证书+TLS1.2的OkHttpClient
        OkHttpClient okHttpClient = createCustomOkHttpClient(context);
        registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(okHttpClient));
    }

    @Override
    public boolean isManifestParsingEnabled() {
        return false;
    }

    private OkHttpClient createCustomOkHttpClient(Context context) {
        try {
            // 1. 加载raw目录里的自签证书
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            InputStream certInputStream = context.getResources().openRawResource(R.raw.my_cert);
            Certificate certificate;
            try {
                certificate = certificateFactory.generateCertificate(certInputStream);
            } finally {
                certInputStream.close();
            }

            // 2. 创建包含自签证书的KeyStore
            String keyStoreType = KeyStore.getDefaultType();
            KeyStore keyStore = KeyStore.getInstance(keyStoreType);
            keyStore.load(null, null);
            keyStore.setCertificateEntry("my_cert", certificate);

            // 3. 创建信任这个自签证书的TrustManager
            String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(tmfAlgorithm);
            trustManagerFactory.init(keyStore);
            TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();

            // 4. 配置SSLContext,同时兼容TLS1.2
            SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
            sslContext.init(null, trustManagers, new SecureRandom());

            OkHttpClient.Builder builder = new OkHttpClient.Builder()
                    .sslSocketFactory(createTls12SocketFactory(sslContext), (X509TrustManager) trustManagers[0]);

            // 给Android 4-5系统强制指定TLS版本
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
                        .tlsVersions(TlsVersion.TLS_1_2, TlsVersion.TLS_1_1, TlsVersion.TLS_1_0)
                        .build();
                builder.connectionSpecs(Collections.singletonList(spec));
            }

            return builder.build();
        } catch (Exception e) {
            Log.e("KioskGlideModule", "创建自定义OkHttpClient失败", e);
            // 出错时 fallback 到默认客户端,避免应用崩溃
            return new OkHttpClient();
        }
    }

    private SSLSocketFactory createTls12SocketFactory(SSLContext sslContext) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            return new SSLSocketFactoryCompat(sslContext.getSocketFactory());
        }
        return sslContext.getSocketFactory();
    }

    // 专门给Android 4.x写的SSLSocketFactory包装类,强制开启TLS1.2
    private static class SSLSocketFactoryCompat extends SSLSocketFactory {
        private final SSLSocketFactory delegate;

        SSLSocketFactoryCompat(SSLSocketFactory delegate) {
            this.delegate = delegate;
        }

        @Override
        public String[] getDefaultCipherSuites() {
            return delegate.getDefaultCipherSuites();
        }

        @Override
        public String[] getSupportedCipherSuites() {
            return delegate.getSupportedCipherSuites();
        }

        @Override
        public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
            return enableTls12(delegate.createSocket(s, host, port, autoClose));
        }

        @Override
        public Socket createSocket(String host, int port) throws IOException {
            return enableTls12(delegate.createSocket(host, port));
        }

        @Override
        public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
            return enableTls12(delegate.createSocket(host, port, localHost, localPort));
        }

        @Override
        public Socket createSocket(InetAddress host, int port) throws IOException {
            return enableTls12(delegate.createSocket(host, port));
        }

        @Override
        public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
            return enableTls12(delegate.createSocket(address, port, localAddress, localPort));
        }

        // 强制开启TLS1.2,同时保留兼容旧协议
        private Socket enableTls12(Socket socket) {
            if (socket instanceof SSLSocket) {
                ((SSLSocket) socket).setEnabledProtocols(new String[]{"TLSv1.2", "TLSv1.1", "TLSv1"});
            }
            return socket;
        }
    }
}

第三步:检查依赖配置

确保你的app/build.gradle里有这些依赖(版本可以根据你的项目调整,但要保持Glide和OkHttp集成库版本一致):

dependencies {
    implementation 'com.github.bumptech.glide:glide:4.15.1'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.15.1'
    implementation 'com.squareup.okhttp3:okhttp:4.10.0'
    implementation 'com.github.bumptech.glide:okhttp3-integration:4.15.1'
}

第四步:更新Glide加载代码

把原来的Glide调用改成用GlideApp(这是Glide注解处理器自动生成的类,确保你已经Rebuild过项目):

GlideApp.with(getApplicationInstance())
        .load(imageUrl)
        .placeholder(R.drawable.no_image)
        .error(R.drawable.no_image)
        .diskCacheStrategy(DiskCacheStrategy.RESOURCE)
        .into(imgView);

关键修复点说明

  1. 正确信任自签证书:把你的证书加载到KeyStore,让TrustManager明确信任这个证书,解决证书路径验证失败的问题
  2. TLS1.2兼容增强:通过包装SSLSocketFactory的方式,强制Android 4.x系统启用TLS1.2——这是很多老系统加载HTTPS资源的关键
  3. 防崩溃处理:添加了完整的异常捕获,就算证书加载出问题,也会fallback到默认客户端,不会导致页面崩溃
  4. 灵活的协议配置:同时支持TLS1.2/1.1/1.0,确保和不同服务器的兼容性

排查小技巧

  • 如果还是崩溃,先检查证书文件是否有效:可以用openssl x509 -in my_cert.crt -text -noout命令在电脑上验证证书内容
  • 确保已经Rebuild项目,Glide注解处理器生成了GlideApp类——如果没生成,检查依赖里的compiler是否添加正确
  • 查看Logcat的错误日志,重点看KioskGlideModule标签下的异常信息,定位具体问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 10:52:33