Retrofit在某些版本的安卓系统上无法使用。

10

我在运行Android 4.3的模拟器上使用Retrofit时遇到了问题,而我的设备是Android 4.4.2,而同样的代码在另一个运行Android 7.1.1的模拟器上正常运行。

每次尝试执行get请求时都会出现超时异常。

java.net.SocketTimeoutException: failed to connect to jsonplaceholder.typicode.com/2606:4700:30::681c:3f5 (port 443) after 10000ms
        at libcore.io.IoBridge.connectErrno(IoBridge.java:159)
        at libcore.io.IoBridge.connect(IoBridge.java:112)
        at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:192)
        at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:459)
        at java.net.Socket.connect(Socket.java:842)
        at okhttp3.internal.platform.AndroidPlatform.connectSocket(AndroidPlatform.java:73)
        at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:246)
        at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:166)
        at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:257)
        at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:135)
        at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:114)
        at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
        at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
        at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:126)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
        at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:254)
        at okhttp3.RealCall$AsyncCall.execute(RealCall.java:200)
        at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
        at java.lang.Thread.run(Thread.java:841)

代码如下:
public interface Api {
    String BASE_URL = "https://jsonplaceholder.typicode.com/";

    @GET("posts")
    Call<ArrayList<Post>> getPosts();
}

以及对API的调用

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(Api.BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .build();

Api api = retrofit.create(Api.class);
Call<ArrayList<Post>> call = api.getPostes();
Log.i("RequestUrl", call.request().url().toString());
call.enqueue(new Callback<ArrayList<Post>>() {
    @Override
    public void onResponse(Call<ArrayList<Post>> call, Response<ArrayList<Post>> response) {
        mPostsList.setValue(response.body());
    }

    @Override
    public void onFailure(Call<ArrayList<Post>> call, Throwable t) {
        Log.e("Posts", "Error occurred", t);
    }
});

你正在使用哪个版本的Retrofit? - David Miguel
请检查我的答案 https://dev59.com/hoLba4cB1Zd3GeqPkeHz#66354256 - Shahab Saalami
3个回答

24
它显示了“java.net.SocketTimeoutException”,初始建议是提高客户端的连接超时值,如此答案中所解释的-但在查看okhttp3.internal.platform.AndroidPlatform的当前源代码时...这更暗示不兼容协议。
服务器的SSL证书支持“TLS 1.0”,因为它对于Android 4.x是必需的(他们这边没有问题); 问题实际上是当前版本的OkHttp3不再支持“TLS 1.0”,因此握手永远不会发生(这就是为什么它抛出这样一个误导性的SocketTimeoutException而不是SSLHandshakeException)。
使用OkHttp3 3.12.x,默认配置MODERN_TLS仍应受支持-
但可以指示OkHttp3 3.13.x改用配置COMPATIBLE_TLS
/* ConnectionSpec.MODERN_TLS is the default value */
List tlsSpecs = Arrays.asList(ConnectionSpec.MODERN_TLS);

/* providing backwards-compatibility for API lower than Lollipop: */
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
    tlsSpecs = Arrays.asList(ConnectionSpec.COMPATIBLE_TLS);
}

OkHttpClient client = new OkHttpClient.Builder()
    .connectionSpecs(tlsSpecs)
    .build();

还需要将其设置为Retrofit的客户端:

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl(Api.BASE_URL)
    .addConverterFactory(GsonConverterFactory.create())
    .setClient(client)
    .build();

查看TLS 配置历史以了解每个OkHttp3版本支持的协议。目前3.12.x已经支持TLS 1.3,而在未来,Android Q将需要此协议。可能不需要降级OkHttp3,因为3.12.xMODERN_TLS仍支持TLSv1,而在3.13.x中移至COMPATIBLE_TLS,对于3.14.x仍不确定。

即使使用当前版本的OkHttp3,也可以将所需的TLS 1.0协议添加到ConnectionSpec.COMPATIBLE_TLS,因为这是一个具有.add()方法的ArrayList - 但不能保证不会有进一步的不兼容性;3.12.x 可能仍然是支持从 Android 4.x 开始的最佳选择,甚至可能会有新功能的后移植。


1
最后一段是错误的。您可以指示OkHttp使用COMPATIBLE_TLS,请参见https://github.com/square/okhttp/wiki/HTTPS。这应该适用于TLS 1.0。请注意,如果使用比OkHttp 3.12更新的版本,则需要小心,因为那是支持Android 4.x及更早版本的最后一个版本。 - aha
1
@aha 3.12.x版本的MODERN_TLS仍支持TLSv1,而在3.13.x中已添加到COMPATIBLE_TLS中...因此此问题仅适用于默认配置的MODERN_TLS。版本3.13.x应该仍然可以工作,只要不使用默认配置;对于3.14.x不太确定。 - Martin Zeitler

8
如果您使用的是Android 9(Pie)或Android SDK 28以上版本,且在通过Retrofit进行API调用时遇到问题。
请将以下行添加到您的清单中:android:usesCleartextTraffic="true" Retrofit问题

好的,但我们只需要这个配置来连接没有SSL(http)的API。 - viper
属性 usesCleartextTraffic 仅在 API 级别 23 及以上版本中使用。 - Arpit J.

1

Android 21之前存在一些缺失的SSL,因此Retrofit无法工作。使用Google服务,您可以更新设备协议,之后HTTP请求将正常工作。

    //compile 'com.google.android.gms:play-services-base:11.0.0'
     //remember to add the library in your dependencies

        //compile 'com.google.android.gms:play-services-base:$currentVersion'

        ProviderInstaller.installIfNeededAsync(this, new ProviderInstallListener() {

            @Override

            public void onProviderInstalled() {

                //Do your http request here

            }


            @Override

            public void onProviderInstallFailed(int errorCode, Intent recoveryIntent) {

                //sad face :C is sad

            }

        });


文档 https://developer.android.com/training/articles/security-gms-provider 和完整讨论 https://github.com/square/okhttp/issues/2372 。也许我错过了什么,请友善地指出 @MartinZeitler。 - cutiko
3
我猜@cutiko提到的是在KitKat之前,Android系统不支持TLS 1.2。请参考以下链接了解如何在Android 4.4及更低版本中使用TLS 1.2:https://medium.com/tech-quizlet/working-with-tls-1-2-on-android-4-4-and-lower-f4f5205629a - madlymad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接