OkHttp 3.X on Android 4.4.4
Feb 27, 2017
2 minute read

    This morning I was greeted at work by an unexpectedly-large number of crashes from a new Android release. As it happens, OkHttp 3.X has issues on Android 4.4.4 and 4.4.2 - it cannot reliably load the system’s default TrustManagers without looping and eventually crashing with an OutOfMemoryError. The fix was simple - we can reliably load it ourselves, and provide it to new OkHttpClient instances. For posterity, the solution we hit on follows below:

    TrustManagerFactory tmf;
    try {
      String defaultAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
      tmf = TrustManagerFactory.getInstance(defaultAlgorithm);
    } catch (NoSuchAlgorithmException e) {
      // The system *just* gave us this algo name :(
      throw new AssertionError(e); // no helping this one.
    }
    
    try {
      tmf.init((KeyStore) null); // null == system default keystore
    } catch (KeyStoreException e) {
      throw new AssertionError(e); // again, no helping this one.
    }
    
    X509TrustManager trustManager = null;
    for (TrustManager tm : tmf.getTrustManagers()) {
      if (tm instanceof X509TrustManager) {
        trustManager = (X509TrustManager) tm;
        break;
      }
    }
    
    if (trustManager == null) {
      throw new AssertionError("The system is not capable of handling X509 certificates - lol");
    }
    
    SSLSocketFactory ssf = (SSLSocketFactory) SSLSocketFactory.getDefault()
    
    // Finally!  With the SSL socket factory and the X509 trust manager,
    // we can safely build our HTTP client instance.
    OkHttpClient client = new OkHttpClient.Builder()
        .sslSocketFactory(ssf, trustManager) 
        .build();
    

    Of course, you won’t want to do this more than once, but ideally you’re already using a singleton client instance and are reaping the benefits of connection-pooling, a smaller memory footprint, etc.

    Hopefully this helps someone - even me, a year from now.