mirror of
https://github.com/revanced/Apktool.git
synced 2025-05-09 18:24:26 +02:00
Support explicit operation for when to load full resource table (#3217)
This commit is contained in:
parent
20afa7d2e5
commit
7a4a20ba34
@ -22,6 +22,7 @@ import brut.androlib.exceptions.OutDirExistsException;
|
|||||||
import brut.androlib.apk.ApkInfo;
|
import brut.androlib.apk.ApkInfo;
|
||||||
import brut.androlib.res.ResourcesDecoder;
|
import brut.androlib.res.ResourcesDecoder;
|
||||||
import brut.androlib.res.data.*;
|
import brut.androlib.res.data.*;
|
||||||
|
import brut.androlib.res.xml.ResXmlPatcher;
|
||||||
import brut.androlib.src.SmaliDecoder;
|
import brut.androlib.src.SmaliDecoder;
|
||||||
import brut.directory.Directory;
|
import brut.directory.Directory;
|
||||||
import brut.directory.ExtFile;
|
import brut.directory.ExtFile;
|
||||||
@ -50,6 +51,10 @@ public class ApkDecoder {
|
|||||||
private final static String[] APK_STANDARD_ALL_FILENAMES = new String[] {
|
private final static String[] APK_STANDARD_ALL_FILENAMES = new String[] {
|
||||||
"classes.dex", "AndroidManifest.xml", "resources.arsc", "res", "r", "R",
|
"classes.dex", "AndroidManifest.xml", "resources.arsc", "res", "r", "R",
|
||||||
"lib", "libs", "assets", "META-INF", "kotlin" };
|
"lib", "libs", "assets", "META-INF", "kotlin" };
|
||||||
|
private final static String[] APK_RESOURCES_FILENAMES = new String[] {
|
||||||
|
"resources.arsc", "res", "r", "R" };
|
||||||
|
private final static String[] APK_MANIFEST_FILENAMES = new String[] {
|
||||||
|
"AndroidManifest.xml" };
|
||||||
private final static Pattern NO_COMPRESS_PATTERN = Pattern.compile("(" +
|
private final static Pattern NO_COMPRESS_PATTERN = Pattern.compile("(" +
|
||||||
"jpg|jpeg|png|gif|wav|mp2|mp3|ogg|aac|mpg|mpeg|mid|midi|smf|jet|rtttl|imy|xmf|mp4|" +
|
"jpg|jpeg|png|gif|wav|mp2|mp3|ogg|aac|mpg|mpeg|mid|midi|smf|jet|rtttl|imy|xmf|mp4|" +
|
||||||
"m4a|m4v|3gp|3gpp|3g2|3gpp2|amr|awb|wma|wmv|webm|webp|mkv)$");
|
"m4a|m4v|3gp|3gpp|3g2|3gpp2|amr|awb|wma|wmv|webm|webp|mkv)$");
|
||||||
@ -92,8 +97,27 @@ public class ApkDecoder {
|
|||||||
LOGGER.info("Using Apktool " + ApktoolProperties.getVersion() + " on " + mApkFile.getName());
|
LOGGER.info("Using Apktool " + ApktoolProperties.getVersion() + " on " + mApkFile.getName());
|
||||||
|
|
||||||
ResourcesDecoder resourcesDecoder = new ResourcesDecoder(mConfig, mApkFile);
|
ResourcesDecoder resourcesDecoder = new ResourcesDecoder(mConfig, mApkFile);
|
||||||
resourcesDecoder.decodeManifest(outDir);
|
if (hasResources()) {
|
||||||
resourcesDecoder.decodeResources(outDir);
|
switch (mConfig.decodeResources) {
|
||||||
|
case Config.DECODE_RESOURCES_NONE:
|
||||||
|
copyResourcesRaw(outDir);
|
||||||
|
break;
|
||||||
|
case Config.DECODE_RESOURCES_FULL:
|
||||||
|
resourcesDecoder.decodeResources(outDir);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasManifest()) {
|
||||||
|
if (mConfig.decodeResources == Config.DECODE_RESOURCES_FULL ||
|
||||||
|
mConfig.forceDecodeManifest == Config.FORCE_DECODE_MANIFEST_FULL) {
|
||||||
|
resourcesDecoder.decodeManifest(outDir);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
copyManifestRaw(outDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resourcesDecoder.updateApkInfo(outDir);
|
||||||
|
|
||||||
if (hasSources()) {
|
if (hasSources()) {
|
||||||
switch (mConfig.decodeSources) {
|
switch (mConfig.decodeSources) {
|
||||||
@ -135,7 +159,7 @@ public class ApkDecoder {
|
|||||||
|
|
||||||
// In case we have no resources. We should store the minSdk we pulled from the source opcode api level
|
// In case we have no resources. We should store the minSdk we pulled from the source opcode api level
|
||||||
ApkInfo apkInfo = resourcesDecoder.getApkInfo();
|
ApkInfo apkInfo = resourcesDecoder.getApkInfo();
|
||||||
if (! resourcesDecoder.hasResources() && mMinSdkVersion > 0) {
|
if (!hasResources() && mMinSdkVersion > 0) {
|
||||||
apkInfo.setSdkInfoField("minSdkVersion", Integer.toString(mMinSdkVersion));
|
apkInfo.setSdkInfoField("minSdkVersion", Integer.toString(mMinSdkVersion));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,6 +178,22 @@ public class ApkDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean hasManifest() throws AndrolibException {
|
||||||
|
try {
|
||||||
|
return mApkFile.getDirectory().containsFile("AndroidManifest.xml");
|
||||||
|
} catch (DirectoryException ex) {
|
||||||
|
throw new AndrolibException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasResources() throws AndrolibException {
|
||||||
|
try {
|
||||||
|
return mApkFile.getDirectory().containsFile("resources.arsc");
|
||||||
|
} catch (DirectoryException ex) {
|
||||||
|
throw new AndrolibException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean hasSources() throws AndrolibException {
|
private boolean hasSources() throws AndrolibException {
|
||||||
try {
|
try {
|
||||||
return mApkFile.getDirectory().containsFile("classes.dex");
|
return mApkFile.getDirectory().containsFile("classes.dex");
|
||||||
@ -187,6 +227,26 @@ public class ApkDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void copyManifestRaw(File outDir)
|
||||||
|
throws AndrolibException {
|
||||||
|
try {
|
||||||
|
LOGGER.info("Copying raw manifest...");
|
||||||
|
mApkFile.getDirectory().copyToDir(outDir, APK_MANIFEST_FILENAMES);
|
||||||
|
} catch (DirectoryException ex) {
|
||||||
|
throw new AndrolibException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyResourcesRaw(File outDir)
|
||||||
|
throws AndrolibException {
|
||||||
|
try {
|
||||||
|
LOGGER.info("Copying raw resources...");
|
||||||
|
mApkFile.getDirectory().copyToDir(outDir, APK_RESOURCES_FILENAMES);
|
||||||
|
} catch (DirectoryException ex) {
|
||||||
|
throw new AndrolibException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void copySourcesRaw(File outDir, String filename)
|
private void copySourcesRaw(File outDir, String filename)
|
||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
try {
|
try {
|
||||||
|
@ -29,7 +29,6 @@ import brut.directory.Directory;
|
|||||||
import brut.directory.DirectoryException;
|
import brut.directory.DirectoryException;
|
||||||
import brut.directory.ExtFile;
|
import brut.directory.ExtFile;
|
||||||
import brut.directory.FileDirectory;
|
import brut.directory.FileDirectory;
|
||||||
import brut.util.Duo;
|
|
||||||
import org.xmlpull.v1.XmlSerializer;
|
import org.xmlpull.v1.XmlSerializer;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -48,10 +47,6 @@ public class ResourcesDecoder {
|
|||||||
private final ApkInfo mApkInfo;
|
private final ApkInfo mApkInfo;
|
||||||
private final Map<String, String> mResFileMapping = new HashMap<>();
|
private final Map<String, String> mResFileMapping = new HashMap<>();
|
||||||
|
|
||||||
private final static String[] APK_RESOURCES_FILENAMES = new String[] {
|
|
||||||
"resources.arsc", "res", "r", "R" };
|
|
||||||
private final static String[] APK_MANIFEST_FILENAMES = new String[] {
|
|
||||||
"AndroidManifest.xml" };
|
|
||||||
private final static String[] IGNORED_PACKAGES = new String[] {
|
private final static String[] IGNORED_PACKAGES = new String[] {
|
||||||
"android", "com.htc", "com.lge", "com.lge.internal", "yi", "flyme", "air.com.adobe.appentry",
|
"android", "com.htc", "com.lge", "com.lge.internal", "yi", "flyme", "air.com.adobe.appentry",
|
||||||
"FFFFFFFFFFFFFFFFFFFFFF" };
|
"FFFFFFFFFFFFFFFFFFFFFF" };
|
||||||
@ -85,9 +80,6 @@ public class ResourcesDecoder {
|
|||||||
throw new AndrolibException(
|
throw new AndrolibException(
|
||||||
"Apk doesn't contain either AndroidManifest.xml file or resources.arsc file");
|
"Apk doesn't contain either AndroidManifest.xml file or resources.arsc file");
|
||||||
}
|
}
|
||||||
if (hasResources() && !mResTable.isMainPkgLoaded()) {
|
|
||||||
mResTable.loadMainPkg(mApkFile);
|
|
||||||
}
|
|
||||||
return mResTable;
|
return mResTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,38 +93,31 @@ public class ResourcesDecoder {
|
|||||||
|
|
||||||
public void decodeManifest(File outDir) throws AndrolibException {
|
public void decodeManifest(File outDir) throws AndrolibException {
|
||||||
if (hasManifest()) {
|
if (hasManifest()) {
|
||||||
if (mConfig.decodeResources == Config.DECODE_RESOURCES_FULL ||
|
decodeManifest(getResTable(), mApkFile, outDir);
|
||||||
mConfig.forceDecodeManifest == Config.FORCE_DECODE_MANIFEST_FULL) {
|
if (hasResources()) {
|
||||||
decodeManifest(getResTable(), mApkFile, outDir);
|
if (!mConfig.analysisMode) {
|
||||||
if (hasResources()) {
|
// Remove versionName / versionCode (aapt API 16)
|
||||||
if (!mConfig.analysisMode) {
|
//
|
||||||
// Remove versionName / versionCode (aapt API 16)
|
// check for a mismatch between resources.arsc package and the package listed in AndroidManifest
|
||||||
//
|
// also remove the android::versionCode / versionName from manifest for rebuild
|
||||||
// check for a mismatch between resources.arsc package and the package listed in AndroidManifest
|
// this is a required change to prevent aapt warning about conflicting versions
|
||||||
// also remove the android::versionCode / versionName from manifest for rebuild
|
// it will be passed as a parameter to aapt like "--min-sdk-version" via apktool.yml
|
||||||
// this is a required change to prevent aapt warning about conflicting versions
|
adjustPackageManifest(getResTable(), outDir.getAbsolutePath() + File.separator + "AndroidManifest.xml");
|
||||||
// it will be passed as a parameter to aapt like "--min-sdk-version" via apktool.yml
|
|
||||||
adjustPackageManifest(getResTable(), outDir.getAbsolutePath() + File.separator + "AndroidManifest.xml");
|
|
||||||
|
|
||||||
ResXmlPatcher.removeManifestVersions(new File(
|
ResXmlPatcher.removeManifestVersions(new File(
|
||||||
outDir.getAbsolutePath() + File.separator + "AndroidManifest.xml"));
|
outDir.getAbsolutePath() + File.separator + "AndroidManifest.xml"));
|
||||||
|
|
||||||
// update apk info
|
// update apk info
|
||||||
mApkInfo.packageInfo.forcedPackageId = String.valueOf(mResTable.getPackageId());
|
mApkInfo.packageInfo.forcedPackageId = String.valueOf(mResTable.getPackageId());
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
try {
|
|
||||||
LOGGER.info("Copying raw manifest...");
|
|
||||||
mApkFile.getDirectory().copyToDir(outDir, APK_MANIFEST_FILENAMES);
|
|
||||||
} catch (DirectoryException ex) {
|
|
||||||
throw new AndrolibException(ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateApkInfo(File outDir) throws AndrolibException {
|
||||||
|
mResTable.initApkInfo(mApkInfo, outDir);
|
||||||
|
}
|
||||||
|
|
||||||
private void decodeManifest(ResTable resTable, ExtFile apkFile, File outDir)
|
private void decodeManifest(ResTable resTable, ExtFile apkFile, File outDir)
|
||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
|
|
||||||
@ -191,22 +176,14 @@ public class ResourcesDecoder {
|
|||||||
return serial;
|
return serial;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void loadMainPkg() throws AndrolibException {
|
||||||
|
mResTable.loadMainPkg(mApkFile);
|
||||||
|
}
|
||||||
|
|
||||||
public ResTable decodeResources(File outDir) throws AndrolibException {
|
public ResTable decodeResources(File outDir) throws AndrolibException {
|
||||||
if (hasResources()) {
|
if (hasResources()) {
|
||||||
switch (mConfig.decodeResources) {
|
loadMainPkg();
|
||||||
case Config.DECODE_RESOURCES_NONE:
|
decodeResources(getResTable(), mApkFile, outDir);
|
||||||
try {
|
|
||||||
LOGGER.info("Copying raw resources...");
|
|
||||||
mApkFile.getDirectory().copyToDir(outDir, APK_RESOURCES_FILENAMES);
|
|
||||||
} catch (DirectoryException ex) {
|
|
||||||
throw new AndrolibException(ex);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Config.DECODE_RESOURCES_FULL:
|
|
||||||
decodeResources(getResTable(), mApkFile, outDir);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
mResTable.initApkInfo(mApkInfo, outDir);
|
|
||||||
}
|
}
|
||||||
return mResTable;
|
return mResTable;
|
||||||
}
|
}
|
||||||
|
@ -58,8 +58,8 @@ public class NonStandardPkgIdTest extends BaseTest {
|
|||||||
Config.getDefaultConfig(), new ExtFile(testApk));
|
Config.getDefaultConfig(), new ExtFile(testApk));
|
||||||
|
|
||||||
sTestNewDir.mkdirs();
|
sTestNewDir.mkdirs();
|
||||||
resourcesDecoder.decodeManifest(sTestNewDir);
|
|
||||||
mResTable = resourcesDecoder.decodeResources(sTestNewDir);
|
mResTable = resourcesDecoder.decodeResources(sTestNewDir);
|
||||||
|
resourcesDecoder.decodeManifest(sTestNewDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
|
@ -57,6 +57,7 @@ public class DecodeArrayTest extends BaseTest {
|
|||||||
Config.getDefaultConfig(),
|
Config.getDefaultConfig(),
|
||||||
new ExtFile(sTmpDir + File.separator + apk));
|
new ExtFile(sTmpDir + File.separator + apk));
|
||||||
|
|
||||||
|
resourcesDecoder.loadMainPkg();
|
||||||
ResTable resTable = resourcesDecoder.getResTable();
|
ResTable resTable = resourcesDecoder.getResTable();
|
||||||
ResValue value = resTable.getResSpec(0x7f020001).getDefaultResource().getValue();
|
ResValue value = resTable.getResSpec(0x7f020001).getDefaultResource().getValue();
|
||||||
|
|
||||||
@ -70,6 +71,7 @@ public class DecodeArrayTest extends BaseTest {
|
|||||||
Config.getDefaultConfig(),
|
Config.getDefaultConfig(),
|
||||||
new ExtFile(sTmpDir + File.separator + apk));
|
new ExtFile(sTmpDir + File.separator + apk));
|
||||||
|
|
||||||
|
resourcesDecoder.loadMainPkg();
|
||||||
ResTable resTable = resourcesDecoder.getResTable();
|
ResTable resTable = resourcesDecoder.getResTable();
|
||||||
ResValue value = resTable.getResSpec(0x7f020000).getDefaultResource().getValue();
|
ResValue value = resTable.getResSpec(0x7f020000).getDefaultResource().getValue();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user