Skip to content
This repository has been archived by the owner on Sep 21, 2020. It is now read-only.

Commit

Permalink
add methods to get all apk icons
Browse files Browse the repository at this point in the history
  • Loading branch information
Liu Dong committed Nov 17, 2017
1 parent 1c38192 commit 641df18
Show file tree
Hide file tree
Showing 19 changed files with 422 additions and 196 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Apk-parser has been submitted to maven central repo. With maven, you can add apk
<dependency>
<groupId>net.dongliu</groupId>
<artifactId>apk-parser</artifactId>
<version>2.3.0</version>
<version>2.4.0</version>
</dependency>
```
From version 2.0, apk-parser requires java7. The last version support java6 is 1.7.4.
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<artifactId>apk-parser</artifactId>
<name>apk-parser</name>
<packaging>jar</packaging>
<version>2.3.0</version>
<version>2.4.0</version>
<url>https://github.com/xiaxiaocao/apk-parser</url>
<developers>
<developer>
Expand Down
95 changes: 49 additions & 46 deletions src/main/java/net/dongliu/apk/parser/AbstractApkFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import net.dongliu.apk.parser.exception.ParserException;
import net.dongliu.apk.parser.parser.*;
import net.dongliu.apk.parser.struct.AndroidConstants;
import net.dongliu.apk.parser.struct.resource.Densities;
import net.dongliu.apk.parser.struct.resource.ResourceTable;
import org.bouncycastle.cms.CMSException;

import java.io.Closeable;
import java.io.IOException;
Expand All @@ -23,11 +23,16 @@
*/
public abstract class AbstractApkFile implements Closeable {
private DexClass[] dexClasses;

private boolean resourceTableParsed;
private ResourceTable resourceTable;
private Set<Locale> locales;

private boolean manifestParsed;
private String manifestXml;
private ApkMeta apkMeta;
private Set<Locale> locales;
private List<IconPath> iconPaths;

private List<CertificateMeta> certificateMetaList;

private static final Locale DEFAULT_LOCALE = Locale.US;
Expand All @@ -43,9 +48,7 @@ public abstract class AbstractApkFile implements Closeable {
* @return decoded AndroidManifest.xml
*/
public String getManifestXml() throws IOException {
if (this.manifestXml == null) {
parseManifestXml();
}
parseManifest();
return this.manifestXml;
}

Expand All @@ -55,9 +58,7 @@ public String getManifestXml() throws IOException {
* @return decoded AndroidManifest.xml
*/
public ApkMeta getApkMeta() throws IOException {
if (this.apkMeta == null) {
parseApkMeta();
}
parseManifest();
return this.apkMeta;
}

Expand All @@ -68,9 +69,7 @@ public ApkMeta getApkMeta() throws IOException {
* @throws IOException
*/
public Set<Locale> getLocales() throws IOException {
if (this.locales == null) {
parseResourceTable();
}
parseResourceTable();
return this.locales;
}

Expand Down Expand Up @@ -98,34 +97,24 @@ private void parseCertificate() throws IOException, CertificateException {
this.certificateMetaList = parser.getCertificateMetas();
}

/**
* parse manifest.xml, get apkMeta.
*
* @throws IOException
*/
private void parseApkMeta() throws IOException {
if (this.manifestXml == null) {
parseManifestXml();
private void parseManifest() throws IOException {
if (manifestParsed) {
return;
}
}

/**
* parse manifest.xml, get manifestXml as xml text.
*
* @throws IOException
*/
private void parseManifestXml() throws IOException {
parseResourceTable();
XmlTranslator xmlTranslator = new XmlTranslator();
ApkMetaTranslator translator = new ApkMetaTranslator();
XmlStreamer xmlStreamer = new CompositeXmlStreamer(xmlTranslator, translator);
ApkMetaTranslator apkTranslator = new ApkMetaTranslator(this.resourceTable, this.preferredLocale);
XmlStreamer xmlStreamer = new CompositeXmlStreamer(xmlTranslator, apkTranslator);

byte[] data = getFileData(AndroidConstants.MANIFEST_FILE);
if (data == null) {
throw new ParserException("Manifest file not found");
}
transBinaryXml(data, xmlStreamer);
this.manifestXml = xmlTranslator.getXml();
this.apkMeta = translator.getApkMeta();
this.apkMeta = apkTranslator.getApkMeta();
this.iconPaths = apkTranslator.getIconPaths();
manifestParsed = true;
}

/**
Expand All @@ -146,19 +135,15 @@ public String transBinaryXml(String path) throws IOException {
if (data == null) {
return null;
}
if (this.resourceTable == null) {
parseResourceTable();
}
parseResourceTable();

XmlTranslator xmlTranslator = new XmlTranslator();
transBinaryXml(data, xmlTranslator);
return xmlTranslator.getXml();
}

private void transBinaryXml(byte[] data, XmlStreamer xmlStreamer) throws IOException {
if (this.resourceTable == null) {
parseResourceTable();
}
parseResourceTable();

ByteBuffer buffer = ByteBuffer.wrap(data);
BinaryXmlParser binaryXmlParser = new BinaryXmlParser(buffer, resourceTable);
Expand All @@ -168,18 +153,36 @@ private void transBinaryXml(byte[] data, XmlStreamer xmlStreamer) throws IOExcep
}

/**
* get the apk icon file as bytes.
*
* @return the apk icon data,null if icon not found
* @throws IOException
* Get the default apk icon file.
*/
public Icon getIconFile() throws IOException {
ApkMeta apkMeta = getApkMeta();
String iconPath = apkMeta.getIcon();
if (iconPath == null) {
return null;
}
return new Icon(iconPath, getFileData(iconPath));
return new Icon(iconPath, Densities.DEFAULT, getFileData(iconPath));
}

/**
* Get all the icon paths, for different densities.
*/
public List<IconPath> getIconPaths() throws IOException {
parseManifest();
return this.iconPaths;
}

/**
* Get all the icons, for different densities.
*/
public List<Icon> getIconFiles() throws IOException {
List<IconPath> iconPaths = getIconPaths();
List<Icon> icons = new ArrayList<>(iconPaths.size());
for (IconPath iconPath : iconPaths) {
Icon icon = new Icon(iconPath.getPath(), iconPath.getDensity(), getFileData(iconPath.getPath()));
icons.add(icon);
}
return icons;
}

/**
Expand Down Expand Up @@ -228,6 +231,10 @@ private void parseDexFiles() throws IOException {
* parse resource table.
*/
private void parseResourceTable() throws IOException {
if (resourceTableParsed) {
return;
}
resourceTableParsed = true;
byte[] data = getFileData(AndroidConstants.RESOURCE_FILE);
if (data == null) {
// if no resource entry has been found, we assume it is not needed by this APK
Expand All @@ -236,9 +243,6 @@ private void parseResourceTable() throws IOException {
return;
}

this.resourceTable = new ResourceTable();
this.locales = Collections.emptySet();

ByteBuffer buffer = ByteBuffer.wrap(data);
ResourceTableParser resourceTableParser = new ResourceTableParser(buffer);
resourceTableParser.parse();
Expand All @@ -248,8 +252,6 @@ private void parseResourceTable() throws IOException {

/**
* check apk sign
*
* @throws IOException
*/
public abstract ApkSignStatus verifyApk() throws IOException;

Expand All @@ -258,6 +260,7 @@ public void close() throws IOException {
this.certificateMetaList = null;
this.resourceTable = null;
this.certificateMetaList = null;
this.iconPaths = null;
}

public Locale getPreferredLocale() {
Expand Down
8 changes: 7 additions & 1 deletion src/main/java/net/dongliu/apk/parser/Main.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package net.dongliu.apk.parser;

import net.dongliu.apk.parser.bean.Icon;

import java.io.IOException;
import java.security.cert.CertificateException;
import java.util.List;

/**
* Main method for parser apk
Expand All @@ -11,7 +14,10 @@
public class Main {
public static void main(String[] args) throws IOException, CertificateException {
try (ApkFile apkFile = new ApkFile(args[0])) {
System.out.println(apkFile.verifyApk());
List<Icon> iconFiles = apkFile.getIconFiles();
for (Icon iconFile : iconFiles) {
System.out.println(iconFile);
}
}
}
}
23 changes: 20 additions & 3 deletions src/main/java/net/dongliu/apk/parser/bean/Icon.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package net.dongliu.apk.parser.bean;

import java.util.Arrays;
import javax.annotation.Nullable;

/**
* The apk icon file path, and data
Expand All @@ -10,23 +10,40 @@
public class Icon {

private final String path;
private int density;
private final byte[] data;

public Icon(String path, byte[] data) {
public Icon(String path, int density, byte[] data) {
this.path = path;
this.density = density;
this.data = data;
}

/**
* The icon path in apk file
*/
public String getPath() {
return path;
}

/**
* Return the density this icon for. 0 means default icon.
* see {@link net.dongliu.apk.parser.struct.resource.Densities} for more density values.
*/
public int getDensity() {
return density;
}

/**
* Icon data may be null, due to some apk missing the icon file.
*/
@Nullable
public byte[] getData() {
return data;
}

@Override
public String toString() {
return "Icon{path='" + path + '\'' + ", size=" + (data == null ? 0 : data.length) + '}';
return "Icon{path='" + path + '\'' + ", density=" + density + ", size=" + (data == null ? 0 : data.length) + '}';
}
}
37 changes: 37 additions & 0 deletions src/main/java/net/dongliu/apk/parser/bean/IconPath.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package net.dongliu.apk.parser.bean;

/**
* Icon path, and density
*/
public class IconPath {
private String path;
private int density;

public IconPath(String path, int density) {
this.path = path;
this.density = density;
}

/**
* The icon path in apk file
*/
public String getPath() {
return path;
}

/**
* Return the density this icon for. 0 means default icon.
* see {@link net.dongliu.apk.parser.struct.resource.Densities} for more density values.
*/
public int getDensity() {
return density;
}

@Override
public String toString() {
return "IconPath{" +
"path='" + path + '\'' +
", density=" + density +
'}';
}
}
3 changes: 3 additions & 0 deletions src/main/java/net/dongliu/apk/parser/bean/Locales.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ public class Locales {
*/
public static final Locale any = new Locale("", "");

/**
* How much the given locale match the expected locale.
*/
public static int match(Locale locale, Locale targetLocale) {
if (locale == null) {
return -1;
Expand Down
Loading

0 comments on commit 641df18

Please sign in to comment.