加入收藏 | 设为首页 | 会员中心 | 我要投稿 厦门网 (https://www.xiamenwang.cn/)- 数据采集、建站、AI开发硬件、专属主机、云硬盘!
当前位置: 首页 > 教程 > 正文

一个自动清理Android项目无用资源的工具类与源码

发布时间:2023-11-10 10:00:09 所属栏目:教程 来源:互联网
导读:   很多人都知道androidunusedresources.jar这个工具,它可以把Android项目中无用的资源列出来。然而它所做的也就止于此了,在列出所有的无用资源以后,开发者们还得手动删除这些文件,这
  很多人都知道androidunusedresources.jar这个工具,它可以把Android项目中无用的资源列出来。然而它所做的也就止于此了,在列出所有的无用资源以后,开发者们还得手动删除这些文件,这实在是一个没技术含量却又烦人的体力活,作为程序员,自然是有解决办法的,我们为什么不写一个程序,让程序来实现这个功能呢?有些人给出了部分解决方案,就是清除部分无用资源,比如layout和drawable,因为这种资源是和文件一一对应的,只要删除对应文件就可以实现资源的清理,但是对于其他没用到的如string、style等资源却没有处理。而本文的工具则弥补了这个缺点,可以清理所有的资源文件。
 
  这个功能要实现的功能应该是这样的:
 
      1、读取androidunusedresources.jar导出的无用资源列表。
 
      2、清理无用的资源,包括删除无用文件以及修改包含无用资源的文件。
 
  对于drawable和layout等资源,当然是直接删掉文件就行了,因为一个文件就对应着一个资源,而对于其他的资源就不是这么一回事了,一个文件里面可能有很多资源,所以只能是删除文件里面的一部分,而保留另一部分。
 
  程序大体如下:
 
  首先是main
 
   public static void main(String[] args) {
 
   if (args.length > 0) {
 
   unusedCleaner(args[0]);
 
   }
 
   }
 
  调用了unusedCleaner方法,我们就用这个方法清理无用资源,传入的参数是androidunusedresources.jar导出的无用资源文件列表。
 
  然后看unusedCleaner方法。
 
   // currents是在找到下一个文件前列出的所有资源id。因为一个文件可能对应着多个id,有可能是一个多对多的关系。
 
   static ArrayList<TypeSource> currents = new ArrayList<>();
 
   static boolean LastIsPath = false;
 
   public static void unusedCleaner(String filePath) {
 
   ArrayList<TypeSource> files = new ArrayList<>();//待清理资源列表
 
   try {
 
   File file = new File(filePath);//androidunusedresources导出的无用资源文件列表
 
   if (file.isFile() && file.exists()) {
 
   InputStreamReader read = new InputStreamReader(
 
   new FileInputStream(file), "utf-8");
 
   BufferedReader bufferedReader = new BufferedReader(read);
 
   String lineTxt = null;
 
   while ((lineTxt = bufferedReader.readLine()) != null) {
 
   if (!parseType(lineTxt)) {
 
           //逐行读取数据,并提取数据。parseType方法可以判断是否此行代表发现了资源名。对应的格式如drawable:    bg_list
 
           //如果不是的话,那么这一行就有可能是资源所对应的文件。
 
   String trim = lineTxt.trim();
 
   if (new File(trim).exists()) {
 
   //简单的用文件是否存在判断此行到底是不是一个文件名,如果是的话,说明currents列表中所有对应的资源名肯定包含在这个文件里
 
   //就把它添加到一个待清理的资源列表中,将这些资源和文件对应起来,并添加到待清理列表中
 
   for (Iterator<TypeSource> iterator = currents
 
   .iterator(); iterator.hasNext();) {
 
   TypeSource typeSource = (TypeSource) iterator
 
   .next().clone();
 
   typeSource.path = trim;
 
   typeSource.xmlTag = typeSource.getXmlTag();
 
   files.add(typeSource);
 
   }
 
   LastIsPath = true;
 
   } else {
 
   continue;
 
   }
 
   }
 
   }
 
   read.close();
 
   } else {
 
   System.out.println("noFile");
 
   }
 
   } catch (Exception e) {
 
   System.out.println("Failed");
 
   e.printStackTrace();
 
   }
 
                  //全部找出来后,将这些资源一一清理就是了,清理文件是TypeSource的方法,TypeSource类代表一个资源。
 
   for (Iterator<TypeSource> iterator = files.iterator(); iterator
 
   .hasNext();) {
 
   TypeSource typeSource = (TypeSource) iterator.next();
 
   System.out.println(typeSource);
 
   typeSource.cleanSelf();
 
   }
 
   System.out.println("done");
 
   }
 
  
 
   public static boolean parseType(String lineTxt) {
 
           //判断当前行是不是一个资源名。如果是的话,加入到currents中,如果上一个资源是文件,那么清空currents,因为之前currents中的已经加入了待清理列表
 
   String reg = "((drawable)|(layout)|(dimen)|(string)|(attr)|(style)|(styleable)|(color)|(id)|(anim))\\s*:\\s*(\\S+)";
 
   Matcher matcher = Pattern.compile(reg).matcher(lineTxt);//使用正则匹配当前行
 
   if (matcher.find()) {
 
   if (LastIsPath) {
 
   currents.clear();
 
   }
 
   LastIsPath = false;
 
   TypeSource typeSource = new TypeSource();
 
   typeSource.type = matcher.group(1);
 
   typeSource.name = matcher.group(12);
 
   currents.add(typeSource);
 
   return true;
 
   } else {
 
   return false;
 
   }
 
   }
 
  
 
   static class TypeSource {
 
   String type = "";// 类型
 
   String name = "";// xml中的name属性
 
   String xmlTag = "";// xml的tag名
 
   String path = "";// 属于哪个文件
 
   public String getXmlTag() {
 
   if ("styleable".equals(type)) {
 
   return "declare-styleable";
 
   } else {
 
   return type;
 
   }
 
   }
 
   @Override
 
   public String toString() {
 
   return type + " | " + name + " | " + xmlTag + " | " + path;
 
   }
 
   /**
 
    * 一个一个的单独删,反正很快,就不考虑效率了。如果把一个文件对应的所有资源列出来统一删除应该很快,但是这里偷懒了
 
    */
 
   public void cleanSelf() {
 
   try {
 
   if (type == null) {
 
   return;
 
   }
 
   if (type.equals("drawable") || type.equals("layout") || type.equals("anim")) {
 
   new File(path).delete();
 
   } else if (type.equals("id") || type.equals("")) {
 
   // 跳过了id资源,如果要删除的话,跟deleteNodeByName方法差不多。
 
   } else {
 
           //deleteNodeByName方法删除xml中单个资源项。
 
   deleteNodeByName(path, xmlTag, name);
 
   }
 
   } catch (Exception e) {
 
   }
 
   }
 
   public TypeSource clone() {
 
   TypeSource ts = new TypeSource();
 
   ts.type = type;
 
   ts.name = name;
 
   ts.xmlTag = xmlTag;
 
   ts.path = path;
 
   return ts;
 
   }
 
   }
 
  
 
   @SuppressWarnings("unchecked")
 
   public static void deleteNodeByName(String path, String tag, String name) {
 
           //删除xml文件中的某个资源项
 
   try {
 
   SAXReader reader = new SAXReader();
 
   Document document = reader.read(new File(path));
 
   Element element = document.getRootElement();
 
   List<Element> list = element.elements(tag);
 
   for (int i = 0; i < list.size(); i++) {
 
   Element ele = list.get(i);
 
   String tName = ele.attributeValue("name");
 
   if (tName != null && tName.length() > 0) {
 
   if (name.equals(ele.attributeValue("name"))) {
 
   element.remove(ele);
 
   break;
 
   }
 
   }
 
   }
 
   OutputFormat format = new OutputFormat("", false);//
 
   XMLWriter xmlWriter = new XMLWriter(new FileWriter(path), format);
 
   xmlWriter.write(document);
 
   xmlWriter.flush();
 
   } catch (Exception e1) {
 
   e1.printStackTrace();
 
   }
 
   }
 
  然后导出成jar,使用方法如下
 
  java -jar AndroidUnusedResources.jar >del.txt
 
  java -jar cleaner.jar del.txt
 
  好了,原来几小时搞定的事现在只要几秒钟了。
 
  由于被无用资源引用的资源不会被视为无用资源,所以要多执行几遍上面的命令才能真正清除掉
 
  注意由于androidunusedresources导出的结果并不十分准确,有可能出错,所以会导致清理有可能不准确。可能会漏掉某些资源删除不了。这时候就得动手了。
 
  最后,记得的清理资源前先把代码提交一下,你懂的
 

(编辑:厦门网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章