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

Commit

Permalink
deal with android 8 adaptive icons
Browse files Browse the repository at this point in the history
  • Loading branch information
dongliu committed Jun 12, 2018
1 parent 9ef1070 commit 666cc64
Show file tree
Hide file tree
Showing 10 changed files with 259 additions and 10 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 @@ Get apk-parser from maven central repo:
<dependency>
<groupId>net.dongliu</groupId>
<artifactId>apk-parser</artifactId>
<version>2.5.3</version>
<version>2.6.0</version>
</dependency>
```
From version 2.0, apk-parser requires java7. The last version support java6 is 1.7.4.
Expand Down
10 changes: 8 additions & 2 deletions 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.5.3</version>
<version>2.6.0</version>
<url>https://github.com/xiaxiaocao/apk-parser</url>
<developers>
<developer>
Expand Down Expand Up @@ -141,14 +141,20 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.5</version>
<version>1.6</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
<configuration>
<gpgArguments>
<arg>--pinentry-mode</arg>
<arg>loopback</arg>
</gpgArguments>
</configuration>
</execution>
</executions>
</plugin>
Expand Down
60 changes: 59 additions & 1 deletion src/main/java/net/dongliu/apk/parser/AbstractApkFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -241,9 +241,58 @@ private void transBinaryXml(byte[] data, XmlStreamer xmlStreamer) throws IOExcep
binaryXmlParser.parse();
}

/**
* This method return icons specified in android manifest file, application.
* The icons could be file icon, color icon, or adaptive icon, etc.
*
* @return icon files.
*/
public List<IconFace> getAllIcons() throws IOException {
List<IconPath> iconPaths = getIconPaths();
if (iconPaths.isEmpty()) {
return Collections.emptyList();
}
List<IconFace> iconFaces = new ArrayList<>(iconPaths.size());
for (IconPath iconPath : iconPaths) {
String filePath = iconPath.getPath();
if (filePath.endsWith(".xml")) {
// adaptive icon?
byte[] data = getFileData(filePath);
if (data == null) {
continue;
}
parseResourceTable();

AdaptiveIconParser iconParser = new AdaptiveIconParser();
transBinaryXml(data, iconParser);
Icon backgroundIcon = null;
if (iconParser.getBackground() != null) {
backgroundIcon = newFileIcon(iconParser.getBackground(), iconPath.getDensity());
}
Icon foregroundIcon = null;
if (iconParser.getForeground() != null) {
foregroundIcon = newFileIcon(iconParser.getForeground(), iconPath.getDensity());
}
AdaptiveIcon icon = new AdaptiveIcon(backgroundIcon, foregroundIcon);
iconFaces.add(icon);
} else {
Icon icon = newFileIcon(filePath, iconPath.getDensity());
iconFaces.add(icon);
}
}
return iconFaces;
}

private Icon newFileIcon(String filePath, int density) throws IOException {
return new Icon(filePath, density, getFileData(filePath));
}

/**
* Get the default apk icon file.
*
* @deprecated use {@link #getAllIcons()}
*/
@Deprecated
public Icon getIconFile() throws IOException {
ApkMeta apkMeta = getApkMeta();
String iconPath = apkMeta.getIcon();
Expand All @@ -255,20 +304,26 @@ public Icon getIconFile() throws IOException {

/**
* Get all the icon paths, for different densities.
*
* @deprecated using {@link #getAllIcons()} instead
*/
@Deprecated
public List<IconPath> getIconPaths() throws IOException {
parseManifest();
return this.iconPaths;
}

/**
* Get all the icons, for different densities.
*
* @deprecated using {@link #getAllIcons()} instead
*/
@Deprecated
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()));
Icon icon = newFileIcon(iconPath.getPath(), iconPath.getDensity());
icons.add(icon);
}
return icons;
Expand Down Expand Up @@ -353,6 +408,9 @@ public void close() throws IOException {
this.iconPaths = null;
}

/**
* The local used to parse apk
*/
public Locale getPreferredLocale() {
return preferredLocale;
}
Expand Down
9 changes: 6 additions & 3 deletions src/main/java/net/dongliu/apk/parser/Main.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
package net.dongliu.apk.parser;

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

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

/**
* Main method for parser apk
*
* @author Liu Dong {@literal <[email protected]>}
*/
public class Main {
public static void main(String[] args) throws IOException, CertificateException {
public static void main(String[] args) throws IOException {
try (ApkFile apkFile = new ApkFile(args[0])) {
System.out.println(apkFile.getApkSingers().get(0).getCertificateMetas());
List<IconFace> allIcons = apkFile.getAllIcons();
System.out.println(allIcons);
}
}
}
55 changes: 55 additions & 0 deletions src/main/java/net/dongliu/apk/parser/bean/AdaptiveIcon.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package net.dongliu.apk.parser.bean;

import java.io.Serializable;

/**
* Android adaptive icon, from android 8.0
*/
public class AdaptiveIcon implements IconFace, Serializable {
private static final long serialVersionUID = 4185750290211529320L;
private final Icon foreground;
private final Icon background;

public AdaptiveIcon(Icon foreground, Icon background) {
this.foreground = foreground;
this.background = background;
}


/**
* The foreground icon
*/
public Icon getForeground() {
return foreground;
}

/**
* The background icon
*/
public Icon getBackground() {
return background;
}

@Override
public String toString() {
return "AdaptiveIcon{" +
"foreground=" + foreground +
", background=" + background +
'}';
}

@Override
public boolean isFile() {
return foreground.isFile();
}

@Override
public byte[] getData() {
return foreground.getData();
}

@Override
public String getPath() {
return foreground.getPath();
}
}
5 changes: 5 additions & 0 deletions src/main/java/net/dongliu/apk/parser/bean/ApkMeta.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package net.dongliu.apk.parser.bean;

import net.dongliu.apk.parser.AbstractApkFile;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -92,11 +94,14 @@ public void addUsesPermission(String permission) {
* the icon file path in apk
*
* @return null if not found
* @deprecated use {@link AbstractApkFile#getAllIcons()} instead.
*/
@Deprecated
public String getIcon() {
return icon;
}

@Deprecated
public void setIcon(String icon) {
this.icon = icon;
}
Expand Down
27 changes: 27 additions & 0 deletions src/main/java/net/dongliu/apk/parser/bean/ColorIcon.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package net.dongliu.apk.parser.bean;

import java.io.Serializable;

/**
* The plain icon, using color drawable resource.
*/
//to be implemented
public class ColorIcon implements IconFace, Serializable {
private static final long serialVersionUID = -7913024425268466186L;

@Override
public boolean isFile() {
return false;
}

@Override
public byte[] getData() {
throw new UnsupportedOperationException();
}

@Override
public String getPath() {
throw new UnsupportedOperationException();
}

}
13 changes: 10 additions & 3 deletions src/main/java/net/dongliu/apk/parser/bean/Icon.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
package net.dongliu.apk.parser.bean;

import javax.annotation.Nullable;
import java.io.Serializable;

/**
* The apk icon file path, and data
* The plain file apk icon.
*
* @author Liu Dong
*/
public class Icon {
public class Icon implements IconFace, Serializable {

private static final long serialVersionUID = 8680309892249769701L;
private final String path;
private int density;
private final int density;
private final byte[] data;

public Icon(String path, int density, byte[] data) {
Expand All @@ -34,6 +36,11 @@ public int getDensity() {
return density;
}

@Override
public boolean isFile() {
return true;
}

/**
* Icon data may be null, due to some apk missing the icon file.
*/
Expand Down
27 changes: 27 additions & 0 deletions src/main/java/net/dongliu/apk/parser/bean/IconFace.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package net.dongliu.apk.parser.bean;

import java.io.Serializable;

/**
* The icon interface
*/
public interface IconFace extends Serializable {

/**
* If icon is file resource
*/
boolean isFile();

/**
* Return the icon file as bytes. This method is valid only when {@link #isFile()} return true.
* Otherwise, {@link UnsupportedOperationException} should be thrown.
*/
byte[] getData();


/**
* Return the icon file path in apk file. This method is valid only when {@link #isFile()} return true.
* Otherwise, {@link UnsupportedOperationException} should be thrown.
*/
String getPath();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package net.dongliu.apk.parser.parser;

import net.dongliu.apk.parser.struct.xml.*;

/**
* Parse adaptive icon xml file.
*
* @author Liu Dong [email protected]
*/
public class AdaptiveIconParser implements XmlStreamer {

private String foreground;
private String background;

public String getForeground() {
return foreground;
}

public String getBackground() {
return background;
}

@Override
public void onStartTag(XmlNodeStartTag xmlNodeStartTag) {
if (xmlNodeStartTag.getName().equals("background")) {
background = getDrawable(xmlNodeStartTag);
} else if (xmlNodeStartTag.getName().equals("foreground")) {
foreground = getDrawable(xmlNodeStartTag);
}
}

private String getDrawable(XmlNodeStartTag xmlNodeStartTag) {
Attributes attributes = xmlNodeStartTag.getAttributes();
for (Attribute attribute : attributes.values()) {
if (attribute.getName().equals("drawable")) {
return attribute.getValue();
}
}
return null;
}

@Override
public void onEndTag(XmlNodeEndTag xmlNodeEndTag) {

}

@Override
public void onCData(XmlCData xmlCData) {

}

@Override
public void onNamespaceStart(XmlNamespaceStartTag tag) {

}

@Override
public void onNamespaceEnd(XmlNamespaceEndTag tag) {

}
}

0 comments on commit 666cc64

Please sign in to comment.