基于aapt实现全尺寸解析apk图标

package com.xunlei.app.tools;

import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * @author pengjin 2013-08-01
 * 
 * 
 * apk icon全尺寸解析(解决有些apk解析信息比较特殊的bug:application-icon-120:'res/drawable-xlarge-mdpi/appicon.xml)
 */
public class ApkIconTool {

	public static String separator = File.separator;
	static String[] dpis = new String[] { "ldpi", "mdpi", "hdpi", "xhdpi" };
	/**
	 * 解析获取icon
	 * 
	 * @param apkPath
	 * @param imgPath
	 * @throws InterruptedException
	 * @throws IOException
	 */
	public static void getIcon(String apkPath, String imgPath)
			throws InterruptedException, IOException {
		// 通过aapt解析apk信息到文件中

		String apkName = apkPath.substring(apkPath.lastIndexOf(separator) + 1);
		if (!isLinux() && apkName.indexOf(".") != -1) {
			apkName = apkName.substring(0, apkName.lastIndexOf("."));
		}
		String imgDir = imgPath
				.substring(0, imgPath.lastIndexOf(separator) + 1);
		String imgName = imgPath.substring(imgPath
				.lastIndexOf(separator) + 1);
		String aaptPath = ApkIconTool.class.getClassLoader()
				.getResource("config.xml").getPath();
		// 打包后在windows环境下
		if (aaptPath.startsWith("file:/") && !isLinux()) {
			//System.out.println("run in windows");
			aaptPath = aaptPath.substring(6);
		}
		// 打包后在linux环境下
		if (aaptPath.startsWith("file:/") && isLinux()) {
			//System.out.println("run in linux");
			aaptPath = aaptPath.substring(5);
		}
		// 调试环境和linux下aaptPath都会以"/"开头
		if (aaptPath.startsWith("/") && !isLinux()) {
			//System.out.println("调试环境下");
			aaptPath = aaptPath.substring(1);
		}
		aaptPath = aaptPath.substring(0, aaptPath.indexOf("config.xml") - 1);
		aaptPath = aaptPath.substring(0, aaptPath.lastIndexOf("/") + 1);
		aaptPath = isLinux() ? aaptPath + "aapt" : aaptPath + "aapt.exe";
		Process pcs = null;
		try {
			/*String commond = aaptPath + " d badging  " + apkPath + ">" + imgDir
					+ apkName + ".txt";*/
			String commond = aaptPath + " d badging  " + apkPath ;
			/*
			 * System.out.println("---------exec commond:" + commond +
			 * "---------------------");
			 */
			String[] shell = { "/bin/sh", "-c", commond };
			String[] cmd = { "cmd.exe ", "/C", commond };
			if (isLinux()) {
				pcs = Runtime.getRuntime().exec(shell);
			} else {
				pcs = Runtime.getRuntime().exec(cmd);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		InputStream msgStream = pcs.getInputStream();
		// 解析apk信息文件。获取icon路径及icon名
		//String msgPath = imgDir + apkName + ".txt";
		// 全尺寸解析icon图标
		//Map iconInfo = getIconInfo(msgPath);
		//new File(msgPath).delete();
		Map iconInfo = getIconInfoEX(msgStream);
		pcs.waitFor();// 阻塞外部程序
		/*String iconPath = null;
		// 优先使用72*72图片
		iconPath = iconInfo.get("hdpi") == null ? iconInfo.get("default")
				: iconInfo.get("hdpi");
		iconInfo.put("default", iconPath);*/
		//System.out.println("aapt Last iconPath====================" + iconPath);
		// 解压apk包查找icon
		if(iconInfo==null){//aapt解析不出调apktool反编译
			GetIconFile.getIcon(apkPath, imgDir, imgName);
			Map iconResult = new HashMap();
			for (String dpi : dpis) {
				iconResult.put(dpi, "");
			}
			iconResult.put("hdpi", imgPath+";"+getIconDpi(imgPath));
			//打印结果
			printMapJson(iconResult);
		}else{
			writeFile(apkPath, imgPath, iconInfo);
		}
	}

	/**
	 * @return
	 * 
	 *         判断是否是linux
	 */
	public static boolean isLinux() {
		return !"\\".equals(File.separator);
	}

	/**
	 * 获取icon各分辨率路径及apk使用的icon路径
	 * 
	 * @param path
	 * @return
	 * @throws IOException
	 */
	public static Map getIconInfo(String path)
			throws IOException {
		Map map = new HashMap();
		for (String dpi : dpis) {
			map.put(dpi, "");
		}
		String iconPath = "";
		String iconRealPath = "";
		BufferedReader br = null;
		boolean isDpiExsis = false;
		try {
			br = new BufferedReader(new FileReader(path));
			String s = null;
			while ((s = br.readLine()) != null) {
				// 各分辨率下icon路径
				if (s.indexOf("application-icon") != -1) {
					iconPath = s.substring(s.lastIndexOf(":") + 2,
							s.length() - 1);
					if(iconPath.endsWith(".xml")){
						return null;
					}
					for (String dpi : dpis) {
						if (s.indexOf("drawable-" + dpi) != -1) {
							isDpiExsis = true;
							map.put(dpi, iconPath);
						}
					}
				}
				// apk实际使用icon
				if (s.indexOf("icon=") != -1 && "".equals(iconRealPath)) {
					iconRealPath = s.substring(s.indexOf("icon") + 6,
							s.length() - 1);
					//map.put("default", iconRealPath);
				}
			}
			//如果没有application-icon-120:'res/drawable/icontaxi.png 信息,保存apk实际使用icon信息
			if(!isDpiExsis){
				map.put("hdpi", iconRealPath);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (br != null) {
				br.close();
			}
		}
		return map;
	}
	
	/**
	 * 获取icon各分辨率路径及apk使用的icon路径
	 * 
	 * @param path
	 * @return
	 * @throws IOException
	 */
	public static Map getIconInfoEX(InputStream stream)
			throws IOException {
		Map map = new HashMap();
		for (String dpi : dpis) {
			map.put(dpi, "");
		}
		String iconPath = "";
		String iconRealPath = "";
		BufferedReader br = null;
		boolean isDpiExsis = false;
		try {
			br = new BufferedReader(new InputStreamReader(stream));
			String s = null;
			while ((s = br.readLine()) != null) {
				// 各分辨率下icon路径
				if (s.indexOf("application-icon") != -1) {
					iconPath = s.substring(s.lastIndexOf(":") + 2,
							s.length() - 1);
					if(iconPath.endsWith(".xml")){
						return null;
					}
					for (String dpi : dpis) {
						if (s.indexOf("drawable-" + dpi) != -1) {
							isDpiExsis = true;
							map.put(dpi, iconPath);
						}
					}
				}
				// apk实际使用icon
				if (s.indexOf("icon=") != -1 && "".equals(iconRealPath)) {
					iconRealPath = s.substring(s.indexOf("icon") + 6,
							s.length() - 1);
					//map.put("default", iconRealPath);
				}
			}
			if(!isDpiExsis){
				map.put("hdpi", iconRealPath);
			}
			/*System.out.println("aapt Default iconPath==============="
					+ iconRealPath);*/
			//printMapJson(map);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (br != null) {
				br.close();
			}
			stream.close();
		}
		return map;
	}

	/**
	 * 
	 * 
	 * 根据解析的icon信息遍历apk输出图片
	 * 
	 * 
	 * @param apkPath
	 * @param imgPath
	 * @param iconInfo
	 * @throws IOException
	 */
	public static void writeFile(String apkPath, String imgPath,
			Map iconInfo) throws IOException {
		FileInputStream in = null;
		ZipInputStream zipin = null;
		Map iconResult = new HashMap();
		for (String dpi : dpis) {
			iconResult.put(dpi, "");
		}
		try {
			in = new FileInputStream(apkPath);
			zipin = new ZipInputStream(in);
			ZipEntry entry = null;
			while ((entry = zipin.getNextEntry()) != null) {
				String name = entry.getName();
				for (Entry e : iconInfo.entrySet()) {
					if (!"".equals(e.getValue())&&!"default".equals(e.getKey())&&name.contains(e.getValue())) {
						String imgDir = imgPath.substring(0,
								imgPath.lastIndexOf(separator) + 1);
						String imgName = imgPath.substring(imgPath
								.lastIndexOf(separator) + 1);
						if (!isLinux()&&imgName.indexOf(".") != -1) {
							imgName = imgName
									.substring(0, imgName.lastIndexOf("."))
									+ "_"
									+ e.getKey()
									+ imgName
											.substring(imgName.lastIndexOf("."));
						} else {
							imgName += "_" + e.getKey();
						}
						String dpiPath = imgDir + imgName;
						FileOutputStream out = new FileOutputStream(new File(
								dpiPath));
						byte[] buff = new byte[1024];
						int n = 0;
						while ((n = zipin.read(buff, 0, buff.length)) != -1) {
							out.write(buff, 0, n);
						}
						iconResult.put(e.getKey(), dpiPath+";"+getIconDpi(dpiPath));
						iconInfo.remove(e.getKey());
						break;
					}
				}
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (in != null) {
				in.close();
			}
			if (zipin != null) {
				zipin.close();
			}
		}
		/*//加入default icon
		for(Entry e : iconResult.entrySet()){
			if(iconInfo.get("default").contains(e.getKey())){
				iconResult.put("default",e.getValue());
				break;
			}
		}*/
		//打印结果
		printMapJson(iconResult);
	}
	
	public static void printMapJson(Map map){
		StringBuffer sb = new StringBuffer();
		sb.append("{");
		int i=0;
		for(Entry e : map.entrySet()){
			i++;
			sb.append("\"").append(e.getKey()).append("\":").append("\"").append(e.getValue()).append("\"");
			if(i


你可能感兴趣的:(基于aapt实现全尺寸解析apk图标)