/**
AndroidInfoUtils:安卓游戏包信息工具类
**/
1 public class AndroidInfoUtils
{
@SuppressWarnings("unchecked")
public static ApkInfo getAndroidInfo(String apkPath) throws DocumentException
{
ApkInfo apkinfo = new ApkInfo();
File file = new File(apkPath);
// 获得APK文件名称
apkinfo.setApkName(file.getName());
// 获得APK文件大小
apkinfo.setApkSize(convertFileSize(file.length()));
// 获得APK文件原始大小
apkinfo.setApkByteSize(file.length()); String xml = AXMLPrinter2.getManifestXMLFromAPK(apkPath);
//System.out.println(xml);
StringReader read = new StringReader(xml);
InputSource scource = new InputSource(read);
SAXReader sax = new SAXReader();
Document root = sax.read(scource);
Element uses_sdk = (Element) root.selectSingleNode("//uses-sdk");
// 获取APK支持的Android SDK版本
apkinfo.setApkMinsdkversion(uses_sdk.attributeValue("minSdkVersion")); // zhouning 设置sdk目标版本
apkinfo.setApkTargetSdkVersion(uses_sdk.attributeValue("targetSdkVersion")); Element manifest = (Element) root.selectSingleNode("//manifest");
// 获取APK版本
apkinfo.setApkVersion(manifest.attributeValue("versionName"));
// 获取APK包名
apkinfo.setApkPageage(manifest.attributeValue("package"));
// 获取APK版本代码
apkinfo.setApkVersionCode(manifest.attributeValue("versionCode"));
List<Element> elements = root.selectNodes("//uses-permission"); if (CommonUtil.isNotEmpty(elements)) {
StringBuffer apkUserPermissionBuff = new StringBuffer();
for (Element el : elements)
{
apkUserPermissionBuff.append("|").append(el.attributeValue("name"));
} String apkUserStr = apkUserPermissionBuff.toString(); if (CommonUtil.isNotEmpty(apkUserStr)) {
apkinfo.setApkUserpermission(apkUserStr.substring(1));
}
} //增加是否存在SDK的设置
apkinfo.setExistSdk(AXMLPrinter2.isExistSdk(apkPath));
// 设置SDK版本
apkinfo.setSdkVersion(AXMLPrinter2.getSdkVersion(apkPath));
// 设置SDK类型
apkinfo.setApkSdkType(AXMLPrinter2.getSdkType(apkPath)); return apkinfo;
} public static String convertFileSize(long filesize)
{
String strUnit = "Bytes";
String strAfterComma = "";
int intDivisor = 1;
if (filesize >= 1024 * 1024)
{
strUnit = "MB";
intDivisor = 1024 * 1024;
} else if (filesize >= 1024)
{
strUnit = "KB";
intDivisor = 1024;
}
if (intDivisor == 1){
return filesize + " " + strUnit;
} strAfterComma = "" + 100 * (filesize % intDivisor) / intDivisor;
if (strAfterComma.equals(""))
strAfterComma = ".0"; return filesize / intDivisor + "." + strAfterComma + " " + strUnit;
} public static ThreeNetsContent getThreeNetsContent(String apkPath)
{
return AXMLPrinter2.getThreeNetsContent(apkPath);
}
}
所用到的ApkInfo
public class ApkInfo { // APK游戏名称
private String apkName; // APK游戏大小
private String apkSize; // APK游戏包名称
private String apkPageage; // APK游戏版本
private String apkVersion; // APK游戏版本代码
private String apkVersionCode; // APK游戏适应Android SDK版本
private String apkMinsdkversion; // APK游戏用户权限
private String apkUserpermission; // APK游戏字节大小
private long apkByteSize; // zhouning SDK目标版本
private String apkTargetSdkVersion; private boolean isExistSdk; //add by mzz sdk类型
private String apkSdkType; /**
* SDK版本
*/
private String sdkVersion; public boolean isExistSdk() {
return isExistSdk;
} public void setExistSdk(boolean isExistSdk) {
this.isExistSdk = isExistSdk;
} public String getApkName() {
return apkName;
} public void setApkName(String apkName) {
this.apkName = apkName;
} public String getApkSize() {
return apkSize;
} public void setApkSize(String apkSize) {
this.apkSize = apkSize;
} public String getApkPageage() {
return apkPageage;
} public void setApkPageage(String apkPageage) {
this.apkPageage = apkPageage;
} public String getApkVersion() {
return apkVersion;
} public void setApkVersion(String apkVersion) {
this.apkVersion = apkVersion;
} public String getApkVersionCode() {
return apkVersionCode;
} public void setApkVersionCode(String apkVersionCode) {
this.apkVersionCode = apkVersionCode;
} public String getApkMinsdkversion() {
return apkMinsdkversion;
} public void setApkMinsdkversion(String apkMinsdkversion) {
this.apkMinsdkversion = apkMinsdkversion;
} public String getApkUserpermission() {
return apkUserpermission;
} public void setApkUserpermission(String apkUserpermission) {
this.apkUserpermission = apkUserpermission;
} public long getApkByteSize() {
return apkByteSize;
} public void setApkByteSize(long apkByteSize) {
this.apkByteSize = apkByteSize;
} public String getApkTargetSdkVersion() {
return apkTargetSdkVersion;
} public void setApkTargetSdkVersion(String apkTargetSdkVersion) {
this.apkTargetSdkVersion = apkTargetSdkVersion;
} public String getSdkVersion()
{
return sdkVersion;
} public void setSdkVersion(String sdkVersion)
{
this.sdkVersion = sdkVersion;
} public void setApkSdkType(String apkSdkType) {
this.apkSdkType = apkSdkType;
} public String getApkSdkType() {
return apkSdkType;
} }
解析Android 主文件 AndroidManifest.xml
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile; import org.apache.commons.codec.binary.Base64;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder; import android.content.res.AXmlResourceParser; import com.huawei.bme.commons.util.debug.DebugLog;
import com.huawei.bme.commons.util.debug.LogFactory;
import com.huawei.igop.common.constants.PropertyKey;
import com.huawei.igop.common.plist.NSObject;
import com.huawei.igop.common.plist.PropertyListParser;
import com.huawei.igop.partner.bean.ThreeNetsContent;
import com.huawei.igop2.common.utils.RSAUtils; public class AXMLPrinter2 { @SuppressWarnings("unused")
private static final String DEFAULT_XML = "AndroidManifest.xml";
private static final float[] RADIX_MULTS = { 0.0039063F, 3.051758E-005F,
1.192093E-007F, 4.656613E-010F };
private static final String[] DIMENSION_UNITS = { "px", "dip", "sp", "pt",
"in", "mm", "", "" };
private static final String[] FRACTION_UNITS = { "%", "%p", "", "", "", "",
"", "" }; public static String getManifestXMLFromAPK(String apkPath) {
ZipFile file = null;
StringBuilder xmlSb = new StringBuilder(100);
try {
int type;
File apkFile = new File(apkPath);
file = new ZipFile(apkFile, 1);
ZipEntry entry = file.getEntry("AndroidManifest.xml"); AXmlResourceParser parser = new AXmlResourceParser();
parser.open(file.getInputStream(entry)); StringBuilder sb = new StringBuilder(10);
@SuppressWarnings("unused")
String indentStep = "\t"; while ((type = parser.next()) != 1) {
switch (type) {
case 0:
log(xmlSb, "<?xml version=\"1.0\" encoding=\"utf-8\"?>",
new Object[0]);
break;
case 2:
log(false,
xmlSb,
"%s<%s%s",
new Object[] { sb,
getNamespacePrefix(parser.getPrefix()),
parser.getName() });
sb.append("\t"); int namespaceCountBefore = parser.getNamespaceCount(parser
.getDepth() - 1);
int namespaceCount = parser.getNamespaceCount(parser
.getDepth()); for (int i = namespaceCountBefore; i != namespaceCount; ++i) {
log(xmlSb,
"%sxmlns:%s=\"%s\"",
new Object[] {
(i == namespaceCountBefore) ? " " : sb,
parser.getNamespacePrefix(i),
parser.getNamespaceUri(i) });
} int i = 0;
for (int size = parser.getAttributeCount(); i != size; ++i) {
log(false,
xmlSb,
"%s%s%s=\"%s\"",
new Object[] {
" ",
getNamespacePrefix(parser
.getAttributePrefix(i)),
parser.getAttributeName(i),
getAttributeValue(parser, i) });
} log(xmlSb, ">", new Object[0]);
break;
case 3:
sb.setLength(sb.length() - "\t".length());
log(xmlSb,
"%s</%s%s>",
new Object[] { sb,
getNamespacePrefix(parser.getPrefix()),
parser.getName() });
break;
case 4:
log(xmlSb, "%s%s", new Object[] { sb, parser.getText() });
case 1:
} } parser.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (file != null) {
try {
file.close();
} catch (IOException e) { }
}
}
return xmlSb.toString();
} public static boolean isExistSdk(String apkPath) {
ZipFile file = null;
try {
File apkFile = new File(apkPath);
file = new ZipFile(apkFile, 1);
ZipEntry entryCharge = file.getEntry("assets/Charge.xml");
ZipEntry entryConsumeCode = file
.getEntry("assets/ConsumeCodeInfo.xml");
if (entryCharge != null && entryConsumeCode != null) {
return true;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (file != null) {
try {
file.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return false;
} private static String getNamespacePrefix(String prefix) {
if ((prefix == null) || (prefix.length() == 0)) {
return "";
}
return prefix + ":";
} private static String getAttributeValue(AXmlResourceParser parser, int index) {
int type = parser.getAttributeValueType(index);
int data = parser.getAttributeValueData(index);
if (type == 3) {
return parser.getAttributeValue(index);
}
if (type == 2) {
return String.format("?%s%08X", new Object[] { getPackage(data),
Integer.valueOf(data) });
}
if (type == 1) {
return String.format("@%s%08X", new Object[] { getPackage(data),
Integer.valueOf(data) });
}
if (type == 4) {
return String.valueOf(Float.intBitsToFloat(data));
}
if (type == 17) {
return String.format("0x%08X",
new Object[] { Integer.valueOf(data) });
}
if (type == 18) {
return ((data != 0) ? "true" : "false");
}
if (type == 5) {
return Float.toString(complexToFloat(data))
+ DIMENSION_UNITS[(data & 0xF)];
}
if (type == 6) {
return Float.toString(complexToFloat(data))
+ FRACTION_UNITS[(data & 0xF)];
}
if ((type >= 28) && (type <= 31)) {
return String.format("#%08X",
new Object[] { Integer.valueOf(data) });
}
if ((type >= 16) && (type <= 31)) {
return String.valueOf(data);
}
return String.format("<0x%X, type 0x%02X>",
new Object[] { Integer.valueOf(data), Integer.valueOf(type) });
} private static String getPackage(int id) {
if (id >>> 24 == 1) {
return "android:";
}
return "";
} private static void log(StringBuilder xmlSb, String format,
Object[] arguments) {
log(true, xmlSb, format, arguments);
} private static void log(boolean newLine, StringBuilder xmlSb,
String format, Object[] arguments) {
xmlSb.append(String.format(format, arguments));
if (newLine)
xmlSb.append("\n");
} public static float complexToFloat(int complex) {
return ((complex & 0xFFFFFF00) * RADIX_MULTS[(complex >> 4 & 0x3)]);
} public static String getSdkVersion(String apkPath)
{
String sdkVersion = null;
ZipFile zipfile = null;
try
{
File apkFile = new File(apkPath);
zipfile = new ZipFile(apkFile, 1);
ZipEntry config = zipfile.getEntry("assets/Config.xml");
if (null != config)
{
Document doc = new SAXBuilder().build(zipfile.getInputStream(config));
sdkVersion = doc.getRootElement().getChildTextTrim("SDKVersion");
}
}
catch (Exception e)
{
DEBUGGER.error("Failed to getSdkVersion", e);
}
finally
{
closeZipFile(zipfile);
}
return sdkVersion;
} public static String getSdkType(String apkPath)
{
String SdkType = null;
ZipFile zipfile = null;
try
{
File apkFile = new File(apkPath);
zipfile = new ZipFile(apkFile, 1);
ZipEntry config = zipfile.getEntry("assets/ConfigExt.xml");
if (null != config)
{
//配置文件内容,由SDK通过RSA 私钥加密,iGop从包体读出时,通过RSA公钥解密(防止CP篡改)。
BufferedReader in = new BufferedReader(new InputStreamReader(zipfile.getInputStream(config)));
StringBuffer strBuffer = new StringBuffer();
String buffer = null;
while (null != (buffer = in.readLine()))
{
//得到密文
strBuffer.append(buffer);
}
String key = PropertyUtil.getString(PropertyKey.SDK_TYPE_PUBLICKEY);
X509EncodedKeySpec pubX509new = new X509EncodedKeySpec(Base64.decodeBase64(key.getBytes()));
RSAPublicKey pukey1 = RSAUtils.getPublicKey(pubX509new);
String jiewen = RSAUtils.decryptByPublicKey(strBuffer.toString(), pukey1);
Document doc = new SAXBuilder().build(new ByteArrayInputStream(jiewen.getBytes()));
SdkType = doc.getRootElement().getChildTextTrim("SDKType"); }
}
catch (Exception e)
{
DEBUGGER.error("Failed to getSdkType", e);
}
finally
{
closeZipFile(zipfile);
}
return SdkType;
} public static void closeZipFile(ZipFile zipfile)
{
if (null != zipfile)
{
try
{
zipfile.close();
}
catch (IOException e)
{
DEBUGGER.error("Failed to close ZipFile", e);
}
}
} public static ThreeNetsContent getThreeNetsContent(String apkPath)
{
ZipFile zipfile = null;
ThreeNetsContent threeNetsContent = null;
try
{
File file = new File(apkPath);
zipfile = new ZipFile(file, 1);
ZipEntry zipEntry = zipfile.getEntry("assets/touchpayservice.xml");
if (null == zipEntry)
{
return null;
} threeNetsContent = new ThreeNetsContent();
Document doc = new SAXBuilder().build(zipfile.getInputStream(zipEntry));
Element element = doc.getRootElement();
threeNetsContent.setCmServiceId(element.getChildTextTrim("cm_serviceid"));
threeNetsContent.setCuServiceId(element.getChildTextTrim("cu_serviceid"));
threeNetsContent.setCtServiceId(element.getChildTextTrim("ct_serviceid"));
}
catch (Exception e)
{
DEBUGGER.error("Failed to getThreeNetsContent", e);
}
finally
{
closeZipFile(zipfile);
} return threeNetsContent;
} public static boolean isExistsSdkFromIOS(String filePath, String projectName)
{
ZipFile file = null;
try {
File iosFile = new File(filePath);
file = new ZipFile(iosFile, 1);
ZipEntry entryCharge = file.getEntry("Payload/"+ projectName +"/Res.bundle/Charge.xml");
ZipEntry entryConsumeCode = file.getEntry("Payload/"+ projectName +"/Res.bundle/ConsumeCodeInfo.xml");
if (entryCharge != null && entryConsumeCode != null) {
return true;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
closeZipFile(file);
}
return false;
} public static String getSdkVersionFromIOS(String filePath, String projectName)
{
String sdkVersion = null;
ZipFile zipfile = null;
try
{
File file = new File(filePath);
zipfile = new ZipFile(file, 1);
ZipEntry config = zipfile.getEntry("Payload/"+ projectName +"/Res.bundle/CM_iOS_Config.xml");
if (null != config)
{
Document doc = new SAXBuilder().build(zipfile.getInputStream(config));
sdkVersion = doc.getRootElement().getChildTextTrim("SDKVersion");
}
}
catch (Exception e)
{
DEBUGGER.error("Failed to getSdkVersion4Ios", e);
}
finally
{
closeZipFile(zipfile);
}
return sdkVersion;
} public static String getXmlFromIOS(String filePath, String projectName)
{
ZipFile zipfile = null;
NSObject nsObject = null;
try
{
File file = new File(filePath);
zipfile = new ZipFile(file, 1);
ZipEntry entry = zipfile.getEntry("Payload/"+ projectName +"/Info.plist");
nsObject = PropertyListParser.parse(zipfile.getInputStream(entry));
}
catch (Exception e)
{
DEBUGGER.error("Failed to getXmlFromIOS", e);
}
finally
{
closeZipFile(zipfile);
}
return nsObject.toXMLPropertyList();
}
}
import java.io.IOException; /**
* Abstract interface for any object contained in a property list.
* The names and functions of the various objects orient themselves
* towards Apple's Cocoa API.
* @author Daniel
*/
public abstract class NSObject { public final static String NEWLINE = System.getProperty("line.separator");
public final static String INDENT = "\t"; /**
* Generates the XML representation of the object (without XML headers or enclosing plist-tags).
* @param xml The StringBuilder onto which the XML representation is appended.
* @param level The indentation level of the object.
*/
public abstract void toXML(StringBuilder xml, int level); /**
* Assigns IDs to all the objects in this NSObject subtree.
*/
void assignIDs(BinaryPropertyListWriter out) {
out.assignID(this);
} /**
* Generates the binary representation of the object.
* @param out The output stream to serialize the object to.
*/
abstract void toBinary(BinaryPropertyListWriter out) throws IOException; /**
* Generates a valid XML property list including headers using this object as root.
* @return The XML representation of the property list
*/
public String toXMLPropertyList() {
StringBuilder xml = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
xml.append(NSObject.NEWLINE);
xml.append("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
xml.append(NSObject.NEWLINE);
xml.append("<plist version=\"1.0\">");
xml.append(NSObject.NEWLINE);
toXML(xml, 0);
xml.append(NSObject.NEWLINE);
xml.append("</plist>");
return xml.toString();
} protected void indent(StringBuilder xml, int level) {
for(int i=0;i<level;i++)
xml.append(INDENT);
}
}
PropertyListParser.java
/**
* Parses any given property list
* @author Daniel Dreibrodt
*/
public class PropertyListParser { /**
* Reads all bytes from an InputStream and stores them in an array, up to
* a maximum count.
* @param in The InputStream
* @param max The maximum number of bytes to read.
**/
static byte[] readAll(InputStream in, int max) throws IOException {
ByteArrayOutputStream buf = new ByteArrayOutputStream();
while (max > 0) {
int n = in.read();
if (n == -1) break; // EOF
buf.write(n);
max--;
}
return buf.toByteArray();
} /**
* Parses a property list from a file. It can either be in XML or binary format.
* @param f The property list file
* @return The root object in the property list
* @throws Exception If an error occurred while parsing
*/
public static NSObject parse(File f) throws Exception {
FileInputStream fis = new FileInputStream(f);
String magicString = new String(readAll(fis, 8), 0, 8);
fis.close();
if (magicString.startsWith("bplist00")) {
return BinaryPropertyListParser.parse(f);
} else if (magicString.startsWith("<?xml")) {
return XMLPropertyListParser.parse(f);
} else {
throw new UnsupportedOperationException("The given data is neither a binary nor a XML property list. ASCII property lists are not supported.");
}
} /**
* Parses a property list from a byte array. It can either be in XML or binary format.
* @param bytes The property list data
* @return The root object in the property list
* @throws Exception If an error occurred while parsing.
*/
public static NSObject parse(byte[] bytes) throws Exception {
String magicString = new String(bytes, 0, 8);
if (magicString.startsWith("bplist00")) {
return BinaryPropertyListParser.parse(bytes);
} else if (magicString.startsWith("<?xml")) {
return XMLPropertyListParser.parse(bytes);
} else {
throw new UnsupportedOperationException("The given data is neither a binary nor a XML property list. ASCII property lists are not supported.");
}
} /**
* Parses a property list from an InputStream. It can either be in XML or binary format.
* @param is The InputStream delivering the property list data
* @return The root object of the property list
* @throws Exception If an error occurred while parsing.
*/
public static NSObject parse(InputStream is) throws Exception {
if(is.markSupported()) {
is.mark(10);
String magicString = new String(readAll(is, 8), 0, 8);
is.reset();
if (magicString.startsWith("bplist00")) {
return BinaryPropertyListParser.parse(is);
} else if (magicString.startsWith("<?xml")) {
return XMLPropertyListParser.parse(is);
} else {
throw new UnsupportedOperationException("The given data is neither a binary nor a XML property list. ASCII property lists are not supported.");
}
} else {
//Now we have to read everything, because if one parsing method fails
//the whole InputStream is lost as we can't reset it
return parse(readAll(is, Integer.MAX_VALUE));
}
} /**
* Saves a property list with the given object as root into a XML file
* @param root the root object
* @param out the output file
* @throws IOException if an error occurs during writing
*/
public static void saveAsXML(NSObject root, File out) throws IOException {
OutputStreamWriter w = new OutputStreamWriter(new FileOutputStream(out), "UTF-8");
w.write(root.toXMLPropertyList());
w.close();
} /**
* Converts a given property list file into the xml format
* @param in the source file
* @param out the target file
* @throws Exception if an error occurs during parsing
* @throws IOException if an error occurs during writing
*/
public static void convertToXml(File in, File out) throws Exception {
NSObject root = parse(in);
saveAsXML(root, out);
} /**
* Saves a property list with the given object as root into a binary file
* @param root the root object
* @param out the output file
* @throws IOException if an error occurs during writing
*/
public static void saveAsBinary(NSObject root, File out) throws IOException {
BinaryPropertyListWriter.write(out, root);
} /**
* Converts a given property list file into the binary format
* @param in the source file
* @param out the target file
* @throws Exception if an error occurs during parsing
* @throws IOException if an error occurs during writing
*/
public static void convertToBinary(File in, File out) throws Exception {
NSObject root = parse(in);
saveAsBinary(root, out);
}
}