有时候为了app的数据安全,开发者会考虑使用https来进行数据传输。在安卓上,原生的HttpsURLConnection和WebView只支持那些得到安卓系统承认的证书的站点。如果请求那些使用未通过系统认证的证书的站点,则系统会报错。对于个人开发者来说,申请正规的证书性价比不高,每年都需要不少的费用,而且开发阶段会被申请流程阻塞,所以使用自定义的证书就好。现在的问题是怎么让app绕过系统的证书认证,从而接受自定义的证书。
HttpsURLConnection
该例程是参考别人的代码修改而来的,下载一个线程里面。可以验证特定的证书。该证书应保存一个副本在app本地上(assets),保存为.crt格式。至于怎样生成自定义的证书,请Google。其中一个内部类实现了HostnameVerifier接口,可以验证特定主机名,以匹配hostname和证书。这里的实现是不对主机名进行验证,默认接受持有该证书所有的主机。
@Override
public void run(){
HttpsURLConnection urlConnection = null;
try {
URL url = new URL(Constant.update_url);
//https
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream in = context.getAssets().open("ca.crt");
Certificate ca = cf.generateCertificate(in);
// Create a KeyStore containing our trusted CAsString keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
HttpsURLConnection.setDefaultHostnameVerifier(new MyHostnameVerifier());
urlConnection = (HttpsURLConnection)url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
urlConnection.setRequestMethod("GET");
urlConnection.connect();
String data = ReceiveRequestData.responseData(urlConnection);
}catch (Exception e){
e.printStackTrace();
}finally {
}
}
private class MyHostnameVerifier implements HostnameVerifier {
@Override
public boolean verify(String hostname, SSLSession session) {
// TODO Auto-generated method stub
return true;
}
}
WebView
如果需要验证特定的证书,WebView上没有很好的办法。看了网上的解决方案,是说找到WebViewClient的隐藏方法并重写,但因为是隐藏方法,需要找到编译包,工程量较大。如果是开发阶段的话,不妨使用接受所有证书的方法,代码也比较简单。
</pre>新建一个类并继承WebViewClient,重写里面的onReceivedSslError方法:</p><p><pre name="code" class="java">private class MyWebViewClient extends WebViewClient{
public MyWebViewClient(WebView webView) {
super(webView);
}
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error){
//handler.cancel(); // Android默认的处理方式
handler.proceed(); // 接受所有网站的证书
//handleMessage(Message msg); // 进行其他处理
}
}
然后为WebView对象设置Client
mainView.setWebViewClient(new MyWebViewClient(mainView));