根据此Android doc,API 16+支持TLS 1.1和1.2,但直到API 20+才默认启用。我找到了一些解决方案(here,here,here和here)来启用对OkHttp的TLS 1.1和1.2支持。如何为Exoplayer启用TLS 1.1 / 1.2支持?我发现唯一支持Exoplayer TLS 1.1 / 1.2的帖子来自此github issue,建议改在此处提问。
“” 07-27 13:21:09.817 8925-9065 / com.ftsgps.monarchE / ExoPlayerImplInternal:源错误。com.google.android.exoplayer2.upstream.HttpDataSource $ HttpDataSourceException:无法连接到https://liveStream/LIVE-0089000D05/manifest.mpd在com.google.android.exoplayer2.upstream.DefaultHttpDataSource.open(DefaultHttpDataSource.java:194)在com.google.android.exoplayer2.upstream.DefaultDataSource.open(DefaultDataSource.java:147)在com.google.android.exoplayer2.upstream.DataSourceInputStream.checkOpened(DataSourceInputStream.java:102)在com.google.android.exoplayer2.upstream.DataSourceInputStream.open(DataSourceInputStream.java:65)在com.google.android.exoplayer2.upstream.ParsingLoadable.load(ParsingLoadable.java:129)在com.google.android.exoplayer2.upstream.Loader $ LoadTask.run(Loader.java:308)在java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)在java.util.concurrent.ThreadPoolExecutor $ Worker.run(ThreadPoolExecutor.java:587)在java.lang.Thread.run(Thread.java:841)导致原因:javax.net.ssl.SSLHandshakeException:javax.net.ssl.SSLProtocolException:SSL握手已中止:ssl = 0x722c3af8:SSL库失败,通常是协议错误错误:14077410:SSL例程:SSL23_GET_SERVER_HELLO:sslv3警报握手失败(external / openssl / ssl / s23_clnt.c:7440x689d8f10:0x00000000)“
仅在API 21版本(棒棒糖)以下才发生这种情况。服务器是使用TLS1.2协议,Lollipop以下的Android不支持该协议版本。
DefaultHttpDataSource
使用HttpsURLConnection
,它具有默认SSLSocketFactory
的静态字段。除非在实例上调用HttpsURLConnection
,否则所有SSLSocketFactory
的新实例都将分配此默认值setSSLSocketFactory()
。因此从技术上讲,如果您调用设置默认的SSLSocketFactory
before实例化DefaultHttpsDataSource
,它应该可以工作:
HttpsURLConnection.setDefaultSSLSocketFactory(new MyCustomSSLSocketFactory());
MyCustomSSLSocketFactoy
可能看起来像这样:
class MyCustomSSLSocketFactory extends SSLSocketFactory {
private javax.net.ssl.SSLSocketFactory internalSSLSocketFactory;
public MyCustomSSLSocketFactory () throws KeyManagementException, NoSuchAlgorithmException {
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, null, null);
internalSSLSocketFactory = context.getSocketFactory();
}
@Override
public String[] getDefaultCipherSuites() {
return internalSSLSocketFactory.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return internalSSLSocketFactory.getSupportedCipherSuites();
}
@Override
public Socket createSocket() throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket());
}
@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose));
}
@Override
public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort));
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port));
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort));
}
private Socket enableTLSOnSocket(Socket socket) {
if(socket != null && (socket instanceof SSLSocket)) {
((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
}
return socket;
}
}
但是请记住,这可能会在意外的地方更改应用程序的行为(极不可能,但从不会变得谨慎),为避免这种情况,您可以在使用DefaultHttpDataSource
之后将Default SSLSocketFactory恢复为旧的SSLSocketFactory。 。
但是,还有另一个更可靠的解决方案。您可以使用OkHttpDataSource
,可以在构造函数中传递OkHttpClient
实例。可以将该OkHttpClient
实例配置为使用我们的自定义SSLSocketFactory
。它看起来像这样:
okhttpclient.sslSocketFactory(new MyCustomSSLSocketFactory());
DataSource dataSource = new DefaultUriDataSource(context, bandwidthMeter,
new OkHttpDataSource(okHttpClient, userAgent, null, bandwidthMeter));
经过一些挖掘之后,我要做的就是使用ProviderInstaller在应用程序类中启用TLS1.2。我已经使用不接受TLS1.0的提供视频内容的服务器对其进行了验证,并且可以正常工作。
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
try {
// Google Play will install latest OpenSSL
ProviderInstaller.installIfNeeded(getApplicationContext());
SSLContext sslContext;
sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, null, null);
sslContext.createSSLEngine();
} catch (GooglePlayServicesRepairableException | GooglePlayServicesNotAvailableException
| NoSuchAlgorithmException | KeyManagementException e) {
e.printStackTrace();
}
}
}
参考:
https://guides.codepath.com/android/Using-OkHttp#enabling-tls-v1-2-on-older-devices