Java解析apk、ipa图标,包名,应用名称,版本号
这篇文章主要针对apk、ipa解析图标,当然也会顺带解析其他一些基本信息,
比如:包名、版本号、版本名、应用名称。
之前google了好多文章,没有完整的可以解决图标的博文。今天我就为大家带来一篇。
首先给大家吃一颗定心丸:这篇文章绝对可以帮助大家解析出来图标的。只要你的apk和ipa文件不是
损坏,是正常的,绝对是百发百中,弹无虚发,屡试不爽。
如果,大家不是为了解析图标而来,那么就不需要看这篇文章了,
请移步到:
完整版java读取apk、ipa包名、版本名、版本号等信息 (附源码)
大家需要做的只是耐心看完这篇文章。
首先大家看一下效果图:
接下来步入正题。。。。。。
#1、首先看一下用到什么工具
环境:linux
解析apk
(1). aapt工具
解析ipa
(1). python2.6
#2、解析apk
对于apk的解析,我是一万个不想用到aapt这个工具,感觉太烦人,如果能通过只需要引用几个jar包,
用代码读取出来多好。
事实上,读取一般信息,是可以的,对于,apk的名称,是不好获取的。我们知道安卓名称都是
android:label=“@string/app_name” 这种方式,定义一个变量,然后就增加了我们获取的难度,
还有另一个难点就是对于图标的获取。我知道可以通过以下方式获取,前提是你要知道图标的名称。
//上面代码省略。。。。。。。
zipFile = new ZipFile(apkUrl);Enumeration> enumeration = zipFile.entries();ZipEntry zipEntry = null;while (enumeration.hasMoreElements()) {zipEntry = (ZipEntry) enumeration.nextElement();//我知道图片的图标名称就叫appicon_logo,所以可以这样获取if (zipEntry.getName().contains("appicon_logo")) {int length = 0;byte b[] = new byte [1024];OutputStream outputStream = new FileOutputStream(new File("E:\\python\\img\\apkicon.png"));InputStream inputStream = zipFile.getInputStream(zipEntry); while (-1 != (length = inputStream.read(b))){outputStream.write(b, 0, length);}outputStream.close();break;}}
//下面代码省略。。。。。。
但是,一般我们要解析的,是我们不知道的apk,所以,我们就要获取图标的名称,然而,无论我怎么通过代码解析,就是获取不到,哎,不得已,只能用到aapt工具了。
##2.1. linux下安装aapt
请移步到这篇博客
linux 64位 安装aapt
window环境下,只需要下载aapt.exe就ok了
首先新建一个实体类
/*** @author ZSL* @since 2016年12月7日* @desc [apk实体信息]*/
public class ApkInfo{public static final String APPLICATION_ICON_120 = "application-icon-120";public static final String APPLICATION_ICON_160 = "application-icon-160";public static final String APPLICATION_ICON_240 = "application-icon-240";public static final String APPLICATION_ICON_320 = "application-icon-320";/*** apk内部版本号*/private String versionCode = null;/*** apk外部版本号*/private String versionName = null;/*** apk的包名*/private String packageName = null;/*** 支持的android平台最低版本号*/private String minSdkVersion = null;/*** apk所需要的权限*/private List usesPermissions = null;/*** 支持的SDK版本。*/private String sdkVersion;/*** 建议的SDK版本*/private String targetSdkVersion;/*** 应用程序名*/private String applicationLable;/*** 各个分辨率下的图标的路径。*/private Map applicationIcons;/*** 程序的图标。*/private String applicationIcon;/*** 暗指的特性。*/private List impliedFeatures;/*** 所需设备特性。*/private List features;/*** 启动界面*/private String launchableActivity;public ApkInfo() {this.usesPermissions = new ArrayList();this.applicationIcons = new HashMap();this.impliedFeatures = new ArrayList();this.features = new ArrayList();}/*** 返回版本代码。* * @return 版本代码。*/public String getVersionCode() {return versionCode;}/*** @param versionCode* the versionCode to set*/public void setVersionCode(String versionCode) {this.versionCode = versionCode;}/*** 返回版本名称。* * @return 版本名称。*/public String getVersionName() {return versionName;}/*** @param versionName* the versionName to set*/public void setVersionName(String versionName) {this.versionName = versionName;}/*** 返回支持的最小sdk平台版本。* * @return the minSdkVersion*/public String getMinSdkVersion() {return minSdkVersion;}/*** @param minSdkVersion* the minSdkVersion to set*/public void setMinSdkVersion(String minSdkVersion) {this.minSdkVersion = minSdkVersion;}/*** 返回包名。* * @return 返回的包名。*/public String getPackageName() {return packageName;}public void setPackageName(String packageName) {this.packageName = packageName;}/*** 返回sdk平台版本。* * @return*/public String getSdkVersion() {return sdkVersion;}public void setSdkVersion(String sdkVersion) {this.sdkVersion = sdkVersion;}/*** 返回所建议的SDK版本。* * @return*/public String getTargetSdkVersion() {return targetSdkVersion;}public void setTargetSdkVersion(String targetSdkVersion) {this.targetSdkVersion = targetSdkVersion;}/*** 返回所需的用户权限。* * @return*/public List getUsesPermissions() {return usesPermissions;}public void setUsesPermissions(List usesPermission) {this.usesPermissions = usesPermission;}public void addToUsesPermissions(String usesPermission) {this.usesPermissions.add(usesPermission);}/*** 返回程序的名称标签。* * @return*/public String getApplicationLable() {return applicationLable;}public void setApplicationLable(String applicationLable) {this.applicationLable = applicationLable;}/*** 返回应用程序的图标。* * @return*/public String getApplicationIcon() {return applicationIcon;}public void setApplicationIcon(String applicationIcon) {this.applicationIcon = applicationIcon;}/*** 返回应用程序各个分辨率下的图标。* * @return*/public Map getApplicationIcons() {return applicationIcons;}public void setApplicationIcons(Map applicationIcons) {this.applicationIcons = applicationIcons;}public void addToApplicationIcons(String key, String value) {this.applicationIcons.put(key, value);}public void addToImpliedFeatures(ImpliedFeature impliedFeature) {this.impliedFeatures.add(impliedFeature);}/*** 返回应用程序所需的暗指的特性。* * @return*/public List getImpliedFeatures() {return impliedFeatures;}public void setImpliedFeatures(List impliedFeatures) {this.impliedFeatures = impliedFeatures;}/*** 返回应用程序所需的特性。* * @return*/public List getFeatures() {return features;}public void setFeatures(List features) {this.features = features;}public void addToFeatures(String feature) {this.features.add(feature);}@Overridepublic String toString() {return "ApkInfo [versionCode=" + versionCode + ",\n versionName="+ versionName + ",\n packageName=" + packageName+ ",\n minSdkVersion=" + minSdkVersion + ",\n usesPermissions="+ usesPermissions + ",\n sdkVersion=" + sdkVersion+ ",\n targetSdkVersion=" + targetSdkVersion+ ",\n applicationLable=" + applicationLable+ ",\n applicationIcons=" + applicationIcons+ ",\n applicationIcon=" + applicationIcon+ ",\n impliedFeatures=" + impliedFeatures + ",\n features="+ features + ",\n launchableActivity=" + launchableActivity + "\n]";}public String getLaunchableActivity() {return launchableActivity;}public void setLaunchableActivity(String launchableActivity) {this.launchableActivity = launchableActivity;}}
还需要一个实体
/*** @author ZSL* @since 2016年12月7日* @desc [特性实体]*/
public class ImpliedFeature { /*** 要的设备特性名称。*/private String feature;/*** 表明所需特性的内容。*/private String implied;public ImpliedFeature() {super();}public ImpliedFeature(String feature, String implied) {super();this.feature = feature;this.implied = implied;}public String getFeature() {return feature;}public void setFeature(String feature) {this.feature = feature;}public String getImplied() {return implied;}public void setImplied(String implied) {this.implied = implied;}@Overridepublic String toString() {return "Feature [feature=" + feature + ", implied=" + implied + "]";}
}
以上两个实体,大家不需要特别关心。
接下来一个解析apk的工具类
public class ApkUtil {public static final String VERSION_CODE = "versionCode";public static final String VERSION_NAME = "versionName";public static final String SDK_VERSION = "sdkVersion";public static final String TARGET_SDK_VERSION = "targetSdkVersion";public static final String USES_PERMISSION = "uses-permission";public static final String APPLICATION_LABEL = "application-label";public static final String APPLICATION_ICON = "application-icon";public static final String USES_FEATURE = "uses-feature";public static final String USES_IMPLIED_FEATURE = "uses-implied-feature";public static final String SUPPORTS_SCREENS = "supports-screens";public static final String SUPPORTS_ANY_DENSITY = "supports-any-density";public static final String DENSITIES = "densities";public static final String PACKAGE = "package";public static final String APPLICATION = "application:";public static final String LAUNCHABLE_ACTIVITY = "launchable-activity";private ProcessBuilder mBuilder;private static final String SPLIT_REGEX = "(: )|(=')|(' )|'";private static final String FEATURE_SPLIT_REGEX = "(:')|(',')|'";/*** aapt所在的目录。*///windows环境下直接指向appt.exe//比如你可以放在lib下//private String mAaptPath = "lib/aapt";//下面是linux下private String mAaptPath = "/usr/local/python/img/aapt";public ApkUtil() {mBuilder = new ProcessBuilder();mBuilder.redirectErrorStream(true);}/*** 返回一个apk程序的信息。* * @param apkPath* apk的路径。* @return apkInfo 一个Apk的信息。*/public ApkInfo getApkInfo(String apkPath) throws Exception {//通过命令调用aapt工具解析apk文件Process process = mBuilder.command(mAaptPath, "d", "badging", apkPath).start();InputStream is = null;is = process.getInputStream();BufferedReader br = new BufferedReader(new InputStreamReader(is, "utf8"));String tmp = br.readLine();try {if (tmp == null || !tmp.startsWith("package")) {throw new Exception("参数不正确,无法正常解析APK包。输出结果为:\n" + tmp + "...");}ApkInfo apkInfo = new ApkInfo();do {System.out.println("==============apkInfo");System.out.println(tmp);setApkInfoProperty(apkInfo, tmp);} while ((tmp = br.readLine()) != null);return apkInfo;} catch (Exception e) {throw e;} finally {process.destroy();closeIO(is);closeIO(br);}}/*** 设置APK的属性信息。* * @param apkInfo* @param source*/private void setApkInfoProperty(ApkInfo apkInfo, String source) {if (source.startsWith(PACKAGE)) {splitPackageInfo(apkInfo, source);} else if(source.startsWith(LAUNCHABLE_ACTIVITY)){apkInfo.setLaunchableActivity(getPropertyInQuote(source));} else if (source.startsWith(SDK_VERSION)) {apkInfo.setSdkVersion(getPropertyInQuote(source));} else if (source.startsWith(TARGET_SDK_VERSION)) {apkInfo.setTargetSdkVersion(getPropertyInQuote(source));} else if (source.startsWith(USES_PERMISSION)) {apkInfo.addToUsesPermissions(getPropertyInQuote(source));} else if (source.startsWith(APPLICATION_LABEL)) {//window下获取应用名称apkInfo.setApplicationLable(getPropertyInQuote(source));} else if (source.startsWith(APPLICATION_ICON)) {apkInfo.addToApplicationIcons(getKeyBeforeColon(source),getPropertyInQuote(source));} else if (source.startsWith(APPLICATION)) {String[] rs = source.split("( icon=')|'");apkInfo.setApplicationIcon(rs[rs.length - 1]);//linux下获取应用名称apkInfo.setApplicationLable(rs[1]);} else if (source.startsWith(USES_FEATURE)) {apkInfo.addToFeatures(getPropertyInQuote(source));} else if (source.startsWith(USES_IMPLIED_FEATURE)) {apkInfo.addToImpliedFeatures(getFeature(source));} else {
// System.out.println(source);}}private ImpliedFeature getFeature(String source) {String[] result = source.split(FEATURE_SPLIT_REGEX);ImpliedFeature impliedFeature = new ImpliedFeature(result[1], result[2]);return impliedFeature;}/*** 返回出格式为name: 'value'中的value内容。* * @param source* @return*/private String getPropertyInQuote(String source) {int index = source.indexOf("'") + 1;return source.substring(index, source.indexOf('\'', index));}/*** 返回冒号前的属性名称* * @param source* @return*/private String getKeyBeforeColon(String source) {return source.substring(0, source.indexOf(':'));}/*** 分离出包名、版本等信息。* * @param apkInfo* @param packageSource*/private void splitPackageInfo(ApkInfo apkInfo, String packageSource) {String[] packageInfo = packageSource.split(SPLIT_REGEX);apkInfo.setPackageName(packageInfo[2]);apkInfo.setVersionCode(packageInfo[4]);apkInfo.setVersionName(packageInfo[6]);}/*** 释放资源。* * @param c* 将关闭的资源*/private final void closeIO(Closeable c) {if (c != null) {try {c.close();} catch (IOException e) {e.printStackTrace();}}}public static void main(String[] args) {try {String demo = "src/test.apk.apk";ApkInfo apkInfo = new ApkUtil().getApkInfo(demo);System.out.println(apkInfo);} catch (Exception e) {e.printStackTrace();} }public String getmAaptPath() {return mAaptPath;}public void setmAaptPath(String mAaptPath) {this.mAaptPath = mAaptPath;}
}
下面这个是获取apk图标的工具类
/*** 通过ApkInfo 里的applicationIcon从APK里解压出icon图片并存放到磁盘上* @author zsl* */
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();}/*** demo 获取apk文件的icon并写入磁盘指定位置* @param args*/public static void main(String[] args) {try {String apkpath = "D:\\DefaultApkTempSaveFolder\\3G安卓市场\\com.jiubang.market.apk";if (args.length > 0) {apkpath = args[0];}ApkInfo apkInfo = new ApkUtil().getApkInfo(apkpath);System.out.println(apkInfo);extractFileFromApk(apkpath, apkInfo.getApplicationIcon(), "D:\\DefaultApkTempSaveFolder\\3G安卓市场\\crawler\\icon.png");} catch (Exception e) {e.printStackTrace();}}
apk就解析结束!
#** 3、解析ipa**
##3.1. 解析图片
解析ipa基本属性需要用到dd-plist-1.16.jar
下载地址:dd-plist-1.16.jar
对于获取图标,大家可以先看我另一篇博客:
完整版java读取apk、ipa包名、版本名、版本号等信息
plist结构如下:
我们可以通过如下方式获取
然后根据名称去下载
最终可以获取到图片并下载到本地
很多人都会遇到这个问题:有的图标是正常的,而有的图标却是黑色的,打不开。
根据网上搜索的资料,大家或者找到了办法,就是通过ipin.py (python脚本)来反序列化恢复正常的图片。
我这边也下载了那个文件试了下,大家看效果:
大家一定注意到了吧,那张图片本来是黑色的,执行了一次之后,就恢复正常了, 然而再次执行之后,就变得更糟了,变成一张损坏的图片,完全打不开。。。。。
我们可以先生成一张黑色的图片,然后执行ipin.py恢复成好的图片,然后把这张图片移动另一个目录。
哎呦 ,这貌似是一个不错的想法,但是,如果,你解析的ipa图片,本身就是一张好的图片,这种情况不是不可能的,不是所有的图标本身就是黑色的。比如:爱奇艺的ipa,图片本身就是正常的,这时候你去ipin.py一下,那么这就尴尬了。
解决办法:
根据之前的ipin.py文件,修改了一下,现在的功能是遇到好的图片就跳过,不去反序列它,遇到黑色图片才去做操作。
请看效果:
没错,程序会报错,直接跳过这张图片。继续执行。
##3.1. python 反序列图片
安装大家可以到这里:
Python环境搭建
对于linux环境,一般python都是安装好的,大家可以直接输入python命令
如果版本太高下面执行会有问题,我的python版本是2.7的
下面最重要的来了,就是那个改进过的ipin.py文件。跳过正常图片。
#---
# iPIN - iPhone PNG Images Normalizer v1.0
# Copyright (C) 2007
#
# Author:
# Axel E. Brzostowski
# http://www.axelbrz.com.ar/
# axelbrz@gmail.com
#
# References:
# http://iphone.fiveforty.net/wiki/index.php/PNG_Images
# http://www.libpng.org/pub/png/spec/1.2/PNG-Contents.html
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#---from struct import *
from zlib import *
import stat
import sys
import os
import shutil
import globdef getNormalizedPNG(filename):pngheader = "\x89PNG\r\n\x1a\n"file = open(filename, "rb")oldPNG = file.read()file.close()if oldPNG[:8] != pngheader:return NonenewPNG = oldPNG[:8]chunkPos = len(newPNG)idatAcc = ""breakLoop = False# For each chunk in the PNG file while chunkPos < len(oldPNG):skip = False# Reading chunkchunkLength = oldPNG[chunkPos:chunkPos+4]chunkLength = unpack(">L", chunkLength)[0]chunkType = oldPNG[chunkPos+4 : chunkPos+8]chunkData = oldPNG[chunkPos+8:chunkPos+8+chunkLength]chunkCRC = oldPNG[chunkPos+chunkLength+8:chunkPos+chunkLength+12]chunkCRC = unpack(">L", chunkCRC)[0]chunkPos += chunkLength + 12# Parsing the header chunkif chunkType == "IHDR":width = unpack(">L", chunkData[0:4])[0]height = unpack(">L", chunkData[4:8])[0]# Parsing the image chunkif chunkType == "IDAT":# Store the chunk data for later decompressionidatAcc += chunkDataskip = True# Removing CgBI chunk if chunkType == "CgBI":skip = True# Add all accumulated IDATA chunksif chunkType == "IEND":try:# Uncompressing the image chunkbufSize = width * height * 4 + heightchunkData = decompress( idatAcc, -15, bufSize)except Exception, e:# The PNG image is normalizedprint ereturn NonechunkType = "IDAT"# Swapping red & blue bytes for each pixelnewdata = ""for y in xrange(height):i = len(newdata)newdata += chunkData[i]for x in xrange(width):i = len(newdata)newdata += chunkData[i+2]newdata += chunkData[i+1]newdata += chunkData[i+0]newdata += chunkData[i+3]# Compressing the image chunkchunkData = newdatachunkData = compress( chunkData )chunkLength = len( chunkData )chunkCRC = crc32(chunkType)chunkCRC = crc32(chunkData, chunkCRC)chunkCRC = (chunkCRC + 0x100000000) % 0x100000000breakLoop = Trueif not skip:newPNG += pack(">L", chunkLength)newPNG += chunkTypeif chunkLength > 0:newPNG += chunkDatanewPNG += pack(">L", chunkCRC)if breakLoop:breakreturn newPNGdef updatePNG(filename):data = getNormalizedPNG(filename)if data != None:file = open(filename, "wb")file.write(data)file.close()return Truereturn datadef getFiles(base):global _dirsglobal _pngsif base == ".":_dirs = []_pngs = []if base in _dirs:returnfiles = os.listdir(base)for file in files:filepath = os.path.join(base, file)try:st = os.lstat(filepath)except os.error:continueif stat.S_ISDIR(st.st_mode):if not filepath in _dirs:getFiles(filepath)_dirs.append( filepath )elif file[-4:].lower() == ".png":if not filepath in _pngs:_pngs.append( filepath )if base == ".":return _dirs, _pngsprint "-----------------------------------"
print " iPhone PNG Images Normalizer v1.0"
print "-----------------------------------"
print " "
print "[+] Searching PNG files...",
dirs, pngs = getFiles(".")
print "ok"if len(pngs) == 0:print " "print "[!] Alert: There are no PNG files found. Move this python file to the folder that contains the PNG files to normalize."exit()print " "
print " - %d PNG files were found at this folder (and subfolders)." % len(pngs)
print " "
while True:normalize = "y"if len(normalize) > 0 and (normalize[0] == "y" or normalize[0] == "n"):breaknormalized = 0
if normalize[0] == "y":for ipng in xrange(len(pngs)):perc = (float(ipng) / len(pngs)) * 100.0print "%.2f%% %s" % (perc, pngs[ipng])if updatePNG(pngs[ipng]):normalized += 1
print " "
print "[+] %d PNG files were normalized." % normalizedfor filename in glob.glob(r'/E:/python/img2/*.png'):shutil.move(filename,"/E:/python/img")print filename
大家需要注意的地方有一点,最后三行代码是我加上的,意思是把发序列的正常图片,
全部移到另一个文件夹里,这样做的好处是什么呢?
1、如果我们上传解析很多ipa文件,
那么理所当然的也就生成很多图标,如果,都放在反序列化的文件夹,而不移走的话,
那么, 程序,每次都会去查找有哪些图片需要反序列,这都是耗时的。
2、那些之前是黑色的,被反序列成正常图片之后是没问题的,如果再次反序列还是
会照样变成损坏的图片。上面改进过的ipin.py文件虽然改进过了,但是它只是针对
源文件是正常图片,而不是本身是黑色图片,这时你转成正常图片,再转一次,还是
会有问题。
其实两者是不矛盾的。
下面需要做的就是写个shell脚本,然后用程序去调用了。
shell脚本
#!/bin/sh
cd /usr/local/python/img/
python ipin.py
下面是后台代码:
/*** @author ZSL* @param ipaURL* @return* @desc [解析ipa文件]*/public static Map getIpaInfo(String ipaURL , HttpServletRequest request){Map map = new HashMap();String newIconName = "";try {File file = new File(ipaURL);InputStream is = new FileInputStream(file);InputStream is2 = new FileInputStream(file);ZipInputStream zipIns = new ZipInputStream(is);ZipInputStream zipIns2 = new ZipInputStream(is2);ZipEntry ze;ZipEntry ze2;InputStream infoIs = null;NSDictionary rootDict = null;String icon = null;while ((ze = zipIns.getNextEntry()) != null) {if (!ze.isDirectory()) {String name = ze.getName();if (null != name && name.toLowerCase().contains("info.plist")) {ByteArrayOutputStream _copy = new ByteArrayOutputStream();int chunk = 0;byte[] data = new byte[1024];while(-1!=(chunk=zipIns.read(data))){_copy.write(data, 0, chunk);}infoIs = new ByteArrayInputStream(_copy.toByteArray());rootDict = (NSDictionary) PropertyListParser.parse(infoIs);NSDictionary iconDict = (NSDictionary) rootDict.get("CFBundleIcons");//获取图标名称while (null != iconDict) {if(iconDict.containsKey("CFBundlePrimaryIcon")){NSDictionary CFBundlePrimaryIcon = (NSDictionary) iconDict.get("CFBundlePrimaryIcon"); if(CFBundlePrimaryIcon.containsKey("CFBundleIconFiles")){NSArray CFBundleIconFiles = (NSArray) CFBundlePrimaryIcon.get("CFBundleIconFiles"); icon = CFBundleIconFiles.getArray()[0].toString();if(icon.contains(".png")){icon = icon.replace(".png", "");}System.out.println("获取icon名称:" + icon);break; }}}break;}}}//根据图标名称下载图标文件到指定位置while ((ze2 = zipIns2.getNextEntry()) != null) {if (!ze2.isDirectory()) {String name = ze2.getName();System.out.println("=================name:" + name);if(name.contains(icon.trim())){newIconName = createDateSuffix()+ ".png";FileOutputStream fos = new FileOutputStream(new File(pythonTempImagePath + File.separator + newIconName ));int chunk = 0;byte[] data = new byte[1024];while(-1!=(chunk=zipIns2.read(data))){fos.write(data, 0, chunk);}fos.close();System.out.println("=================下载图片成功");break;}}}//如果想要查看有哪些key ,可以把下面注释放开
// for (String string : dictionary.allKeys()) {
// System.out.println(string + ":" + dictionary.get(string).toString());
// }// 应用包名NSString parameters = (NSString) rootDict.get("CFBundleIdentifier");map.put("package", parameters.toString());// 应用版本名parameters = (NSString) rootDict.objectForKey("CFBundleShortVersionString");map.put("versionName", parameters.toString());//应用版本号parameters = (NSString) rootDict.get("CFBundleVersion");map.put("versionCode", parameters.toString());//应用名称parameters = (NSString) rootDict.get("CFBundleDisplayName");if(null == parameters){parameters = (NSString) rootDict.get("CFBundleName");}map.put("appName", parameters.toString());
// parameters = (NSString) rootDict.get("CFBundlePrimaryIcon");
// map.put("icon", parameters.toString());/infoIs.close();is.close();zipIns.close();} catch (Exception e) {e.printStackTrace();map.put("code", "fail");map.put("error","读取ipa文件失败");}
// finally {
// if (null != infoIs) {
// infoIs.close();
// }
// if (null != is) {
// is.close();
// }
// if (null != zipIns) {
// zipIns.close();
// }
// }System.out.println("================================执行命令获取icon开始=========================");Process process;try {process = Runtime.getRuntime().exec("sh /usr/local/python/img/ipin.sh");BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));String line = null;while ((line = reader.readLine()) != null) {System.out.println(line);}reader.close();process.waitFor();} catch (Exception e) {e.printStackTrace();}System.out.println("================================执行命令获取icon结束=========================");System.out.println("================================图标名称:"+newIconName+"=========================");map.put("icon", newIconName);map.put("code", "success");return map;}
大功告成! ipa文件解析成功 !
再来看一下效果:上传了两个比较大的,100M多
我这里是在linux下操作的,不过windows下也是可以的,只需要把shell脚本改成bat文件,然后 调用系统命令执行bat文件。
下面提供一份源码
Java解析apk、ipa图标,包名,应用名称,版本号源码
希望对大家有所帮助!
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
