<span style="font-size:18px;">需求: app调用照相机拍摄若干张图片,<span style="color:#FF0000;">在图库中不显示这些图片,避免被拷贝篡改</span>。 在以后有wifi的环境下上传到服务器。 要求判断出这些图片被篡改过?</span>

按照安卓的设计, 在拍照后MediaScanner会扫出手机的所有照片并在图库中显示出来。

      

       备注:我考虑过使用图片Exif属性判断图片被篡改过,  后来发现有工具可以修改Exif属性, 所以exif这条路走不通。


三种实现方式:


名称

缓存到sqlite

校验MD5

保存到隐藏目录

实现方式

 将图片数据存到数据库一张表的blob字段里

拍摄照片后将图片完整路径, 图片的MD5值存储到应用的database里,  在传输图片前比较图片文件的MD5值。

在sdcard下建立层次比较深的目录, 最终以".nomedia"格式命名文件夹, 在Android系统里以.作前缀是隐藏文件夹。

优点

只有本应用能读写,安全性高。

通过比较MD5值,能判断出文件是否被篡改。

实现简单,在手机图库里找不到这些图片, 在文件管理器也找不到隐藏目录。 如果目录层级很深, 一般很难被发现。

缺点

适合小图片如缩略图

计算MD5时要读图片文件, IO操作费时间耗内存。

理解android系统的可以写工具软件找到隐藏目录。



第一种: 保存到sqlite的blob类型字段,  在建表时创建一个类型为blob的字段, 将图片数据保存到该字段。(在此不贴代码了,  找度娘)。


第二种: 计算MD5值, 也可以是其它算法的校验值,  就是用文件数据生成一个字符串。

md5示例代码:

  1. import java.security.MessageDigest;  
  2. import java.io.FileInputStream;  
  3. import java.io.InputStream;  
  4.   
  5. public class MD5 {  
  6.     private static final char HEX_DIGITS[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',  
  7. 'A', 'B', 'C', 'D', 'E', 'F' };  
  8.   
  9.     public static void main(String[] args)  
  10.     {  
  11.         System.out.println(md5sum("/init.rc"));  
  12.     }  
  13.   
  14.     public static String toHexString(byte[] b) {  
  15. sb = new
  16. i = 0; i < b.length; i++) {  
  17. >>>
  18.             sb.append(HEX_DIGITS[b[i] & 0x0f]);  
  19.         }  
  20.         return sb.toString();  
  21.     }  
  22.   
  23.     public static String md5sum(String filename) {  
  24.         InputStream fis;  
  25. buffer = new
  26. numRead = 0;  
  27.         MessageDigest md5;  
  28.         try{  
  29. fis = new
  30. md5 = MessageDigest.getInstance("MD5");  
  31. numRead=fis.read(buffer)) >
  32.                 md5.update(buffer,0,numRead);  
  33.             }  
  34.             fis.close();  
  35.             return toHexString(md5.digest());     
  36.         } catch (Exception e) {  
  37.             System.out.println("error");  
  38.             return null;  
  39.         }  
  40.     }  


第三种: 保存到手机隐藏目录, 记住目录层级越深越隐蔽。请注意目录名".nomedia", “.”是隐藏目录的前缀, 目录名随便定义。

参考代码:


public String getBaseDir(Context context) {
    String baseDir = null;
    if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
        baseDir = Environment.getExternalStorageDirectory() + "/" + FILE_NAME + "/";
    } else {
        baseDir = context.getCacheDir().getAbsolutePath() + "/" + FILE_NAME + "/";
    }
    File basedir = new File(baseDir);
    if (!basedir.exists()) {
        basedir.mkdirs();
    }
    return baseDir;
}




File mediaStorageDir = new File(
        FileManager.getInstance().getBaseDir(this), ".nomedia");
if (!mediaStorageDir.exists()) {
    if (!mediaStorageDir.mkdirs()) {
        Log.d("MyCameraApp", "failed to create directory");
        return null;
    }
}