Android进阶——Volley+Https给你的安卓应用加上SSL证书

本文介绍如何通过修改Volley框架源码实现HTTPS访问,确保网络数据传输安全性。文中详细展示了如何构建信任证书并配置网络堆栈。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景 

     作为开发人员,我们需要对网络访问的安全性加以保证,这样才能在基本上保证我们的数据不受到修改和攻击。笔者的项目之前用的是Volley框架访问的网络,基于http协议。现在我们需要使用更为安全的https。https简单的理解就是http+ssl,对于SSL证书,自己签发也行,花钱购买也可以,孰优孰劣,大家自行百度了解。
     因为是基于Volley框架访问的网络,所以网上搜到的许多方法都不能用了,经过大量筛选测试,最靠谱的方法就是修改Volley源码了。

PASS

     刚开始想着下载个Volley的jar包,修改完毕再直接生成新的jar来使用,可是生成新jar后的签名和源jar包不一致,所以无法使用了。此方案PASS。

改源码

     后来直接下载Volley的zip包,( 点击下载,侵删)。先把它运行起来,(该Volley项目是用Android Studio写的),如果你的项目同样是Studio写的,那就比较省事了。笔者目前还用的是老旧的Eclipse,直接导入就行,差别也不太大。找到android.volley.toolbox下面的Volley.java文件,对里面的内容进行修改替换。替换后的代码如下:

Volley.java代码

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <pre name="code" class="java">/* 
  2.  * Copyright (C) 2012 The Android Open Source Project 
  3.  * 
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  * 
  8.  *      http://www.apache.org/licenses/LICENSE-2.0 
  9.  * 
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License. 
  15.  */  
  16.   
  17. package com.android.volley.toolbox;  
  18.   
  19. import android.content.Context;  
  20. import android.content.pm.PackageInfo;  
  21. import android.content.pm.PackageManager.NameNotFoundException;  
  22. import android.net.http.AndroidHttpClient;  
  23. import android.os.Build;  
  24.   
  25. import com.android.volley.RequestQueue;  
  26. import com.jiemi.waiterpad.R;  
  27.   
  28. import org.apache.http.client.HttpClient;  
  29. import org.apache.http.conn.scheme.PlainSocketFactory;  
  30. import org.apache.http.conn.scheme.Scheme;  
  31. import org.apache.http.conn.scheme.SchemeRegistry;  
  32. import org.apache.http.impl.client.DefaultHttpClient;  
  33. import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;  
  34. import org.apache.http.params.BasicHttpParams;  
  35. import org.apache.http.params.HttpParams;  
  36.   
  37. import java.io.File;  
  38. import java.io.IOException;  
  39. import java.io.InputStream;  
  40. import java.security.KeyManagementException;  
  41. import java.security.KeyStore;  
  42. import java.security.KeyStoreException;  
  43. import java.security.NoSuchAlgorithmException;  
  44. import java.security.UnrecoverableKeyException;  
  45. import java.security.cert.Certificate;  
  46. import java.security.cert.CertificateException;  
  47. import java.security.cert.CertificateFactory;  
  48.   
  49. import javax.net.ssl.SSLContext;  
  50. import javax.net.ssl.SSLSocketFactory;  
  51. import javax.net.ssl.TrustManagerFactory;  
  52.   
  53.   
  54. public class Volley {  
  55.   
  56.     /** 
  57.      * Default on-disk cache directory. 
  58.      */  
  59.     private static final String DEFAULT_CACHE_DIR = "volley";  
  60.     private static BasicNetwork network;  
  61.     private static RequestQueue queue;  
  62.   
  63.     private Context mContext;  
  64.   
  65.     /** 
  66.      * Creates a default instance of the worker pool and calls 
  67.      * {@link RequestQueue#start()} on it. 
  68.      * 
  69.      * @param context A {@link Context} to use for creating the cache dir. 
  70.      * @param stack   An {@link HttpStack} to use for the network, or null for 
  71.      *                default. 
  72.      * @return A started {@link RequestQueue} instance. 
  73.      */  
  74.     public static RequestQueue newRequestQueue(Context context,  
  75.                                                HttpStack stack, boolean selfSignedCertificate, int rawId) {  
  76.         File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);  
  77.   
  78.         String userAgent = "volley/0";  
  79.         try {  
  80.             String packageName = context.getPackageName();  
  81.             PackageInfo info = context.getPackageManager().getPackageInfo(  
  82.                     packageName, 0);  
  83.             userAgent = packageName + "/" + info.versionCode;  
  84.         } catch (NameNotFoundException e) {  
  85.         }  
  86.   
  87.         if (stack == null) {  
  88.             if (Build.VERSION.SDK_INT >= 9) {  
  89.                 if (selfSignedCertificate) {  
  90.                     stack = new HurlStack(null, buildSSLSocketFactory(context,  
  91.                             rawId));  
  92.                 } else {  
  93.                     stack = new HurlStack();  
  94.                 }  
  95.             } else {  
  96.                 // Prior to Gingerbread, HttpUrlConnection was unreliable.  
  97.                 // See:  
  98.                 // http://android-developers.blogspot.com/2011/09/androids-http-clients.html  
  99.                 if (selfSignedCertificate)  
  100.                     stack = new HttpClientStack(getHttpClient(context, rawId));  
  101.                 else {  
  102.                     stack = new HttpClientStack(  
  103.                             AndroidHttpClient.newInstance(userAgent));  
  104.                 }  
  105.             }  
  106.         }  
  107.   
  108.         //此处是坑啊,network和queue 是static的,不用一直new  
  109.         if (network == null) {  
  110.             network = new BasicNetwork(stack);  
  111.         }  
  112.         if (queue == null) {  
  113.             queue = new RequestQueue(new DiskBasedCache(cacheDir),network);  
  114.         }  
  115.         queue.start();  
  116.   
  117.         return queue;  
  118.     }  
  119.   
  120.     /** 
  121.      * Creates a default instance of the worker pool and calls 
  122.      * {@link RequestQueue#start()} on it. 
  123.      * 
  124.      * @param context A {@link Context} to use for creating the cache dir. 
  125.      * @return A started {@link RequestQueue} instance. 
  126.      */  
  127.     public static RequestQueue newRequestQueue(Context context) {  
  128.         // 如果你目前还没有证书,那么先用下面的这行代码,http可以照常使用.  
  129.         //       return newRequestQueue(context, null, false, 0);  
  130.         // 此处R.raw.certificateName 表示你的证书文件,替换为自己证书文件名字就好  
  131.         return newRequestQueue(context, nulltrue, R.raw.jiemica);  
  132.     }  
  133.   
  134.     private static SSLSocketFactory buildSSLSocketFactory(Context context,  
  135.                                                           int certRawResId) {  
  136.         KeyStore keyStore = null;  
  137.         try {  
  138.             keyStore = buildKeyStore(context, certRawResId);  
  139.         } catch (KeyStoreException e) {  
  140.             e.printStackTrace();  
  141.         } catch (CertificateException e) {  
  142.             e.printStackTrace();  
  143.         } catch (NoSuchAlgorithmException e) {  
  144.             e.printStackTrace();  
  145.         } catch (IOException e) {  
  146.             e.printStackTrace();  
  147.         }  
  148.   
  149.         String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();  
  150.         TrustManagerFactory tmf = null;  
  151.         try {  
  152.             tmf = TrustManagerFactory.getInstance(tmfAlgorithm);  
  153.             tmf.init(keyStore);  
  154.   
  155.         } catch (NoSuchAlgorithmException e) {  
  156.             e.printStackTrace();  
  157.         } catch (KeyStoreException e) {  
  158.             e.printStackTrace();  
  159.         }  
  160.   
  161.         SSLContext sslContext = null;  
  162.         try {  
  163.             sslContext = SSLContext.getInstance("TLS");  
  164.         } catch (NoSuchAlgorithmException e) {  
  165.             e.printStackTrace();  
  166.         }  
  167.         try {  
  168.             sslContext.init(null, tmf.getTrustManagers(), null);  
  169.         } catch (KeyManagementException e) {  
  170.             e.printStackTrace();  
  171.         }  
  172.   
  173.         return sslContext.getSocketFactory();  
  174.   
  175.     }  
  176.   
  177.     private static HttpClient getHttpClient(Context context, int certRawResId) {  
  178.         KeyStore keyStore = null;  
  179.         try {  
  180.             keyStore = buildKeyStore(context, certRawResId);  
  181.         } catch (KeyStoreException e) {  
  182.             e.printStackTrace();  
  183.         } catch (CertificateException e) {  
  184.             e.printStackTrace();  
  185.         } catch (NoSuchAlgorithmException e) {  
  186.             e.printStackTrace();  
  187.         } catch (IOException e) {  
  188.             e.printStackTrace();  
  189.         }  
  190.         if (keyStore != null) {  
  191.         }  
  192.         org.apache.http.conn.ssl.SSLSocketFactory sslSocketFactory = null;  
  193.         try {  
  194.             sslSocketFactory = new org.apache.http.conn.ssl.SSLSocketFactory(  
  195.                     keyStore);  
  196.         } catch (NoSuchAlgorithmException e) {  
  197.             e.printStackTrace();  
  198.         } catch (KeyManagementException e) {  
  199.             e.printStackTrace();  
  200.         } catch (KeyStoreException e) {  
  201.             e.printStackTrace();  
  202.         } catch (UnrecoverableKeyException e) {  
  203.             e.printStackTrace();  
  204.         }  
  205.   
  206.         HttpParams params = new BasicHttpParams();  
  207.   
  208.         SchemeRegistry schemeRegistry = new SchemeRegistry();  
  209.         schemeRegistry.register(new Scheme("http", PlainSocketFactory  
  210.                 .getSocketFactory(), 80));  
  211.         schemeRegistry.register(new Scheme("https", sslSocketFactory, 443));  
  212.   
  213.         ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(  
  214.                 params, schemeRegistry);  
  215.   
  216.         return new DefaultHttpClient(cm, params);  
  217.     }  
  218.   
  219.     private static KeyStore buildKeyStore(Context context, int certRawResId)  
  220.             throws KeyStoreException, CertificateException,  
  221.             NoSuchAlgorithmException, IOException {  
  222.         String keyStoreType = KeyStore.getDefaultType();  
  223.         KeyStore keyStore = KeyStore.getInstance(keyStoreType);  
  224.         keyStore.load(nullnull);  
  225.   
  226.         Certificate cert = readCert(context, certRawResId);  
  227.         keyStore.setCertificateEntry("ca", cert);  
  228.   
  229.         return keyStore;  
  230.     }  
  231.   
  232.     private static Certificate readCert(Context context, int certResourceID) {  
  233.         InputStream inputStream = context.getResources().openRawResource(  
  234.                 certResourceID);  
  235.         Certificate ca = null;  
  236.   
  237.         CertificateFactory cf = null;  
  238.         try {  
  239.             cf = CertificateFactory.getInstance("X.509");  
  240.             ca = cf.generateCertificate(inputStream);  
  241.   
  242.         } catch (CertificateException e) {  
  243.             e.printStackTrace();  
  244.         }  
  245.         return ca;  
  246.     }  
  247. }  
 

改自己的项目

     然后就是大刀阔斧的改自己的项目了。首先把证书文件拷贝到res/raw文件夹下。然后把libs下面的Volley.jar包删除,会发现多处报错(把访问网络的代码删除了当然会报错),先不用管,接着把自己刚才修改的Volley源码添加过来。直接把com.android.volley直接copy到自己项目的src下,把上面源码中提到的证书文件的名字替换为自己项目证书的名字就可以了。

小结

     起初也是一头雾水,查了好多文章,咨询了许多朋友,总算是顺利的用上了https。所以呢,世上本没有路,尝试的多了,也会踏出一条路。Go on !


原文地址:http://blog.youkuaiyun.com/haovip123/article/details/49509045

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值