├── README.md ├── .gitignore ├── LICENSE └── src └── ScanAndClearUnusedResource.java /README.md: -------------------------------------------------------------------------------- 1 | # ScanUnusedResouce 2 | Android工程 无用资源扫描 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | 21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 22 | hs_err_pid* 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /src/ScanAndClearUnusedResource.java: -------------------------------------------------------------------------------- 1 | package com.chu; 2 | 3 | import android.util.Log; 4 | 5 | import java.io.BufferedReader; 6 | import java.io.DataInputStream; 7 | import java.io.File; 8 | import java.io.FileNotFoundException; 9 | import java.io.FileReader; 10 | import java.io.IOException; 11 | import java.io.InputStream; 12 | import java.util.ArrayList; 13 | import java.util.Enumeration; 14 | import java.util.HashMap; 15 | import java.util.List; 16 | import java.util.jar.JarEntry; 17 | import java.util.jar.JarFile; 18 | 19 | /** 20 | * Created by chulili on 2017/8/3. 21 | */ 22 | 23 | public class ScanAndClearUnusedResource { 24 | private static final String TAG = ScanAndClearUnusedResource.class.getSimpleName(); 25 | 26 | private static boolean REAL_DEL = false; // 是否真的删除文件 27 | 28 | private final static boolean DEL_JAVA = true; // 是否删除java文件 29 | 30 | private final static boolean NEED_READ_JAR = true; // 是否需要扫描jar 31 | 32 | private final static boolean FULL_LOG = false;// 是否显示具体Log 33 | 34 | private final static boolean DEL_ALL = true; 35 | 36 | private static ArrayList allUnusedExp = null; 37 | 38 | // 存在拼接查找资源的逻辑 39 | private final static String[] HOLD = new String[]{ 40 | "cate_", "music_top_fans_", "gift_num_", "ico_hot_" 41 | }; 42 | 43 | public final static String ROOT_DIR = "E:\\pps_svn\\Android O\\WebpSample\\"; 44 | 45 | public final static String[] EXCLUDE_DIR = { 46 | ".git", 47 | ".gitignore", 48 | ".gradle", 49 | ".idea", 50 | "build", 51 | "gradle" 52 | }; 53 | 54 | 55 | public final static String[] INCLUDE_DIR = { 56 | "app" 57 | }; 58 | 59 | public final static String[] TO_CLEAR_PROJECTS = { 60 | "app" 61 | }; 62 | 63 | public static List TO_CLEAR = new ArrayList<>(); 64 | 65 | private final static String[] XML_DIRS = {"/res/layout", "/res/menu", "/res/xml", "/res/anim", "/res/drawable"}; 66 | private final static String[] IMG_DIRS = {"/res/drawable", "/res/drawable-hdpi", "/res/drawable-xhdpi", "/res/drawable-xxhdpi", "/res/drawable-xxxhdpi"}; 67 | 68 | // 保存所有代码,以文件名做key 69 | private final static HashMap codeMap = new HashMap(); 70 | 71 | private static int delFiles = 0; 72 | private static long totalBytes = 0; 73 | private static long delXMLBytes = 0; 74 | private static long delIMGBytes = 0; 75 | 76 | public static void main(String[] args) { 77 | 78 | getAllUnusedResExcept(); 79 | 80 | // 加载所有代码到内存中 81 | loadCode(); 82 | 83 | System.out.print("***************************************\n"); 84 | 85 | int lastDelFiles = -1; 86 | while (true) { 87 | lastDelFiles = delFiles; 88 | if (!REAL_DEL) { 89 | delFiles = 0; 90 | totalBytes = 0; 91 | delXMLBytes = 0; 92 | delIMGBytes = 0; 93 | } 94 | 95 | if (DEL_ALL) { 96 | // 代码 97 | if (DEL_JAVA) { 98 | for (String p : INCLUDE_DIR) { 99 | File java_root = new File(ROOT_DIR + p + "/src/main/java"); 100 | if (!java_root.exists()) { 101 | java_root = new File(ROOT_DIR + p + "/src"); 102 | } 103 | delUnusedJava(java_root); 104 | } 105 | } 106 | 107 | // 扫描所有XML 108 | for (String p : INCLUDE_DIR) { 109 | File xml_root = new File(ROOT_DIR + p + "/src/main"); 110 | if (!xml_root.exists()) { 111 | xml_root= new File(ROOT_DIR + p); 112 | } 113 | for (String dir : XML_DIRS) { 114 | File f = new File(xml_root.getAbsoluteFile() + dir); 115 | delUnusedXml(f); 116 | } 117 | } 118 | 119 | // Image 120 | for (String p : INCLUDE_DIR) { 121 | File image_root = new File(ROOT_DIR + p + "/src/main"); 122 | if (!image_root.exists()) { 123 | image_root = new File(ROOT_DIR + p); 124 | } 125 | for (String dir : IMG_DIRS) { 126 | File f = new File(image_root.getAbsoluteFile() + dir); 127 | delUnusedImage(f); 128 | } 129 | } 130 | 131 | } else { 132 | // 代码 133 | if (DEL_JAVA) { 134 | for (String p : TO_CLEAR_PROJECTS) { 135 | File f = new File(ROOT_DIR + p + "/src"); 136 | delUnusedJava(f); 137 | } 138 | } 139 | 140 | // 扫描所有XML 141 | for (String p : TO_CLEAR_PROJECTS) { 142 | for (String dir : XML_DIRS) { 143 | File f = new File(ROOT_DIR + p + dir); 144 | delUnusedXml(f); 145 | } 146 | } 147 | 148 | // Image 149 | for (String p : TO_CLEAR_PROJECTS) { 150 | for (String dir : IMG_DIRS) { 151 | File f = new File(ROOT_DIR + p + dir); 152 | delUnusedImage(f); 153 | } 154 | } 155 | 156 | } 157 | 158 | System.out.println("可删除文件数:" + delFiles); 159 | if (delFiles == lastDelFiles) { 160 | break; 161 | } 162 | } 163 | 164 | System.out.println("最终删除文件数:" + delFiles); 165 | System.out.println("删除的XML字节数:" + delXMLBytes); 166 | System.out.println("删除的IMG字节数:" + delIMGBytes); 167 | } 168 | 169 | // 加载所有代码(包括xml和java) 170 | private static void loadCode() { 171 | codeMap.clear(); 172 | for (String dirName : INCLUDE_DIR) { 173 | File project = new File(ROOT_DIR + dirName); 174 | if (project.isFile()) { 175 | continue; 176 | } 177 | 178 | File dir = null; 179 | 180 | // System.out.println(project.getAbsolutePath()); 181 | 182 | String filename = project.getAbsolutePath() + "\\src\\main"; 183 | File src_main_file = new File(filename); 184 | 185 | if(src_main_file.exists()) { 186 | dir = new File(filename, "/java"); 187 | loadDirCode(dir); 188 | 189 | dir = new File(filename, "/res"); 190 | loadDirCode(dir); 191 | 192 | dir = new File(filename, "/AndroidManifest.xml"); 193 | if (dir.exists()) { 194 | loadFileCode(dir); 195 | } 196 | 197 | } else { 198 | dir = new File(project, "/src"); 199 | loadDirCode(dir); 200 | 201 | dir = new File(project, "/res"); 202 | loadDirCode(dir); 203 | } 204 | 205 | if (NEED_READ_JAR) { 206 | dir = new File(project, "/libs"); 207 | loadContantsInJar(dir); 208 | } 209 | 210 | dir = new File(project, "/AndroidManifest.xml"); 211 | if (dir.exists()) { 212 | loadFileCode(dir); 213 | } 214 | 215 | } 216 | System.out.println("初始文件总数:" + codeMap.size()); 217 | System.out.println("代码字节数:" + totalBytes); 218 | } 219 | 220 | // 筛选出没有引用的java文件并且删除 221 | private static void delUnusedJava(File dir) { 222 | if (codeMap == null || codeMap.size() == 0) { 223 | System.err.println("textMap没有初始化"); 224 | } 225 | if (dir == null || !dir.exists() || !dir.isDirectory()) { 226 | return; 227 | } 228 | 229 | for (File f : dir.listFiles()) { 230 | if (f.isDirectory()) { 231 | delUnusedJava(f); 232 | } else { 233 | String fileName = f.getAbsolutePath(); 234 | if (fileName.endsWith(".java") && !isExclude(f)) { 235 | if (!containsStringByJava(f)) { 236 | logD(f); 237 | codeMap.remove(f.getAbsolutePath()); 238 | delXMLBytes += f.length(); 239 | delFiles++; 240 | if (REAL_DEL) { 241 | f.delete(); 242 | } 243 | } 244 | } 245 | } 246 | } 247 | } 248 | 249 | private static void logD(File f) { 250 | System.out.println(f.getAbsolutePath()); 251 | } 252 | 253 | // 筛选出没有引用的xml文件并且删除 254 | private static void delUnusedXml(File dir) { 255 | if (codeMap == null || codeMap.size() == 0) { 256 | System.err.println("textMap没有初始化"); 257 | } 258 | if (dir == null || !dir.exists() || !dir.isDirectory()) { 259 | return; 260 | } 261 | 262 | for (File f : dir.listFiles()) { 263 | String fileName = f.getAbsolutePath(); 264 | if (fileName.endsWith(".xml") && !isExclude(f)) { 265 | if (!containsString(f)) { 266 | logD(f); 267 | codeMap.remove(f.getAbsolutePath()); 268 | delXMLBytes += f.length(); 269 | delFiles++; 270 | if (REAL_DEL) { 271 | f.delete(); 272 | } 273 | } 274 | } 275 | } 276 | } 277 | 278 | // 筛选出没有引用的图片文件并且删除 279 | private static void delUnusedImage(File dir) { 280 | if (codeMap.size() == 0) { 281 | System.err.println("textMap没有初始化"); 282 | } 283 | if (dir == null || !dir.exists() || !dir.isDirectory()) { 284 | return; 285 | } 286 | for (File f : dir.listFiles()) { 287 | String fileName = f.getName(); 288 | if ((fileName.endsWith(".9.png") || fileName.endsWith(".png") || fileName.endsWith(".jpg")) && !isExclude(f)) { 289 | if (!containsString(f)) { 290 | logD(f); 291 | codeMap.remove(f.getAbsolutePath()); 292 | delIMGBytes += f.length(); 293 | delFiles++; 294 | if (REAL_DEL) { 295 | f.delete(); 296 | } 297 | } 298 | } 299 | } 300 | } 301 | 302 | // 查找指定字符串 303 | private static boolean containsString(File currentFile) { 304 | String currentName = currentFile.getName(); 305 | String currentFilePath = currentFile.getAbsolutePath(); 306 | String fileName = currentName.substring(0, currentName.indexOf(".")); 307 | 308 | // TODO; 存在拼接查找资源的逻辑 309 | for (String s : HOLD) { 310 | if (fileName.startsWith(s)) { 311 | return true; 312 | } 313 | } 314 | 315 | int c = 0; 316 | for (String filePath : codeMap.keySet()) { 317 | if (filePath.equals(currentFilePath)) { 318 | continue; 319 | } 320 | String text = codeMap.get(filePath); 321 | if (text.contains(fileName)) { 322 | c++; 323 | if (filePath.contains(".jar")) { 324 | if (FULL_LOG) { 325 | System.err.println("###" + filePath + "包含" + currentFilePath); 326 | } 327 | } 328 | break; 329 | } 330 | } 331 | 332 | return c > 0; 333 | } 334 | 335 | // 查找指定字符串 336 | private static boolean containsStringByJava(File currentFile) { 337 | String currentName = currentFile.getName(); 338 | String currentFilePath = currentFile.getAbsolutePath(); 339 | String fileName = currentName.substring(0, currentName.indexOf(".")); 340 | 341 | int c = 0; 342 | for (String filePath : codeMap.keySet()) { 343 | // if (!filePath.endsWith(".java") && !filePath.endsWith("AndroidManifest.xml")) { 344 | // continue; 345 | // } 346 | if (filePath.equals(currentFilePath)) { 347 | continue; 348 | } 349 | String text = codeMap.get(filePath); 350 | if (text.contains(fileName)) { 351 | c++; 352 | break; 353 | } 354 | } 355 | 356 | if (c == 0) { 357 | return false; 358 | } else { 359 | return true; 360 | } 361 | } 362 | 363 | // 只加载jar包中String类型的常量 364 | private static void loadContantsInJar(File f) { 365 | if (f == null || !f.exists()) { 366 | return; 367 | } 368 | if (f.isDirectory()) { 369 | for (File file : f.listFiles()) { 370 | loadContantsInJar(file); 371 | } 372 | } else { 373 | if (f.getName().endsWith(".jar")) { 374 | readJar(f); 375 | } 376 | } 377 | } 378 | 379 | private static void readJar(File f) { 380 | JarFile jarfile = null; 381 | StringBuilder sb = new StringBuilder(); 382 | try { 383 | jarfile = new JarFile(f); 384 | Enumeration entryList = jarfile.entries(); 385 | while (entryList.hasMoreElements()) { 386 | JarEntry jarentry = (JarEntry) entryList.nextElement(); 387 | if (!jarentry.getName().endsWith(".class")) { 388 | continue; 389 | } 390 | try { 391 | InputStream is = jarfile.getInputStream(jarentry); 392 | readContantsInClass(is, sb); 393 | is.close(); 394 | } catch (IOException e) { 395 | } 396 | } 397 | jarfile.close(); 398 | } catch (IOException e) { 399 | } 400 | codeMap.put(f.getAbsolutePath(), sb.toString()); 401 | } 402 | 403 | private static void readContantsInClass(InputStream is, StringBuilder sb) throws IOException { 404 | DataInputStream dis = new DataInputStream(is); 405 | int magic = 0xCAFEBABE; 406 | if (!(magic == dis.readInt())) { 407 | dis.close(); 408 | return; 409 | } 410 | 411 | dis.readShort(); //minor_version 412 | dis.readShort();//major_version 413 | int constant_pool_count = dis.readShort(); 414 | 415 | /* 常量池中数据项类型 类型标志 类型描述 416 | CONSTANT_Utf8 1 UTF-8编码的Unicode字符串 417 | CONSTANT_Integer 3 int类型字面值 418 | CONSTANT_Float 4 float类型字面值 419 | CONSTANT_Long 5 long类型字面值 420 | CONSTANT_Double 6 double类型字面值 421 | CONSTANT_Class 7 对一个类或接口的符号引用 422 | CONSTANT_String 8 String类型字面值 423 | CONSTANT_Fieldref 9 对一个字段的符号引用 424 | CONSTANT_Methodref 10 对一个类中声明的方法的符号引用 425 | CONSTANT_InterfaceMethodref 11 对一个接口中声明的方法的符号引用 426 | CONSTANT_NameAndType 12 对一个字段或方法的部分符号引用 427 | */ 428 | for (int i = 1; i < constant_pool_count; i++) { // 常量池 429 | int tag = dis.readByte(); 430 | switch (tag) { 431 | case 1: //CONSTANT_Utf8 432 | short len = dis.readShort(); 433 | if (len < 0) { 434 | System.out.println("len " + len); 435 | continue; 436 | } 437 | byte[] bs = new byte[len]; 438 | dis.read(bs); 439 | pln(new String(bs), sb); 440 | continue; 441 | case 3: //CONSTANT_Integer 442 | int v_int = dis.readInt(); 443 | pln(v_int, sb); 444 | continue; 445 | case 4: //CONSTANT_Float 446 | float v_float = dis.readFloat(); 447 | pln(v_float, sb); 448 | continue; 449 | case 5: //CONSTANT_Long 450 | long v_long = dis.readLong(); 451 | pln(v_long, sb); 452 | continue; 453 | case 6: //CONSTANT_Double 454 | double v_double = dis.readDouble(); 455 | pln(v_double, sb); 456 | continue; 457 | case 7: //CONSTANT_String 458 | dis.readShort(); 459 | continue; 460 | case 8: //CONSTANT_String 461 | dis.readShort(); 462 | continue; 463 | case 9: //CONSTANT_Fieldref_info 464 | dis.readShort(); //指向一个CONSTANT_Class_info数据项 465 | dis.readShort(); //指向一个CONSTANT_NameAndType_info 466 | continue; 467 | case 10: //CONSTANT_Methodref_info 468 | dis.readShort(); //指向一个CONSTANT_Class_info数据项 469 | dis.readShort(); //指向一个CONSTANT_NameAndType_info 470 | continue; 471 | case 11: //CONSTANT_InterfaceMethodref_info 472 | dis.readShort(); //指向一个CONSTANT_Class_info数据项 473 | dis.readShort(); //指向一个CONSTANT_NameAndType_info 474 | continue; 475 | case 12: 476 | dis.readShort(); 477 | dis.readShort(); 478 | continue; 479 | default: 480 | return; 481 | } 482 | } 483 | } 484 | 485 | private static void pln(Object string, StringBuilder sb) { 486 | sb.append(string.toString()).append("\n"); 487 | } 488 | 489 | // 加载文件夹中的代码 490 | private static void loadDirCode(File dir) { 491 | // System.out.println("加载代码:" + dir.getAbsolutePath()); 492 | if (dir == null || !dir.exists() || dir.isFile() || dir.listFiles() == null) { 493 | return; 494 | } 495 | 496 | // System.out.println(dir.getAbsoluteFile()); 497 | 498 | for (File f : dir.listFiles()) { 499 | if (f.isDirectory()) { 500 | loadDirCode(f); 501 | } else { 502 | if (f.getName().endsWith(".xml") || f.getName().endsWith(".java")) { 503 | loadFileCode(f); 504 | } 505 | } 506 | } 507 | } 508 | 509 | // 加载代码 510 | private static void loadFileCode(File f) { 511 | if (f == null || f.isDirectory() || !f.exists()) { 512 | return; 513 | } 514 | 515 | if (isExclude(f)) { 516 | return; 517 | } 518 | 519 | StringBuilder sb = new StringBuilder(); 520 | try { 521 | FileReader fr = new FileReader(f); 522 | BufferedReader sr = new BufferedReader(fr); 523 | String s = null; 524 | do { 525 | s = sr.readLine(); 526 | if (s != null) { 527 | sb.append(s).append("\n"); 528 | } else { 529 | break; 530 | } 531 | } while (true); 532 | // System.out.println(f.getAbsolutePath()); 533 | codeMap.put(f.getAbsolutePath(), sb.toString()); 534 | totalBytes += sb.toString().length(); 535 | sr.close(); 536 | } catch (Exception e) { 537 | } 538 | } 539 | 540 | private static void getAllUnusedResExcept() { 541 | allUnusedExp = new ArrayList(); 542 | try { 543 | FileReader fileReader = new FileReader(new File("E:\\pps_svn\\Android N\\APK_Lose_Weight\\ScanUnusedResource\\app\\src\\unused_res_except.txt")); 544 | BufferedReader bufferedReader = new BufferedReader(fileReader); 545 | String line = ""; 546 | while(true){ 547 | line = bufferedReader.readLine(); 548 | if (line != null && !line.isEmpty()) { 549 | allUnusedExp.add(line); 550 | } else { 551 | break; 552 | } 553 | } 554 | } catch (FileNotFoundException e){ 555 | e.printStackTrace(); 556 | Log.d(TAG, e.getMessage()); 557 | } catch (IOException E){ 558 | 559 | } finally{ 560 | 561 | } 562 | 563 | } 564 | 565 | public static boolean isExclude(File file) { 566 | 567 | String filepath = file.getAbsolutePath(); 568 | 569 | for (int i = 0; i < allUnusedExp.size(); i ++){ 570 | String filename = allUnusedExp.get(i); 571 | 572 | if (filepath.equals(filename) || file.getName().equals(filename)) { 573 | // System.out.print("-----------------------" + filepath + "\n"); 574 | return true; 575 | } 576 | } 577 | 578 | return false; 579 | } 580 | } 581 | --------------------------------------------------------------------------------