美文网首页NetAndroid知识Android开发经验谈
Android 4.x 在 https 协议下无法利用 okht

Android 4.x 在 https 协议下无法利用 okht

作者: ayuhani | 来源:发表于2017-06-28 10:10 被阅读183次

    最近公司项目迁移了服务器,同样的也由 http 变成了 https 协议。不过调试的时候发现 4.x 的设备都无法进行访问网络了,5.0 及以上的设备没有遇到问题。百度许久未果,在 google 上找到了答案。
    原文地址:https://github.com/square/okhttp/issues/2372

    解决方法如下:

    1.添加以下内容的Tls12SocketFactory.java

    import java.io.IOException;
    import java.net.InetAddress;
    import java.net.Socket;
    import java.net.UnknownHostException;
    
    import javax.net.ssl.SSLSocket;
    import javax.net.ssl.SSLSocketFactory;
    
    /**
     * Enables TLS v1.2 when creating SSLSockets.
     * <p/>
     * For some reason, android supports TLS v1.2 from API 16, but enables it by
     * default only from API 20.
     * @link https://developer.android.com/reference/javax/net/ssl/SSLSocket.html
     * @see SSLSocketFactory
     */
    public class Tls12SocketFactory extends SSLSocketFactory {
        private static final String[] TLS_V12_ONLY = {"TLSv1.2"};
    
        final SSLSocketFactory delegate;
    
        public Tls12SocketFactory(SSLSocketFactory base) {
            this.delegate = base;
        }
    
        @Override
        public String[] getDefaultCipherSuites() {
            return delegate.getDefaultCipherSuites();
        }
    
        @Override
        public String[] getSupportedCipherSuites() {
            return delegate.getSupportedCipherSuites();
        }
    
        @Override
        public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
            return patch(delegate.createSocket(s, host, port, autoClose));
        }
    
        @Override
        public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
            return patch(delegate.createSocket(host, port));
        }
    
        @Override
        public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
            return patch(delegate.createSocket(host, port, localHost, localPort));
        }
    
        @Override
        public Socket createSocket(InetAddress host, int port) throws IOException {
            return patch(delegate.createSocket(host, port));
        }
    
        @Override
        public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
            return patch(delegate.createSocket(address, port, localAddress, localPort));
        }
    
        private Socket patch(Socket s) {
            if (s instanceof SSLSocket) {
                ((SSLSocket) s).setEnabledProtocols(TLS_V12_ONLY);
            }
            return s;
        }
    }
    

    2.在代码中添加下面的方法

    public static OkHttpClient.Builder enableTls12OnPreLollipop(OkHttpClient.Builder client) {
        if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT < 22) {
            try {
                SSLContext sc = SSLContext.getInstance("TLSv1.2");
                sc.init(null, null, null);
                client.sslSocketFactory(new Tls12SocketFactory(sc.getSocketFactory()));
    
                ConnectionSpec cs = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
                        .tlsVersions(TlsVersion.TLS_1_2)
                        .build();
    
                List<ConnectionSpec> specs = new ArrayList<>();
                specs.add(cs);
                specs.add(ConnectionSpec.COMPATIBLE_TLS);
                specs.add(ConnectionSpec.CLEARTEXT);
    
                client.connectionSpecs(specs);
            } catch (Exception exc) {
                Log.e("OkHttpTLSCompat", "Error while setting TLS 1.2", exc);
            }
        }
        
        return client;
    }
    

    3.最后在实例化okhttp客户端的时候,作类似如下的处理

    private OkHttpClient getNewHttpClient() {
        OkHttpClient.Builder client = new OkHttpClient.Builder()
                .followRedirects(true)
                .followSslRedirects(true)
                .retryOnConnectionFailure(true)
                .cache(null)
                .connectTimeout(5, TimeUnit.SECONDS)
                .writeTimeout(5, TimeUnit.SECONDS)
                .readTimeout(5, TimeUnit.SECONDS);
    
        return enableTls12OnPreLollipop(client).build();
    }
    

    采用了上面的方法后,4.x 的设备也可以正常的进行网络访问了,不过又遇到了新的坑。在 4.x 下,第三方的图片加载框架,无论是 glide 还是 imageloader,都无法正常加载。看来这是网站配置证书的问题,毕竟用的是免费证书,遇到问题也不足为怪了。

    欢迎关注我的微信公众号

    相关文章

      网友评论

      • 倔强的炉包:Glide需要自定义glidemoudle 并在androidMainifest文件注册。
        ayuhani: @倔强的炉包 谢谢,回去试试🙂

      本文标题:Android 4.x 在 https 协议下无法利用 okht

      本文链接:https://www.haomeiwen.com/subject/iwaycxtx.html