前言:
参考了org.sandrob.sslexample和http://blog.csdn.net/mingli198611/article/details/9233705的实现方式,结合实际情况才完成该技术难题,现在分享一下我的实现方案来弥补这方面的空白。
正文:
1.android 4.0(不包含)以下版本的实现方法:
1.1 书写认证
- private SSLContext createSSLContext() {
- SSLContext localSSLContext = null;
- try {
- // 创建一个证书库,并将证书导入证书库
- KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC");
- keyStore.load(
- mContext.getResources().openRawResource(R.raw.client),//client 是*.pfx文件
- CERTFILE_PASSWORD.toCharArray());//CERTFILE_PASSWORD 为你的证书的密码
- KeyManagerFactory localKeyManagerFactory = KeyManagerFactory
- .getInstance(KeyManagerFactory.getDefaultAlgorithm());
- localKeyManagerFactory.init(keyStore,
- CERTFILE_PASSWORD.toCharArray());
- KeyManager[] arrayOfKeyManager = localKeyManagerFactory
- .getKeyManagers();
- localSSLContext = SSLContext.getInstance("TLS");
- localSSLContext.init(arrayOfKeyManager, trustAllCerts,
- new SecureRandom());
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- return localSSLContext;
- }
- /**
- * 设置webview的ssl双向认证
- * 注意:改方法只支持android4.0(不包含)一下
- * 该方法调用一次即可
- * <P>Author : mingli </P>
- * <P>Date : 2013-7-2 </P>
- */
- public boolean setWebViewSSLCert() {
- boolean issuc = false;// true 代表验证和设置成功
- if (Build.VERSION.SDK_INT >= 14){
- return issuc;
- }
- try {
- Field[] arrayOfField = Class.forName(
- "android.net.http.HttpsConnection").getDeclaredFields();
- for (Field localField : arrayOfField) {
- if (localField.getName().equals("mSslSocketFactory")) {//采用反射的方式修改mSslSocketFactory变量
- localField.setAccessible(true);
- localField.set(null,createSSLContext().getSocketFactory());
- issuc = true;
- break;
- }
- }
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- return issuc;
- }
1.2 调用
在webview初始化或者application 等,需要用https认证的地方调用 setWebViewSSLCert方法即可。
2.android 4.0(包含)以上版本的实现方法:
2.1 书写认证
- private X509Certificate[] mX509Certificates;
- private PrivateKey mPrivateKey;
- private void initPrivateKeyAndX509Certificate()
- throws Exception {
- KeyStore keyStore;
- // 创建一个证书库,并将证书导入证书库
- KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC");
- keyStore.load(
- mContext.getResources().openRawResource(R.raw.client),
- CERTFILE_PASSWORD.toCharArray());
- Enumeration<?> localEnumeration;
- localEnumeration = keyStore.aliases();
- while (localEnumeration.hasMoreElements()) {
- String str3 = (String) localEnumeration.nextElement();
- mPrivateKey = (PrivateKey) keyStore.getKey(str3,
- CERTFILE_PASSWORD.toCharArray());
- if (mPrivateKey == null) {
- continue;
- } else {
- Certificate[] arrayOfCertificate = keyStore
- .getCertificateChain(str3);
- mX509Certificates = new X509Certificate[arrayOfCertificate.length];
- for (int j = 0; j < mX509Certificates.length; j++) {
- mX509Certificates[j] = ((X509Certificate) arrayOfCertificate[j]);
- }
- }
- }
- }
- public class BasicWebViewClientEx extends WebViewClient {
- private X509Certificate[] certificatesChain;
- private PrivateKey clientCertPrivateKey;
- public BasicWebViewClientEx(AbstractActivity activity) {
- mActivity = activity;
- certificatesChain = getX509Certificates();//此处就是上文中的mX509Certificates
- clientCertPrivateKey = getPrivateKey();//次处就是上文中的mPrivateKey
- }
- public void onReceivedClientCertRequest(WebView view,
- ClientCertRequestHandler handler, String host_and_port) {
- //注意该方法是调用的隐藏函数接口。这儿是整个验证的技术难点:就是如何调用隐藏类的接口。
- //方法:去下载一个android4.2版本全编译后的class.jar 然后导入到工程中
- if((null != clientCertPrivateKey) && ((null!=certificatesChain) && (certificatesChain.length !=0))){
- handler.proceed(this.clientCertPrivateKey, this.certificatesChain);
- }else{
- handler.cancel();
- }
- }
- @Override
- public void onReceivedSslError(final WebView view, SslErrorHandler handler,
- SslError error) {
- handler.proceed();
- }
- }
2.2 调用
mWebView.setWebViewClient(new BasicWebViewClientEx());
2.3 编译
方案一:到android 4.2 源码环境下编译
方案二:(推荐)
1.去下载一个全编译的class.jar(http://download.csdn.net/detail/sfhong2008/5506219)
2.把该class.jar导入工程。步骤如下:(http://www.linuxidc.com/Linux/2012-02/54978.htm)
使用Eclipse,Android工程添加library(BuildPath -> Add Libraries->User Library->New User Library),将.jar文件加入添加到library,同时勾选“SystemLibrary”选项,www.linuxidc.com 以避免产生“java.lang.OutOfMemoryError:Java Heap Space”错误。如果已经正确导入了jar库,却仍然找不到隐藏的API。原因可能是Buildclass path order不正确,即android.jar和classes.jar的导入顺序不对,具体调节Buildclass path order,选择Build Path-> Config Build Path->Order and Export,调整自定义的library与android.jar的顺序。
3.编译
方案二:(推荐)
1.去下载一个全编译的class.jar(http://download.csdn.net/detail/sfhong2008/5506219)
2.把该class.jar导入工程。步骤如下:(http://www.linuxidc.com/Linux/2012-02/54978.htm)
使用Eclipse,Android工程添加library(BuildPath -> Add Libraries->User Library->New User Library),将.jar文件加入添加到library,同时勾选“SystemLibrary”选项,www.linuxidc.com 以避免产生“java.lang.OutOfMemoryError:Java Heap Space”错误。如果已经正确导入了jar库,却仍然找不到隐藏的API。原因可能是Buildclass path order不正确,即android.jar和classes.jar的导入顺序不对,具体调节Buildclass path order,选择Build Path-> Config Build Path->Order and Export,调整自定义的library与android.jar的顺序。
3.编译