Universal-Image-Loader Disk缓存加密功能实现

Universal-Image-Loader(UIL)这个开源库,相信大家也都熟悉,应该算是Android图片加载这块的集大成者了吧。基本上该有的功能都有了,关于UIL源码的分析,有兴趣的同学可以点击这里

UIL将各个功能模块都以接口的形式抽象出来,这样大家可以很方便的进行扩展,同时各个功能模块也都提供了默认的实现,可以满足大部分的需求。优秀的框架的扩展性,真的很赞。

我们项目中一直使用是UIL,最近项目有个需求,对UIL中在Disk中的缓存进行加密,不希望通过文件管理器能查看这些图片。


加解密算法不是重点,大家根据自己的需求,选择合适的算法即可(我在项目中选择了简单的AES加密),重点是怎么在UIL中进行拓展。


采用的方案是:

1.自定义DiskCache,存入Disk时,将图片文件加密,从Disk取出的时候,将加密后的缓存图片文件解密。

2.自定义ImageLoadingListener,当图片显示完成后,删除解密后的文件。


首先是自定义DiskCache

/**
 * 
 * 实现了加密解密的DiskCache<br/>
 * 继承自BaseDiscCache,重点实现了get方法和两个重载的save方法
 * 
 * @author grumoon
 * 
 */
public class SecureDiscCache extends BaseDiscCache {

	private static final String TEMP_IMAGE_POSTFIX = ".tmp";

	private static final String TAG = "SecureDiscCache";

	private FileSecUtil fileSecUtil = null;

	public SecureDiscCache(File cacheDir) {
		super(cacheDir);
		this.fileSecUtil = new FileSecUtil();
	}

	public SecureDiscCache(File cacheDir, File reserveCacheDir) {
		super(cacheDir, reserveCacheDir);
		this.fileSecUtil = new FileSecUtil();
	}

	public SecureDiscCache(File cacheDir, File reserveCacheDir, FileNameGenerator fileNameGenerator) {
		super(cacheDir, reserveCacheDir, fileNameGenerator);
		this.fileSecUtil = new FileSecUtil();
	}

	/**
	 * 根据imageUri获取Disk中缓存文件,将其解密并返回。
	 */
	@Override
	public File get(String imageUri) {
		Log.v(TAG, "get->" + imageUri);
		File sourceFile = getFile(imageUri);
		File imageFile = null;
		try {
			// 解密
			imageFile = fileSecUtil.decrypt(sourceFile, sourceFile.getAbsolutePath() + FileSecUtil.DECRYPT_TEMP_FILE_TYPE, FileSecUtil.SEC_KEY);
		} catch (Exception e) {
			imageFile = null;
		}
		return imageFile;
	}

	/**
	 * 将图片流imageStream写入到Disk中,并做加密处理。
	 */
	@Override
	public boolean save(String imageUri, InputStream imageStream, CopyListener listener) throws IOException {
		Log.v(TAG, "save with stream->" + imageUri);
		File imageFile = getFile(imageUri);
		File tmpFile = new File(imageFile.getAbsolutePath() + TEMP_IMAGE_POSTFIX);
		boolean loaded = false;
		try {
			OutputStream os = new BufferedOutputStream(new FileOutputStream(tmpFile), bufferSize);
			try {
				loaded = IoUtils.copyStream(imageStream, os, listener, bufferSize);
			} finally {
				IoUtils.closeSilently(os);
			}
		} finally {
			IoUtils.closeSilently(imageStream);
			if (loaded) {
				try {
					// 加密
					fileSecUtil.encrypt(tmpFile, imageFile.getAbsolutePath(), FileSecUtil.SEC_KEY);
				} catch (Exception e) {
					loaded = false;
				}
			}
			tmpFile.delete();
		}
		Log.v(TAG, "save with stream->" + loaded);
		return loaded;
	}

	/**
	 * 将bitmap对象写入到Disk中,并做加密处理。
	 */
	@Override
	public boolean save(String imageUri, Bitmap bitmap) throws IOException {
		Log.v(TAG, "save with bitmap->" + imageUri);
		File imageFile = getFile(imageUri);
		File tmpFile = new File(imageFile.getAbsolutePath() + TEMP_IMAGE_POSTFIX);
		OutputStream os = new BufferedOutputStream(new FileOutputStream(tmpFile), bufferSize);
		boolean savedSuccessfully = false;
		try {
			savedSuccessfully = bitmap.compress(compressFormat, compressQuality, os);
		} finally {
			IoUtils.closeSilently(os);
			if (savedSuccessfully) {
				try {
					// 加密
					fileSecUtil.encrypt(tmpFile, imageFile.getAbsolutePath(), FileSecUtil.SEC_KEY);
				} catch (Exception e) {
					savedSuccessfully = false;
				}
			}
			tmpFile.delete();
		}
		bitmap.recycle();
		Log.v(TAG, "save with bitmap->" + savedSuccessfully);
		return savedSuccessfully;
	}

	/**
	 * 获取加密的文件绝对地址
	 * 
	 * @param imageUri
	 * @return
	 */
	public String getFilePath(String imageUri) {
		return getFile(imageUri).getAbsolutePath();
	}

}

继承自BaseDiskCache,BaseDiskCache是个抽象类,已基本实现所有功能

我们这里重写了两个save方法,实现了文件加密

重写get方法,实现了文件的解密

这样在缓存的中文件就是加密状态了。


然后是自定义ImageLoadingListener

/**
 * 配合SecureDiscCache完成加解密功能 <br/>
 * 用于在显示完图片以后,删除未加密文件
 * 
 * @author grumoon
 * 
 */
public class SecureImageLoadingListener implements ImageLoadingListener {
	@Override
	public void onLoadingStarted(String imageUri, View view) {

	}

	@Override
	public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
		deleteImageFile(imageUri);
	}

	@Override
	public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
		deleteImageFile(imageUri);
	}

	@Override
	public void onLoadingCancelled(String imageUri, View view) {
		deleteImageFile(imageUri);
	}

	public void deleteImageFile(String imageUri) {
		try {
			ImageLoader imageLoader = ImageLoader.getInstance();
			DiskCache diskCache = imageLoader.getDiskCache();
			if (diskCache instanceof SecureDiscCache) {
				SecureDiscCache sdc = (SecureDiscCache) diskCache;
				new File(sdc.getFilePath(imageUri) + FileSecUtil.DECRYPT_TEMP_FILE_TYPE).delete();
			}
		} catch (Exception e) {
		}
	}
}
这个类的主要目的,实在解密文件后,Disk中存在一个未加密的文件,我们需要在显示出图片或者显示失败后删掉他。

使用方法:

初始化过程:


ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
				.diskCache(new SecureDiscCache(cacheDir,cacheDir,new Md5FileNameGenerator()))
				...其它配置
				.build();
ImageLoader.getInstance().init(config);

显示图片过程:

ImageLoader.getInstance().displayImage(UrlUtil.preUrl(uri), imageView,
				ImageLoaderUtil.getDisplayImageOptions(),
				new SecureImageLoadingListener());


缺点和不足:

1.在调用SecureDiskCache的get方法(解密文件,产生未加密的文件)到 显示图片完成删除图片之前的时间内(时间很短),Disk中会存在未加密的文件,希望能得到改进。

2.SecureDiskCache中的两个save方法,基本上都是复制了BaseDiskCache中的方法,将流或者bitmap存到disk中,再通过加密工具对文件进行处理。最好是能够直接对流或者bitmap进行处理,直接加密生成文件,免去中间过程和提高安全性。


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值