溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

一個自動清理Android項(xiàng)目無用資源的工具類及源碼

發(fā)布時間:2020-04-20 00:01:52 來源:網(wǎng)絡(luò) 閱讀:8185 作者:NashLegend 欄目:移動開發(fā)

此工具在我的github上。地址:https://github.com/NashLegend/AndroidResourceCleaner


很多人都知道androidunusedresources.jar這個工具,它可以把Android項(xiàng)目中無用的資源列出來。然而它所做的也就止于此了,在列出所有的無用資源以后,開發(fā)者們還得手動刪除這些文件,這實(shí)在是一個沒技術(shù)含量卻又煩人的體力活,作為程序員,自然是有解決辦法的,我們?yōu)槭裁床粚懸粋€程序,讓程序來實(shí)現(xiàn)這個功能呢?有些人給出了部分解決方案,就是清除部分無用資源,比如layout和drawable,因?yàn)檫@種資源是和文件一一對應(yīng)的,只要刪除對應(yīng)文件就可以實(shí)現(xiàn)資源的清理,但是對于其他沒用到的如string、style等資源卻沒有處理。而本文的工具則彌補(bǔ)了這個缺點(diǎn),可以清理所有的資源文件。


這個功能要實(shí)現(xiàn)的功能應(yīng)該是這樣的:

    1、讀取androidunusedresources.jar導(dǎo)出的無用資源列表。

    2、清理無用的資源,包括刪除無用文件以及修改包含無用資源的文件。

對于drawable和layout等資源,當(dāng)然是直接刪掉文件就行了,因?yàn)橐粋€文件就對應(yīng)著一個資源,而對于其他的資源就不是這么一回事了,一個文件里面可能有很多資源,所以只能是刪除文件里面的一部分,而保留另一部分。


程序大體如下:

首先是main

	public static void main(String[] args) {
		if (args.length > 0) {
			unusedCleaner(args[0]);
		}
	}

調(diào)用了unusedCleaner方法,我們就用這個方法清理無用資源,傳入的參數(shù)是androidunusedresources.jar導(dǎo)出的無用資源文件列表。

然后看unusedCleaner方法。

	// currents是在找到下一個文件前列出的所有資源id。因?yàn)橐粋€文件可能對應(yīng)著多個id,有可能是一個多對多的關(guān)系。
	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導(dǎo)出的無用資源文件列表
			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)) { 
					        //逐行讀取數(shù)據(jù),并提取數(shù)據(jù)。parseType方法可以判斷是否此行代表發(fā)現(xiàn)了資源名。對應(yīng)的格式如drawable:    bg_list
					        //如果不是的話,那么這一行就有可能是資源所對應(yīng)的文件。
						String trim = lineTxt.trim();
						if (new File(trim).exists()) { 
						//簡單的用文件是否存在判斷此行到底是不是一個文件名,如果是的話,說明currents列表中所有對應(yīng)的資源名肯定包含在這個文件里
						//就把它添加到一個待清理的資源列表中,將這些資源和文件對應(yīng)起來,并添加到待清理列表中
							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) {
	        //判斷當(dāng)前行是不是一個資源名。如果是的話,加入到currents中,如果上一個資源是文件,那么清空currents,因?yàn)橹癱urrents中的已經(jīng)加入了待清理列表
		String reg = "((drawable)|(layout)|(dimen)|(string)|(attr)|(style)|(styleable)|(color)|(id)|(anim))\\s*:\\s*(\\S+)";
		Matcher matcher = Pattern.compile(reg).matcher(lineTxt);//使用正則匹配當(dāng)前行
		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;
		}

		/**
		 * 一個一個的單獨(dú)刪,反正很快,就不考慮效率了。如果把一個文件對應(yīng)的所有資源列出來統(tǒng)一刪除應(yīng)該很快,但是這里偷懶了
		 */
		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中單個資源項(xiàng)。
					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文件中的某個資源項(xiàng)
		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();
		}
	}


然后導(dǎo)出成jar,使用方法如下

java -jar AndroidUnusedResources.jar >del.txt
java -jar cleaner.jar del.txt

好了,原來幾小時搞定的事現(xiàn)在只要幾秒鐘了。

由于被無用資源引用的資源不會被視為無用資源,所以要多執(zhí)行幾遍上面的命令才能真正清除掉


注意由于androidunusedresources導(dǎo)出的結(jié)果并不十分準(zhǔn)確,有可能出錯,所以會導(dǎo)致清理有可能不準(zhǔn)確??赡軙┑裟承┵Y源刪除不了。這時候就得動手了。


最后,記得的清理資源前先把代碼提交一下,你懂的

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI