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

使用ExoPlayer流式播放音频时遇SSLHandshakeException问题求助

我之前碰到过一模一样的问题,本质就是你的流媒体服务器用了Android系统默认不信任的SSL证书——要么是自签名证书,要么是用了自定义CA颁发的证书,导致ExoPlayer在建立SSL连接时通不过证书验证。下面给你两种实用的解决办法,根据你的场景选:

方法一:将证书打包到应用中(推荐生产环境使用)

这个方法是把服务器的证书添加到应用的信任仓库里,让ExoPlayer信任这个证书,安全合规。

  1. 获取并放置证书文件
    先从你的流媒体服务器导出X.509格式的证书(通常是.cer或.pem后缀),把它放到你的Android项目的src/main/assets目录下(如果没有assets文件夹就新建一个)。假设证书文件名是stream_server.cer。

  2. 编写工具类加载证书并构建SSLContext
    创建一个工具类来处理证书加载和SSL上下文的初始化:

    import android.content.Context;
    import java.io.InputStream;
    import java.security.KeyStore;
    import java.security.cert.CertificateFactory;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.TrustManagerFactory;
    
    public class SSLHelper {
        public static SSLContext getTrustedSSLContext(Context context) throws Exception {
            // 加载assets中的证书
            CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
            InputStream certStream = context.getAssets().open("stream_server.cer");
            java.security.cert.Certificate serverCert = certFactory.generateCertificate(certStream);
            certStream.close();
    
            // 创建KeyStore并添加证书
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null, null);
            keyStore.setCertificateEntry("trusted_server_cert", serverCert);
    
            // 初始化信任管理器工厂
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
                TrustManagerFactory.getDefaultAlgorithm()
            );
            trustManagerFactory.init(keyStore);
    
            // 构建并返回SSLContext
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
            return sslContext;
        }
    }
    
  3. 为ExoPlayer配置自定义数据源
    推荐使用ExoPlayer的OkHttp扩展来配置自定义SSL(比默认的DefaultHttpDataSource更灵活),先确保你的build.gradle里添加了依赖:

    implementation "com.google.android.exoplayer:extension-okhttp:${exoplayer_version}"
    

    然后创建带自定义SSL的OkHttpClient,并配置给ExoPlayer:

    try {
        SSLContext sslContext = SSLHelper.getTrustedSSLContext(getApplicationContext());
        // 这里需要获取TrustManagerFactory实例,可在工具类中返回或调整代码逻辑
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init((KeyStore) null); // 这里对应工具类中的KeyStore初始化逻辑,可优化为工具类返回
    
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .sslSocketFactory(
                    sslContext.getSocketFactory(),
                    (X509TrustManager) trustManagerFactory.getTrustManagers()[0]
                )
                .build();
    
        // 创建自定义数据源工厂
        HttpDataSource.Factory dataSourceFactory = new OkHttpDataSource.Factory(okHttpClient);
    
        // 初始化ExoPlayer时使用这个数据源工厂
        ExoPlayer player = new ExoPlayer.Builder(this)
                .setMediaSourceFactory(new DefaultMediaSourceFactory(dataSourceFactory))
                .build();
    } catch (Exception e) {
        e.printStackTrace();
        // 处理证书加载或SSL初始化异常
    }
    
方法二:临时绕过证书验证(仅测试环境可用)

如果是测试阶段不想折腾证书,可以临时用这个方法跳过证书验证,但绝对不能在生产环境使用——这会完全暴露你的应用在SSL安全风险下:

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;
import java.security.SecureRandom;

// 自定义信任所有证书的TrustManager
private static final TrustManager[] TRUST_ALL_CERTS = new TrustManager[]{
    new X509TrustManager() {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) {}
        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) {}
        @Override
        public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
    }
};

// 构建信任所有证书的SSLContext
private SSLContext getUnsafeSSLContext() throws Exception {
    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, TRUST_ALL_CERTS, new SecureRandom());
    return sslContext;
}

// 配置到ExoPlayer的OkHttp数据源
try {
    OkHttpClient okHttpClient = new OkHttpClient.Builder()
            .sslSocketFactory(
                getUnsafeSSLContext().getSocketFactory(),
                (X509TrustManager) TRUST_ALL_CERTS[0]
            )
            .hostnameVerifier((hostname, session) -> true) // 同时跳过主机名验证
            .build();

    HttpDataSource.Factory dataSourceFactory = new OkHttpDataSource.Factory(okHttpClient);
    ExoPlayer player = new ExoPlayer.Builder(this)
            .setMediaSourceFactory(new DefaultMediaSourceFactory(dataSourceFactory))
            .build();
} catch (Exception e) {
    e.printStackTrace();
}
注意事项
  • 确保你的证书文件是正确的X.509格式,如果导出的是.pem文件,也可以直接用,代码里的CertificateFactory.getInstance("X.509")能处理。
  • 不要忘记添加网络权限到AndroidManifest.xml:<uses-permission android:name="android.permission.INTERNET" />
  • 生产环境一定要用方法一,方法二只适合本地测试或内部调试。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:11:36