Java环境解析apk文件信息

java

概述:Java解析apk文件,获取apk文件里的包名,版本号,图标文件等;

功能:可以提供给windows和linux平台使用;

原理:利用aapt.exe或者aapt这些anroid平台解析apk文件的工具,借用终端shell调用命令解析输出信息;

代码:

      这里贴出一些关键代码,并给出代码注释,如下

  1 package com.apkutils;

2

3 import java.io.BufferedReader;

4 import java.io.Closeable;

5 import java.io.File;

6 import java.io.FileInputStream;

7 import java.io.IOException;

8 import java.io.InputStream;

9 import java.io.InputStreamReader;

10 import java.util.HashMap;

11 import java.util.Map;

12 import java.util.Properties; 16

17

18 /**

19 * apk工具类。封装了获取Apk信息的方法。

20 *

21 * @author @author tony

22 *

23 * <p>

24 * <b>version description</b><br />

25 * V0.2.1 修改程序名字为从路径中获得。

26 * </p>

27 */

28 public class ApkUtil {

29 public static final String VERSION_CODE = "versionCode";

30 public static final String VERSION_NAME = "versionName";

31 public static final String SDK_VERSION = "sdkVersion";

32 public static final String TARGET_SDK_VERSION = "targetSdkVersion";

33 public static final String USES_PERMISSION = "uses-permission";

34 public static final String APPLICATION_LABEL = "application-label";

35 public static final String APPLICATION_ICON = "application-icon";

36 public static final String USES_FEATURE = "uses-feature";

37 public static final String USES_IMPLIED_FEATURE = "uses-implied-feature";

38 public static final String SUPPORTS_SCREENS = "supports-screens";

39 public static final String SUPPORTS_ANY_DENSITY = "supports-any-density";

40 public static final String DENSITIES = "densities";

41 public static final String PACKAGE = "package";

42 public static final String APPLICATION = "application:";

43 public static final String LAUNCHABLE_ACTIVITY = "launchable-activity";

44

45 // api ---- os

46 static Map<String, String> OSVersion = new HashMap<String, String>();

47

48 static {

49 OSVersion.put("3", "1.5");

50 OSVersion.put("4", "1.6");

51 OSVersion.put("5", "2.0");

52 OSVersion.put("6", "2.0.1");

53 OSVersion.put("7", "2.1");

54 OSVersion.put("8", "2.2");

55 OSVersion.put("9", "2.3");

56 OSVersion.put("10", "2.3.3");

57 OSVersion.put("11", "3.0");

58 OSVersion.put("12", "3.1");

59 OSVersion.put("13", "3.2");

60 OSVersion.put("14", "4.0");

61 OSVersion.put("15", "4.0.3");

62 OSVersion.put("16", "4.1.1");

63 OSVersion.put("17", "4.2");

64 OSVersion.put("18", "4.3");

65 OSVersion.put("19", "4.4");

66 }

67

68 private static final String SPLIT_REGEX = "(: )|(=')|(' )|'";

69 private static final String FEATURE_SPLIT_REGEX = "(:')|(',')|'";

70 /**

71 * aapt所在的目录。

72 */

73 private String mAaptPath = "D:\\App\\";//winOS

74 //private String mAaptPath = ApkUtil.class.getClassLoader().getResource("").getPath();//linux

75

76 static String[] shellCommand;

77 static String softName = "";

78 static {

79 shellCommand = new String[2];

80 final String anOSName = System.getProperty("os.name");

81 if (anOSName.toLowerCase().startsWith("windows")) {

82 // Windows XP, Vista ...

83 shellCommand[0] = "cmd";

84 shellCommand[1] = "/C";

85 softName = "aapt.exe";

86 } else {

87 // Unix, Linux ...

88 shellCommand[0] = "/bin/sh";

89 shellCommand[1] = "-c";

90 softName = "aapt";

91 }

92 }

93

94 /***

95 * apkPath

96 */

97 static String apkPath = "C:/Users/win7/Desktop/Android/baiduyinyue_49.apk";

98

99 /**

100 * 返回一个apk程序的信息。

101 *

102 * @param apkPath

103 * apk的路径。

104 * @return apkInfo 一个Apk的信息。

105 */

106 public ApkInfo getApkInfo(String apkPath) throws Exception {

107 String command = mAaptPath + softName + " d badging \"" + apkPath

108 + "\"";

109 Process process;

110 try {

111 process = Runtime.getRuntime().exec(

112 new String[] {shellCommand[0], shellCommand[1], command});

113 } catch (IOException e) {

114 process = null;

115 throw e;

116 }

117

118 ApkInfo apkInfo = null;

119 if(process != null){

120 InputStream is = process.getInputStream();

121 BufferedReader br = new BufferedReader(

122 new InputStreamReader(is, "utf8"));

123 String tmp = br.readLine();

124 try {

125 if (tmp == null || !tmp.startsWith("package")) {

126 throw new Exception("参数不正确,无法正常解析APK包。输出结果为:\n" + tmp + "...");

127 }

128 apkInfo = new ApkInfo();

129 do {

130 setApkInfoProperty(apkInfo, tmp);

131 } while ((tmp = br.readLine()) != null);

132 } catch (Exception e) {

133 throw e;

134 } finally {

135 process.destroy();

136 closeIO(is);

137 closeIO(br);

138 }

139 }

140 return apkInfo;

141 }

142

143 /**

144 * 设置APK的属性信息。

145 *

146 * @param apkInfo

147 * @param source

148 */

149 private void setApkInfoProperty(ApkInfo apkInfo, String source) {

150 if (source.startsWith(PACKAGE)) {

151 splitPackageInfo(apkInfo, source);

152 } else if (source.startsWith(LAUNCHABLE_ACTIVITY)) {

153 apkInfo.setLaunchableActivity(getPropertyInQuote(source));

154 } else if (source.startsWith(SDK_VERSION)) {

155 apkInfo.setSdkVersion(getPropertyInQuote(source));

156 apkInfo.setMinOSVersion(OSVersion.get(getPropertyInQuote(source)));

157 } else if (source.startsWith(TARGET_SDK_VERSION)) {

158 apkInfo.setTargetSdkVersion(getPropertyInQuote(source));

159 } else if (source.startsWith(USES_PERMISSION)) {

160 apkInfo.addToUsesPermissions(getPropertyInQuote(source));

161 } else if (source.startsWith(APPLICATION_LABEL)) {

162 apkInfo.setApplicationLable(getPropertyInQuote(source));

163 } else if (source.startsWith(APPLICATION_ICON)) {

164 apkInfo.addToApplicationIcons(getKeyBeforeColon(source),

165 getPropertyInQuote(source));

166 } else if (source.startsWith(APPLICATION)) {

167 String[] rs = source.split("( icon=')|'");

168 apkInfo.setApplicationIcon(rs[rs.length - 1]);

169 } else if (source.startsWith(USES_FEATURE)) {

170 apkInfo.addToFeatures(getPropertyInQuote(source));

171 } else if (source.startsWith(USES_IMPLIED_FEATURE)) {

172 apkInfo.addToImpliedFeatures(getFeature(source));

173 } else {

174

175 }

176 try {

177 apkInfo.setApkFileSize(getFileSizes(new File(apkPath)));

178 } catch (Exception e) {

179 e.printStackTrace();

180 }

181 }

182

183 private ImpliedFeature getFeature(String source) {

184 String[] result = source.split(FEATURE_SPLIT_REGEX);

185 ImpliedFeature impliedFeature = new ImpliedFeature(result[1], result[2]);

186 return impliedFeature;

187 }

188

189 /**

190 * 返回出格式为name: 'value'中的value内容。

191 *

192 * @param source

193 * @return

194 */

195 private String getPropertyInQuote(String source) {

196 int index = source.indexOf("'") + 1;

197 return source.substring(index, source.indexOf('\'', index));

198 }

199

200 /**

201 * 返回冒号前的属性名称

202 *

203 * @param source

204 * @return

205 */

206 private String getKeyBeforeColon(String source) {

207 return source.substring(0, source.indexOf(':'));

208 }

209

210 /**

211 * 分离出包名、版本等信息。

212 *

213 * @param apkInfo

214 * @param packageSource

215 */

216 private void splitPackageInfo(ApkInfo apkInfo, String packageSource) {

217 String[] packageInfo = packageSource.split(SPLIT_REGEX);

218 apkInfo.setPackageName(packageInfo[2]);

219 apkInfo.setVersionCode(packageInfo[4]);

220 apkInfo.setVersionName(packageInfo[6]);

221 }

222

223 /**

224 * 释放资源。

225 *

226 * @param c

227 * 将关闭的资源

228 */

229 private final void closeIO(Closeable c) {

230 if (c != null) {

231 try {

232 c.close();

233 } catch (IOException e) {

234 e.printStackTrace();

235 }

236 }

237 }

238

239 public static void main(String[] args) {

240 try {

241 ApkInfo apkInfo = new ApkUtil().getApkInfo(apkPath);

242 System.out.println(apkInfo);

243 IconUtil.extractFileFromApk(apkPath, apkInfo.getApplicationIcon(),

244 "D:\\icon.png");

245 } catch (Exception e) {

246 e.printStackTrace();

247 }

248 }

249

250 public String getmAaptPath() {

251 return mAaptPath;

252 }

253

254 public void setmAaptPath(String mAaptPath) {

255 this.mAaptPath = mAaptPath;

256 }

257

258 // 取得文件大小

259 public static long getFileSizes(File f) throws Exception {

260 long s = 0;

261 if (f.exists()) {

262 FileInputStream fis = null;

263 fis = new FileInputStream(f);

264 s = fis.available();

265 } else {

266 System.out.println("文件不存在");

267 }

268 return s;

269 }

270 }

上面加上阴影的部分代码,我想基本都是很好理解的,获取当前运行的操作系统类型,适配上相应的指令和软件,这样可以跨平台操作,而不需要修改代码;

 获取到相应软件后,对apk文件一行一行的进行解析,将相应的属性存到javaBean中,并将apk文件图片通过流的方式写出到文件系统中,

package com.apkutils;

import java.io.BufferedInputStream;

import java.io.BufferedOutputStream;

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.util.zip.ZipEntry;

import java.util.zip.ZipFile;

/**

* 通过ApkInfo 里的applicationIcon从APK里解压出icon图片并存放到磁盘上

* @author @author tony

*/

public class IconUtil {

/**

* 从指定的apk文件里获取指定file的流

* @param apkpath

* @param fileName

* @return

*/

public static InputStream extractFileFromApk(String apkpath, String fileName) {

try {

ZipFile zFile = new ZipFile(apkpath);

ZipEntry entry = zFile.getEntry(fileName);

entry.getComment();

entry.getCompressedSize();

entry.getCrc();

entry.isDirectory();

entry.getSize();

entry.getMethod();

InputStream stream = zFile.getInputStream(entry);

return stream;

} catch (IOException e) {

e.printStackTrace();

}

return null;

}

public static void extractFileFromApk(String apkpath, String fileName, String outputPath) throws Exception {

InputStream is = extractFileFromApk(apkpath, fileName);

File file = new File(outputPath);

BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file), 1024);

byte[] b = new byte[1024];

BufferedInputStream bis = new BufferedInputStream(is, 1024);

while(bis.read(b) != -1){

bos.write(b);

}

bos.flush();

is.close();

bis.close();

bos.close();

}

}

这里没什么好说的,就是用JavaIO中zip的方式解析文件,并拿出图标写出到指定文件目录

参考文献 : 

纯java从apk文件里获取包名、版本号、icon

以上是 Java环境解析apk文件信息 的全部内容, 来源链接: utcz.com/z/391897.html

回到顶部