公司因为网络安全的问题,将http协议换成了https协议,之前使用的okhttputils包在4.4.4以下的安卓系统中访问https协议的接口会报错,提示我因为没有ssl协议的问题。
起初我以为是我自己的框架问题,因为用习惯了okhttpuitls框架,不想更换。就去github上面查找了(推荐dependencies在添加github上面的托管项目,而不要下载一个第三方项目去关联,因为在github上面会有维护,而且这样子代码看起来整洁。一般挑选框架,直接搜索之后选择星星最多的就好了。一般都是好东西),发现上面星星数量最多的是样神的。链接https://github.com/hongyangAndroid/okhttputils。按照上面所说的初始化兼容https的方法,发现还是无法在安卓4.4.4以下的系统中访问https。
于是我去网上查找了一个SSl协议的工具类(以下工具类直接复制使用就好)
package com.baosheng.boosoo_ktv.Util; import android.os.Build; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; import java.security.GeneralSecurityException; import java.util.Arrays; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.X509TrustManager; /** * Created by kkk on 2017/5/12. * 让安卓4.4.4以下的系统支持TLS协议,方法加入okhttp中 */ public class SSLSocketFactoryCompat extends SSLSocketFactory { private SSLSocketFactory defaultFactory; // Android 5.0+ (API level21) provides reasonable default settings // but it still allows SSLv3 // https://developer.android.com/about/versions/android-5.0-changes.html#ssl static String protocols[] = null, cipherSuites[] = null; static { try { SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket(); if (socket != null) { /* set reasonable protocol versions */ // - enable all supported protocols (enables TLSv1.1 and TLSv1.2 on Android <5.0) // - remove all SSL versions (especially SSLv3) because they're insecure now List<String> protocols = new LinkedList<>(); for (String protocol : socket.getSupportedProtocols()) if (!protocol.toUpperCase().contains("SSL")) protocols.add(protocol); SSLSocketFactoryCompat.protocols = protocols.toArray(new String[protocols.size()]); /* set up reasonable cipher suites */ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { // choose known secure cipher suites List<String> allowedCiphers = Arrays.asList( // TLS 1.2 "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECHDE_RSA_WITH_AES_128_GCM_SHA256", // maximum interoperability "TLS_RSA_WITH_3DES_EDE_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", // additionally "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"); List<String> availableCiphers = Arrays.asList(socket.getSupportedCipherSuites()); // take all allowed ciphers that are available and put them into preferredCiphers HashSet<String> preferredCiphers = new HashSet<>(allowedCiphers); preferredCiphers.retainAll(availableCiphers); /* For maximum security, preferredCiphers should *replace* enabled ciphers (thus disabling * ciphers which are enabled by default, but have become unsecure), but I guess for * the security level of DAVdroid and maximum compatibility, disabling of insecure * ciphers should be a server-side task */ // add preferred ciphers to enabled ciphers HashSet<String> enabledCiphers = preferredCiphers; enabledCiphers.addAll(new HashSet<>(Arrays.asList(socket.getEnabledCipherSuites()))); SSLSocketFactoryCompat.cipherSuites = enabledCiphers.toArray(new String[enabledCiphers.size()]); } } } catch (IOException e) { throw new RuntimeException(e); } } public SSLSocketFactoryCompat(X509TrustManager tm) { try { SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, (tm != null) ? new X509TrustManager[] { tm } : null, null); defaultFactory = sslContext.getSocketFactory(); } catch (GeneralSecurityException e) { throw new AssertionError(); // The system has no TLS. Just give up. } } private void upgradeTLS(SSLSocket ssl) { // Android 5.0+ (API level21) provides reasonable default settings // but it still allows SSLv3 // https://developer.android.com/about/versions/android-5.0-changes.html#ssl if (protocols != null) { ssl.setEnabledProtocols(protocols); } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && cipherSuites != null) { ssl.setEnabledCipherSuites(cipherSuites); } } @Override public String[] getDefaultCipherSuites() { return cipherSuites; } @Override public String[] getSupportedCipherSuites() { return cipherSuites; } @Override public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { Socket ssl = defaultFactory.createSocket(s, host, port, autoClose); if (ssl instanceof SSLSocket) upgradeTLS((SSLSocket)ssl); return ssl; } @Override public Socket createSocket(String host, int port) throws IOException, UnknownHostException { Socket ssl = defaultFactory.createSocket(host, port); if (ssl instanceof SSLSocket) upgradeTLS((SSLSocket)ssl); return ssl; } @Override public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { Socket ssl = defaultFactory.createSocket(host, port, localHost, localPort); if (ssl instanceof SSLSocket) upgradeTLS((SSLSocket)ssl); return ssl; } @Override public Socket createSocket(InetAddress host, int port) throws IOException { Socket ssl = defaultFactory.createSocket(host, port); if (ssl instanceof SSLSocket) upgradeTLS((SSLSocket)ssl); return ssl; } @Override public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { Socket ssl = defaultFactory.createSocket(address, port, localAddress, localPort); if (ssl instanceof SSLSocket) upgradeTLS((SSLSocket)ssl); return ssl; } }然后在Application初始化这个ssl协议进入okhttputils框架中
/* 初始化添加ssl协议(解决安卓4.4.4中okhttp不能访问https的问题) */ private void intiSSL() { // 自定义一个信任所有证书的TrustManager final X509TrustManager trustAllCert = new X509TrustManager() { @Override public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { } @Override public java.security.cert.X509Certificate[] getAcceptedIssuers() { return new java.security.cert.X509Certificate[]{}; } }; final SSLSocketFactory sslSocketFactory = new SSLSocketFactoryCompat(trustAllCert); HttpsUtils.SSLParams sslParams = HttpsUtils.getSslSocketFactory(null, null, null); OkHttpClient okHttpClient = new OkHttpClient.Builder() .sslSocketFactory(sslSocketFactory, trustAllCert) //其他配置 .build(); OkHttpUtils.initClient(okHttpClient); }顺利的解决了这个问题。随便符下一些其他的代码,如果访问过程中有出错,可以对照我这边的代码。
OkHttpUtils.get() .url("https:...") .build() .execute(new UpdateCallBack() { @Override public void onError(Call call, Exception e, int id) { Log.e("onError", e.getMessage()); } @Override public void onResponse(Updateinfo response, int id) { Log.e("onResponse", response.getData().getApkurl()); } });
package com.baosheng.boosoo_ktv.Httpcallbcak; import com.baosheng.boosoo_ktv.info.Updateinfo; import com.google.gson.Gson; import com.zhy.http.okhttp.callback.Callback; import java.io.IOException; import okhttp3.Response; /** * Created by Administrator on 2016/6/12. */ public abstract class UpdateCallBack extends Callback<Updateinfo> { public Updateinfo parseNetworkResponse(Response response, int id) throws IOException { String string = response.body().string(); Updateinfo goods = new Gson().fromJson(string, Updateinfo.class); return goods; } }
package com.baosheng.boosoo_ktv.info; /** * Created by kkk on 2017/5/12. */ public class Updateinfo { /** * data : {"apkurl":"http://singerimg.cavca.net/4c316e7c26c34d68b85f6da2e11d7a00.apk","desic":"1.发生的。2.12132231。3.阿斯顿发生。4.打撒","isenforce":0,"title":"版本更新","version":"1.3"} * msg : success * status_code : 200 */ private DataBean data; private String msg; private String status_code; public DataBean getData() { return data; } public void setData(DataBean data) { this.data = data; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public String getStatus_code() { return status_code; } public void setStatus_code(String status_code) { this.status_code = status_code; } public static class DataBean { /** * apkurl : http://singerimg.cavca.net/4c316e7c26c34d68b85f6da2e11d7a00.apk * desic : 1.发生的。2.12132231。3.阿斯顿发生。4.打撒 * isenforce : 0 * title : 版本更新 * version : 1.3 */ private String apkurl; private String desic; private int isenforce; private String title; private String version; public String getApkurl() { return apkurl; } public void setApkurl(String apkurl) { this.apkurl = apkurl; } public String getDesic() { return desic; } public void setDesic(String desic) { this.desic = desic; } public int getIsenforce() { return isenforce; } public void setIsenforce(int isenforce) { this.isenforce = isenforce; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } } }