android之as自動化刪除無用資源爲apk瘦身

隨着項目越來越大,一些無用的資源越來越多,有必要爲apk瘦身了,網上一頓亂拔,有歡喜也有淚水,唉,要麼是搭建python環境太複雜,要麼是沒有適用於android studio項目的自動化刪除無用資源的。。。頭痛的要死,手動一個個刪除吧又不符合一個程序員懶惰的高雅氣質,於是乎結合現有的,自己寫一個自動刪除的java demo,有不對的地方忘大家不吝賜教。。。使用也比較簡單。。。。

注:一定要是java項目,因爲android是無法刪除pc硬盤中的項目的

大致步驟呢和網上的一樣,都是通過gradle lint工具去check無用資源

 1、這裏不多說廢話,假設已經獲取到了

lint-result.xml 

 這裏給一個博客地址:按照這個博客說的步驟就可以獲取到lint-results.xml  

http://blog.csdn.net/imesong/article/details/49187695

   注:Android Studio 終端指的是as項目下的terminal 


 2、直接上代碼,不解釋,有註釋了,也比較簡單,拿過來就用。。。

package www.unused.res;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream.GetField;
import java.util.ArrayList;
import java.util.List;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;

public class DeleteMain {
	public static void main(String[] args) {

		new Thread(new Runnable() {

			@Override
			public void run() {
				DeleteMain main = new DeleteMain();
				 final List<String> pathList = main.parseUnusedResXml();//getFilePathList();
                 int size = pathList.size();
                 String filePath = null;
				// 測試使用
				// main.copyFile("D:\\soft\\studio_project\\PregnancyPartner\\app\\src\\main\\res\\drawable-hdpi\\soundwave4.png",
				// "D:\\dele_res\\soundwave4.png");
                 for (int i = 0; i < size; i++) {
                     filePath = pathList.get(i);
                     try {
                    	 main.copyFile(filePath,
                                 "D:/dele_res/" + filePath.substring(filePath.lastIndexOf("\\")+1, filePath.length()));
                     } catch (Exception e) {
                         e.printStackTrace();
                     } finally {
                    	 main.deletFile(filePath);
                     }
                 }
			}
		}).start();
	}

	/**
	 * 刪除 未使用的冗餘資源(圖片 xml佈局)
	 * <p>
	 * false 顯示資源列表
	 * <p>
	 * true 顯示資源列表 並刪除資源
	 *
	 * @throws Exception
	 */
	private void deletFile(String filePath) {
		File file = new File(filePath);
		System.out.println("file.isFile() = " + file.isFile());
		if (file.isFile() && file.exists()) { // 判斷文件是否存在
			try {
				file.delete();
				System.out.println("刪除成功");
			} catch (Exception e) {
			}
		}
	}

	/**
	 * 複製單個文件:將刪除的文件備份
	 *
	 * @param oldPath
	 *            String 原文件路徑 如:c:/fqf.txt
	 * @param newPath
	 *            String 複製後路徑 如:f:/fqf.txt
	 * @return boolean
	 * @author zhongwr
	 */
	public void copyFile(String oldPath, String newPath) {
		try {
			System.out.println("oldPath = " + oldPath + " \\n newPath = " + newPath);
			int bytesum = 0;
			int byteread = 0;
			File oldfile = new File(oldPath);
			if (oldfile.exists()) { // 文件存在時
				InputStream inStream = new FileInputStream(oldPath); // 讀入原文件
				FileOutputStream fs = new FileOutputStream(newPath);
				System.out.println("file size = " + inStream.available());
				byte[] buffer = new byte[inStream.available()];
				while ((byteread = inStream.read(buffer)) != -1) {
					bytesum += byteread; // 字節數 文件大小
					System.out.println("bytesum = " + bytesum);
					fs.write(buffer, 0, byteread);
				}
				inStream.close();
			}
		} catch (Exception e) {
			System.out.println("複製單個文件操作出錯");
			e.printStackTrace();
		}
	}

	 /**
     * 例子:
     * <student id="5" group="5">
     * <name>小明</name>
     * <sex>男</sex>
     * <age>18</age>
     * <email>[email protected]</email>
     * <birthday>1987-06-08</birthday>
     * <memo>好學生</memo>
     * </student>
     * <p>
     * switch (eventType) {
     * //文檔開始
     * case XmlPullParser.START_DOCUMENT:
     * list=new ArrayList<Student>();
     * break;
     * //開始節點
     * case XmlPullParser.START_TAG:
     * //判斷如果其實節點爲student
     * if("student".equals(nodeName)){
     * //實例化student對象
     * student=new Student();
     * //設置Id屬性
     * student.setId(Integer.parseInt(xmlPullParser.getAttributeValue(0)));
     * //設置Group屬性
     * student.setGroup(Integer.parseInt(xmlPullParser.getAttributeValue(1)));
     * }else if("name".equals(nodeName)){
     * //設置name
     * student.setName(xmlPullParser.nextText());
     * <p>
     * }
     * break;
     * //結束節點
     * case XmlPullParser.END_TAG:
     * if("student".equals(nodeName)){
     * list.add(student);
     * student=null;
     * }
     * break;
     * default:
     * break;
     * }
     * eventType=xmlPullParser.next();
     * }
     * <p>
     * <p>
     * pull解析lint的xml--獲取要刪除資源的路徑 如:d:/results.xml
     * 
     *
     * @return
     * @author zhongwr
     */
	public List<String> parseUnusedResXml() {
		List<String> pathLists = new ArrayList<String>();
		FileInputStream fis = null;
		InputStream is = null;
		try {
			XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
			// 獲取XmlPullParser實例
			XmlPullParser pullParser = factory.newPullParser();
			File resFile = new File("d:/results.xml");
			if (!resFile.isFile()) {
				System.out.println("file is not exist");
				return pathLists;
			}
			fis = new FileInputStream(new File("d:/results.xml"));
			is = new BufferedInputStream(fis);
			pullParser.setInput(is, "UTF-8");
			// 開始
			int eventType = pullParser.getEventType();
			boolean isUnusedPath = false;
			while (eventType != XmlPullParser.END_DOCUMENT) {// 文檔沒讀取完
				String nodeName = pullParser.getName();
				switch (eventType) {
				// 文檔開始
				case XmlPullParser.START_DOCUMENT:
					pathLists = new ArrayList<String>();
					break;

				// 開始節點
				case XmlPullParser.START_TAG:

					// System.out.println( "START_TAG Node = " + nodeName);
					// 過濾要刪除的未使用的資源
					if ("issue".equals(nodeName) && "UnusedResources".equals(pullParser.getAttributeValue(0))) {
						isUnusedPath = true;
						System.out.println("UnusedResources Node = " + nodeName);

					} else if ("location".equals(nodeName) && isUnusedPath) {
						System.out.println("location Node = " + nodeName);
						String path = pullParser.getAttributeValue(0);
						System.out.println("path = " + path);
						// 刪除指定目錄下的資源,防止刪除lib下的資源 以及 過濾掉不需要刪除的目錄
						if (path.startsWith("D:\\soft\\studio_project\\pp\\app\\src\\main\\res")
								&& !path.contains("res\\values")) {
							pathLists.add(path);
						}
					}
					break;
				// 結束節點
				case XmlPullParser.END_TAG:
					if ("issue".equals(nodeName)) {
						isUnusedPath = false;
					}
					// System.out.println( "END_TAG Node = " + nodeName);
					break;
				default:
					break;
				}
				// 手動的觸發下一個事件
				eventType = pullParser.next();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {  
            try {  
                if(is!=null){  
                is.close();  
                }  
                if(fis!=null){  
                    fis.close();  
                }  
            } catch (IOException e) {  
                e.printStackTrace();  
            }     
    }

		System.out.println("pathLists = " + pathLists.size());
		return pathLists;
	}

	/**
	 * 獲取刪除的文件絕對路徑集合 zhongwr 下午7:18:34 void
	 */
	private List<String> getFilePathList() {
		String projectPath = "D:\\soft\\studio_project\\pp";
		List<String> filePathList = new ArrayList<String>();
		try {
			BufferedReader reader = new BufferedReader(new FileReader("D:\\soft\\studio_project\\pp\\result.txt"));
			String line;
			int count = 0;
			// double totalSize = 0;
			while ((line = reader.readLine()) != null) {
				if (line.startsWith("app") && line.contains("UnusedResources") && !line.contains("res/value")
						&& !line.contains("appcompat") && !line.contains("umeng")) {
					count++;
					int end = line.indexOf(":");
					if (end != -1) {
						String fileName = line.substring(0, end);
						String filePath = projectPath + fileName;
						System.out.println(filePath);
						filePathList.add(filePath);
					}
				}
			}
			System.out.println("filePathList = " + filePathList.size());
			System.out.println("count = " + String.valueOf(count));
			// System.out.println(String.valueOf(totalSize / 1024));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return filePathList;
	}
}

這裏要注意的是,我已經將lint-results.xml更改爲results.xml,也可以不改。。再者是將results.xml放到d盤,你隨意,放在自己喜歡的目錄下就行,只是要相應的修改一下;其次再刪除之前我將文件備份在其它目錄下,你也可以不備份,隨你開心就好;還有這個是java項目不是android,所以要用eclipse打開後直接運行就可以了

demo:http://download.csdn.net/detail/zhongwn/9648920

xpullJar: http://download.csdn.net/detail/zhongwn/9656052

希望能幫到你


網上遇到的問題有一些小結也貼出來如下:

1、刪除無用的(導入類)import。。。
http://jingyan.baidu.com/article/48b37f8d0580801a646488fd.html
2、
  1)、方法一:使用手動刪除
     使用lint工具掃描
     http://www.waychel.com/shi-yong-android-studiode-lintqing-chu-wu-yong-de-zi-yuan-wen-jian/


  2)、方法二:使用自動化掃描,自動化刪除,自行過濾
    自動化刪除無用資源  配置lint環境量,在cmd控制檯下執行,執行完後,在執行腳本就行了
    http://www.cnblogs.com/yxy8023ustc/p/4050243.html
    用android tools自帶的lint掃描,但是會報錯說是as只能用gradle lint掃描不能使用sdk自帶的lint---


  3)、使用lint掃描後,用第三方自動化工具
    或者使用自動構建工具刪除---風險很大,刪除到jar裏邊的可能就有問題
    http://blog.csdn.net/imesong/article/details/49187695
    http://blog.csdn.net/caoxiao90/article/details/51057986
  
  4)、as或者eclipse 可以使用自動化掃描代碼,作者開發的工具下載(arc.jar),雙擊打開,選擇自己的工程下對應要掃描的目錄,可以一次性將無用代碼和無用資源一起掃描,也可以分開掃描
    http://blog.csdn.net/androidzhaoxiaogang/article/details/7930304  ---這個我試了一下,用不起來,放棄,也沒有找到as的Ucdetector的插件
 總結:
  所以方法2和4都是行不通的
  一定要注意,刪除的時候要確保刪除的是無用的,畢竟項目以穩定爲主要目的
  方法2使用於eclipse開發的android項目,as無法使用
  使用方法三:
   1、需要安裝python 2.7+的環境 ,配置好環境變量,安裝Pip:安裝pip需將get-pip.py文件下載,放到一個指定目錄比如 d:\soft\get-pip.py;直接cmd到控制檯執行 python get-pip.py就安裝好了;將python下的script文件夾添加到系統環境變量path裏
   2、安裝android-resource-remover;直接cmd之後,執行命令pip install android-resource-remover;之後從github下載android-resource-remover解壓執行demo
   根據提示會讓給你安裝一系列的安裝包 pip install android-resource-remover  pip install pyopenssl ndg-httpsclient pyasn1 以及  libxml2 and libxslt 都要安裝,看着都煩。。。我就想用用這個工具而已,特麼讓我搭一個爬蟲環境,一個挨着一個安裝包。。。哭的沒眼淚啊
   Task 'android-resource-remover' not found in root project
  參考:http://blog.csdn.net/mlj1668956679/article/details/38643145 


發佈了68 篇原創文章 · 獲贊 38 · 訪問量 25萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章