Retrofit not working on specific versions of android

11,614

Solution 1

It reads java.net.SocketTimeoutException, which at first suggests to raise the client's connect-timeout value, as it is being explained in this answer - but when reviewing the current source code of okhttp3.internal.platform.AndroidPlatform... this rather hints for incompatible protocols.

The server's SSL certificate supports TLS 1.0, as it would be required for Android 4.x (there's no problem on their side); the problem rather is, that the current version of OkHttp3 does not support TLS 1.0 anymore and therefore the handshake won't ever take place (that's why it throws such a misleading SocketTimeoutException instead of a SSLHandshakeException).


With OkHttp3 3.12.x, it should still be supported with the default configuration MODERN_TLS -

but one could instruct OkHttp3 3.13.x to use configuration COMPATIBLE_TLS instead:

/* 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();

One also has to set it as the client for Retrofit:

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

See the TLS Configuration History for the available protocol support, per OkHttp3 version. As it seems, 3.12.x even already supports TLS 1.3, as it will in future be required for Android Q. It might not even be required to down-grade OkHttp3, because MODERN_TLS of 3.12.x still supports TLSv1, while in 3.13.x it had been moved into COMPATIBLE_TLS; still uncertain about 3.14.x.

Even with current versions of OkHttp3, one could possibly still add the desired TLS 1.0 protocol back into ConnectionSpec.COMPATIBLE_TLS, since this is an ArrayList with a method .add() - without any guarantee, that there won't be further incompatibilities; 3.12.x might still be the best choice for supporting Android 4.x onward and there might even be back-ports of newer features.

Solution 2

If you use android 9 (Pie) or android SDK above 28 and get the issue on over the api call through Retrofit.

Add this line to your manifest android:usesCleartextTraffic="true"
Retrofit Issue

Solution 3

Android prior to 21 has some missing SSL and Retrofit wont work. Using google services you can update the device protocols after that the HTTP request will work

    //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

            }

        });

Share:
11,614
SaNtoRiaN
Author by

SaNtoRiaN

Interested in Java, android programming and learning new languages.

Updated on June 24, 2022

Comments

  • SaNtoRiaN
    SaNtoRiaN almost 2 years

    I have a problem with Retrofit on my emulator running Android 4.3 and my device is on Android 4.4.2 while the same code runs normally on another emulator with Android 7.1.1

    Each time I try to execute the get request I get a timeout exception.

    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)
    

    The code is below

    public interface Api {
        String BASE_URL = "https://jsonplaceholder.typicode.com/";
    
        @GET("posts")
        Call<ArrayList<Post>> getPosts();
    }
    

    and the call to the 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);
        }
    });
    
  • aha
    aha about 5 years
    The last paragraph is wrong. You can instruct OkHttp to use COMPATIBLE_TLS, see github.com/square/okhttp/wiki/HTTPS. That should work with TLS 1.0. Beware that you use anything newer than OkHttp 3.12 because that's the last one that supports Android 4.x and earlier.
  • cutiko
    cutiko about 5 years
    Docs developer.android.com/training/articles/security-gms-provide‌​r and full discussion github.com/square/okhttp/issues/2372 Maybe Im missing somethinf, be kind to point out please @MartinZeitler
  • madlymad
    madlymad about 5 years
    I would guess that @cutiko refers to the fact that before KitKat there wasn't support for TLS 1.2 medium.com/tech-quizlet/…
  • Martin Zeitler
    Martin Zeitler about 5 years
    @aha MODERN_TLS of 3.12.x still supports TLSv1, while in 3.13.x it had been added into COMPATIBLE_TLS... so this problem only applies to the default configuration MODERN_TLS. version 3.13.x should still work, while not using the default configuration; not that certain about 3.14.x.
  • viper
    viper over 4 years
    Okay but we need this configuration only to connect with api without SSL (http)
  • Arpit J.
    Arpit J. almost 3 years
    Attribute usesCleartextTraffic is only used in API level 23 and higher