mirror of
https://github.com/revanced/Apktool.git
synced 2025-01-07 10:35:52 +01:00
Androlib: completely rewritten build methods, added changes checking, etc.
This commit is contained in:
parent
901035d240
commit
4e49612c18
@ -22,10 +22,10 @@ import brut.androlib.res.data.ResTable;
|
|||||||
import brut.androlib.res.util.ExtFile;
|
import brut.androlib.res.util.ExtFile;
|
||||||
import brut.common.BrutException;
|
import brut.common.BrutException;
|
||||||
import brut.directory.*;
|
import brut.directory.*;
|
||||||
|
import brut.util.BrutIO;
|
||||||
import brut.util.OS;
|
import brut.util.OS;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||||
@ -34,99 +34,6 @@ public class Androlib {
|
|||||||
private final AndrolibResources mAndRes = new AndrolibResources();
|
private final AndrolibResources mAndRes = new AndrolibResources();
|
||||||
private final AndrolibSmali mSmali = new AndrolibSmali();
|
private final AndrolibSmali mSmali = new AndrolibSmali();
|
||||||
|
|
||||||
public void buildAll() throws AndrolibException {
|
|
||||||
clean();
|
|
||||||
new File("build/apk").mkdirs();
|
|
||||||
buildCopyRawFiles();
|
|
||||||
buildResources();
|
|
||||||
buildClasses();
|
|
||||||
buildPackage();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clean() throws AndrolibException {
|
|
||||||
try {
|
|
||||||
OS.rmdir("build");
|
|
||||||
OS.rmdir("dist");
|
|
||||||
} catch (BrutException ex) {
|
|
||||||
throw new AndrolibException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void buildCopyRawFiles() throws AndrolibException {
|
|
||||||
try {
|
|
||||||
if (new File("assets").exists()) {
|
|
||||||
OS.cpdir("assets", "build/apk/assets");
|
|
||||||
}
|
|
||||||
if (new File("lib").exists()) {
|
|
||||||
OS.cpdir("lib", "build/apk/lib");
|
|
||||||
}
|
|
||||||
} catch (BrutException ex) {
|
|
||||||
throw new AndrolibException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void buildResources() throws AndrolibException {
|
|
||||||
if (new File("resources.arsc").exists()) {
|
|
||||||
try {
|
|
||||||
new File("build/apk/res").mkdirs();
|
|
||||||
DirUtil.copyToDir(new FileDirectory("res"),
|
|
||||||
new FileDirectory("build/apk/res"));
|
|
||||||
IOUtils.copy(new FileInputStream("resources.arsc"),
|
|
||||||
new FileOutputStream("build/apk/resources.arsc"));
|
|
||||||
IOUtils.copy(new FileInputStream("AndroidManifest.xml"),
|
|
||||||
new FileOutputStream("build/apk/AndroidManifest.xml"));
|
|
||||||
} catch (IOException ex) {
|
|
||||||
throw new AndrolibException(ex);
|
|
||||||
} catch (DirectoryException ex) {
|
|
||||||
throw new AndrolibException(ex);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
File apkFile;
|
|
||||||
try {
|
|
||||||
apkFile = File.createTempFile("APKTOOL", null);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
throw new AndrolibException(ex);
|
|
||||||
}
|
|
||||||
apkFile.delete();
|
|
||||||
|
|
||||||
mAndRes.aaptPackage(
|
|
||||||
apkFile,
|
|
||||||
new File("AndroidManifest.xml"),
|
|
||||||
new File("res")
|
|
||||||
);
|
|
||||||
// mAndRes.updateSmaliResIDs(
|
|
||||||
// mAndRes.getResTable(apkFile), new File("smali"));
|
|
||||||
|
|
||||||
try {
|
|
||||||
DirUtil.copyToDir(new ZipRODirectory(apkFile),
|
|
||||||
new FileDirectory("build/apk"));
|
|
||||||
} catch (DirectoryException ex) {
|
|
||||||
throw new AndrolibException(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
apkFile.delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void buildClasses() throws AndrolibException {
|
|
||||||
new AndrolibSmali().smali("smali", "build/apk/classes.dex");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void buildPackage() throws AndrolibException {
|
|
||||||
File outApk = new File("dist/out.apk");
|
|
||||||
if (outApk.exists()) {
|
|
||||||
outApk.delete();
|
|
||||||
} else {
|
|
||||||
File outDir = outApk.getParentFile();
|
|
||||||
if (! outDir.exists()) {
|
|
||||||
outDir.mkdirs();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mAndRes.aaptPackage(outApk, null, null,
|
|
||||||
new File("build/apk"), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResTable getResTable(ExtFile apkFile) throws AndrolibException {
|
public ResTable getResTable(ExtFile apkFile) throws AndrolibException {
|
||||||
LOGGER.info("Decoding resource table...");
|
LOGGER.info("Decoding resource table...");
|
||||||
return mAndRes.getResTable(apkFile);
|
return mAndRes.getResTable(apkFile);
|
||||||
@ -159,8 +66,7 @@ public class Androlib {
|
|||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
try {
|
try {
|
||||||
LOGGER.info("Copying raw resources...");
|
LOGGER.info("Copying raw resources...");
|
||||||
apkFile.getDirectory().copyToDir(outDir,
|
apkFile.getDirectory().copyToDir(outDir, APK_RESOURCES_FILENAMES);
|
||||||
new String[]{"AndroidManifest.xml", "resources.arsc", "res"});
|
|
||||||
} catch (DirectoryException ex) {
|
} catch (DirectoryException ex) {
|
||||||
throw new AndrolibException(ex);
|
throw new AndrolibException(ex);
|
||||||
}
|
}
|
||||||
@ -188,8 +94,180 @@ public class Androlib {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void build(File appDir, boolean forceBuildAll)
|
||||||
|
throws AndrolibException {
|
||||||
|
build(new ExtFile(appDir), forceBuildAll);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void build(ExtFile appDir, boolean forceBuildAll)
|
||||||
|
throws AndrolibException {
|
||||||
|
new File(appDir, APK_DIRNAME).mkdirs();
|
||||||
|
buildSources(appDir, forceBuildAll);
|
||||||
|
buildResources(appDir, forceBuildAll);
|
||||||
|
buildApk(appDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void buildSources(File appDir, boolean forceBuildAll)
|
||||||
|
throws AndrolibException {
|
||||||
|
if (! buildSourcesRaw(appDir, forceBuildAll)
|
||||||
|
&& ! buildSourcesSmali(appDir, forceBuildAll)) {
|
||||||
|
throw new AndrolibException("Could not find sources");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean buildSourcesRaw(File appDir, boolean forceBuildAll)
|
||||||
|
throws AndrolibException {
|
||||||
|
try {
|
||||||
|
File working = new File(appDir, "classes.dex");
|
||||||
|
if (! working.exists()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
File stored = new File(appDir, APK_DIRNAME + "/classes.dex");
|
||||||
|
if (forceBuildAll || isModified(working, stored)) {
|
||||||
|
LOGGER.info("Copying classes.dex file...");
|
||||||
|
BrutIO.copyAndClose(new FileInputStream(working),
|
||||||
|
new FileOutputStream(stored));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new AndrolibException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean buildSourcesSmali(File appDir, boolean forceBuildAll)
|
||||||
|
throws AndrolibException {
|
||||||
|
File smaliDir = new File(appDir, "smali");
|
||||||
|
if (! smaliDir.exists()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
File dex = new File(appDir, APK_DIRNAME + "/classes.dex");
|
||||||
|
if (! forceBuildAll) {
|
||||||
|
LOGGER.info("Checking whether sources has changed...");
|
||||||
|
}
|
||||||
|
if (forceBuildAll || isModified(smaliDir, dex)) {
|
||||||
|
LOGGER.info("Smaling...");
|
||||||
|
dex.delete();
|
||||||
|
mSmali.smali(smaliDir, dex);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void buildResources(ExtFile appDir, boolean forceBuildAll)
|
||||||
|
throws AndrolibException {
|
||||||
|
if (! buildResourcesRaw(appDir, forceBuildAll)
|
||||||
|
&& ! buildResourcesFull(appDir, forceBuildAll)) {
|
||||||
|
throw new AndrolibException("Could not find resources");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean buildResourcesRaw(ExtFile appDir, boolean forceBuildAll)
|
||||||
|
throws AndrolibException {
|
||||||
|
try {
|
||||||
|
if (! new File(appDir, "resources.arsc").exists()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
File apkDir = new File(appDir, APK_DIRNAME);
|
||||||
|
if (! forceBuildAll) {
|
||||||
|
LOGGER.info("Checking whether resources has changed...");
|
||||||
|
}
|
||||||
|
if (forceBuildAll || isModified(
|
||||||
|
newFiles(APK_RESOURCES_FILENAMES, appDir),
|
||||||
|
newFiles(APK_RESOURCES_FILENAMES, apkDir))) {
|
||||||
|
LOGGER.info("Copying raw resources");
|
||||||
|
appDir.getDirectory()
|
||||||
|
.copyToDir(apkDir, APK_RESOURCES_FILENAMES);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (DirectoryException ex) {
|
||||||
|
throw new AndrolibException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean buildResourcesFull(File appDir, boolean forceBuildAll)
|
||||||
|
throws AndrolibException {
|
||||||
|
try {
|
||||||
|
if (! forceBuildAll) {
|
||||||
|
LOGGER.info("Checking whether resources has changed...");
|
||||||
|
}
|
||||||
|
File apkDir = new File(appDir, APK_DIRNAME);
|
||||||
|
if (forceBuildAll || isModified(
|
||||||
|
newFiles(APP_RESOURCES_FILENAMES, appDir),
|
||||||
|
newFiles(APK_RESOURCES_FILENAMES, apkDir))) {
|
||||||
|
LOGGER.info("Building resources...");
|
||||||
|
|
||||||
|
File apkFile = File.createTempFile("APKTOOL", null);
|
||||||
|
apkFile.delete();
|
||||||
|
|
||||||
|
mAndRes.aaptPackage(
|
||||||
|
apkFile,
|
||||||
|
new File(appDir, "AndroidManifest.xml"),
|
||||||
|
new File(appDir, "res")
|
||||||
|
);
|
||||||
|
|
||||||
|
new ExtFile(apkFile).getDirectory()
|
||||||
|
.copyToDir(apkDir, APK_RESOURCES_FILENAMES);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new AndrolibException(ex);
|
||||||
|
} catch (DirectoryException ex) {
|
||||||
|
throw new AndrolibException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void buildApk(File appDir) throws AndrolibException {
|
||||||
|
LOGGER.info("Building apk file");
|
||||||
|
File outApk = new File(appDir, OUT_APK_FILENAME);
|
||||||
|
if (outApk.exists()) {
|
||||||
|
outApk.delete();
|
||||||
|
} else {
|
||||||
|
File outDir = outApk.getParentFile();
|
||||||
|
if (! outDir.exists()) {
|
||||||
|
outDir.mkdirs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
File assetDir = new File(appDir, "assets");
|
||||||
|
if (! assetDir.exists()) {
|
||||||
|
assetDir = null;
|
||||||
|
}
|
||||||
|
mAndRes.aaptPackage(outApk, null, null,
|
||||||
|
new File(appDir, APK_DIRNAME), assetDir, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isModified(File working, File stored) {
|
||||||
|
if (! stored.exists()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return BrutIO.recursiveModifiedTime(working) >
|
||||||
|
BrutIO.recursiveModifiedTime(stored);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isModified(File[] working, File[] stored) {
|
||||||
|
for (int i = 0; i < stored.length; i++) {
|
||||||
|
if (! stored[i].exists()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return BrutIO.recursiveModifiedTime(working) >
|
||||||
|
BrutIO.recursiveModifiedTime(stored);
|
||||||
|
}
|
||||||
|
|
||||||
|
private File[] newFiles(String[] names, File dir) {
|
||||||
|
File[] files = new File[names.length];
|
||||||
|
for (int i = 0; i < names.length; i++) {
|
||||||
|
files[i] = new File(dir, names[i]);
|
||||||
|
}
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
private final static Logger LOGGER =
|
private final static Logger LOGGER =
|
||||||
Logger.getLogger(Androlib.class.getName());
|
Logger.getLogger(Androlib.class.getName());
|
||||||
|
|
||||||
private final static String SMALI_DIRNAME = "smali";
|
private final static String SMALI_DIRNAME = "smali";
|
||||||
|
private final static String APK_DIRNAME = "build/apk";
|
||||||
|
private final static String OUT_APK_FILENAME = "dist/out.apk";
|
||||||
|
private final static String[] APK_RESOURCES_FILENAMES =
|
||||||
|
new String[]{"resources.arsc", "AndroidManifest.xml", "res"};
|
||||||
|
private final static String[] APP_RESOURCES_FILENAMES =
|
||||||
|
new String[]{"AndroidManifest.xml", "res"};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user