前言
在Android开发中,Okhttp想必大家都不陌生,一个处理网络请求的开源项目,是安卓端最火热的轻量级框架。
本人在开发过程中也用了很长一段时间了,但是基本请求的都是http接口。即使访问https网站也都是绿色的,有个很特殊的大型购票网站则不是,所以本文主要介绍如何使用Okhttp访问自签名证书的https接口。而且公司自己服务接口也全部换成了https接口,在去年就说ios要强制更换https接口,不然appstore无法上架,最近好像也没信了,估计是政策放宽了吧。不管怎样,今天就拿这个大型购票网站举例来说,使用Okhttp访问购票网站。
获取签名证书
购票网站的签名证书可以在官网上直接下载,或者点击这里下载即可。srca.cer即为购票网站的签名证书。
为了方便将签名证书添加到OkHttp中,可以将签名证书放在本地的assets文件夹下,为了便于管理我放在了assets/cers目录下,在代码中可以通过流的形式获取到证书文件。
添加证书一般是在访问接口之前添加,为了方便,我放在了Application中,这样的话,在应用启动的时候就会已经将添加添加到了OkHttp中。
使用Okhttp访问接口
- 使用Android Studio的话,直接添加Okhttp的依赖:
compile 'com.squareup.okhttp3:okhttp:3.3.1'
- 获取签名证书文件流
//获取证书流
private void readHttpsCer() {
try {
InputStream is = getAssets().open("cers/srca.cer");
NetConfig.addCertificate(is); // 这里将证书读取出来,,放在配置中byte[]里
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
- NetConfig相关代码:
// 证书数据
private static List<byte[]> CERTIFICATES_DATA = new ArrayList<>();
/**
* 添加https证书
*
* @param inputStream
*/
public synchronized static void addCertificate(InputStream inputStream) {
Log.i(TAG, "#addCertificate inputStream = " + inputStream);
if (inputStream != null) {
try {
int ava = 0;// 数据当次可读长度
int len = 0;// 数据总长度
ArrayList<byte[]> data = new ArrayList<>();
while ((ava = inputStream.available()) > 0) {
byte[] buffer = new byte[ava];
inputStream.read(buffer);
data.add(buffer);
len += ava;
}
byte[] buff = new byte[len];
int dstPos = 0;
for (byte[] bytes : data) {
int length = bytes.length;
System.arraycopy(bytes, 0, buff, dstPos, length);
dstPos += length;
}
CERTIFICATES_DATA.add(buff);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* https证书
*
* @return
*/
public static List<byte[]> getCertificatesData() {
return CERTIFICATES_DATA;
}
- 编写工具类,将证书添加到OkHttp中:
public static OkHttpClient createOkHttp() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
// 添加证书
List<InputStream> certificates = new ArrayList<>();
List<byte[]> certs_data = NetConfig.getCertificatesData();
// 将字节数组转为数组输入流
if (certs_data != null && !certs_data.isEmpty()) {
for (byte[] bytes : certs_data) {
certificates.add(new ByteArrayInputStream(bytes));
}
}
SSLSocketFactory sslSocketFactory = getSocketFactory(certificates);
if (sslSocketFactory != null) {
builder.sslSocketFactory(sslSocketFactory);
}
return builder.build();
}
/**
* 添加证书
*
* @param certificates
*/
private static SSLSocketFactory getSocketFactory(List<InputStream> certificates) {
try {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
try {
for (int i = 0, size = certificates.size(); i < size; ) {
InputStream certificate = certificates.get(i);
String certificateAlias = Integer.toString(i++);
keyStore.setCertificateEntry(certificateAlias, certificateFactory
.generateCertificate(certificate));
if (certificate != null)
certificate.close();
}
} catch (IOException e) {
e.printStackTrace();
}
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManagerFactory trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
return sslContext.getSocketFactory();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
- 查看测试使用结果:
将自签名证书添加到Okhttp中,通过创建的OkHttpClient对象,我们就可以访问相关的Https接口服务了。