使用okhttp做爲網絡鏈接時,java
Okhttp現做爲Android網絡鏈接框架已經很流行了,我也使用okhttp有三年了。之前https仍是使用得少的,訪問別人的網站,若是使用了https都是綠色的(在瀏覽器上看,某購火車票網站的不是),在okhttp裏啥問題也沒有,最近的項目是公司本身的服務器使用了https,但證書不是購買的,是本身產生的(使用jdk自產的),okhttp默認拒絕訪問這自產證書的https的鏈接。數組
怎麼辦?查看okhttp說明,是能夠向okhttp裏添加證書的。下面是向okhttp添加證書的內容了。證書能夠瀏覽器上導出,導時選擇X509,導出結果的xxx.cer。瀏覽器
爲了方便各模塊添加本身的證書,各模塊把須要用到的證書都放在assets裏和同一路徑的目錄下(我放置的目錄爲assets/certs),Android Studio編譯時會把因此模塊裏的assets/cert統一塊兒來,到時遍歷這目錄就能讀取到全部證書了。服務器
添加證書,能夠在okhttp訪問網絡前,但我放置在Application.OnCreate裏,目的爲了讓okhttp使用時不用傳入Context,也不用Context滿天飛。網絡
讀取證書文件代碼以下:框架
// 添加https證書 try { String[] certFiles=this.getAssets().list("certs"); if (certFiles != null) { for (String cert:certFiles) { InputStream is = getAssets().open("certs/" + cert); NetConfig.addCertificate(is); // 這裏將證書讀取出來,,放在配置中byte[]裏 } } } catch (IOException ioe) { ioe.printStackTrace(); }
NetConfig的相關代碼:dom
// 證書數據 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 OkHttpClient createOkhttp() { OkHttpClient.Builder builder = new OkHttpClient.Builder(); // 添加證書 List<InputStream> certificates = new ArrayList<>(); List<String> certs = NetConfig.getCertificates(); 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; }
Ok,https就這樣了。ui