Skip to content

Commit

Permalink
2.1.3
Browse files Browse the repository at this point in the history
Update APKEditor and other dependencies from REAndroid
Remove dependency on Apache Commons Compress (Fix processing some XAPK files on older Android versions)
  • Loading branch information
AbdurazaaqMohammed committed Oct 29, 2024
1 parent bb44dfd commit a64c9bf
Show file tree
Hide file tree
Showing 1,451 changed files with 158,927 additions and 4,938 deletions.
5 changes: 2 additions & 3 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ android {
applicationId = "com.abdurazaaqmohammed.AntiSplit"
minSdk = 19
targetSdk = 35
versionCode = 40
versionName = "2.1.2"
versionCode = 41
versionName = "2.1.3"
multiDexEnabled = true
}

Expand All @@ -34,7 +34,6 @@ android {
viewBinding = false
}
dependencies {
implementation("org.apache.commons:commons-compress:1.24.0")
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.2")
implementation("com.google.android.material:material:1.12.0")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
package com.abdurazaaqmohammed.AntiSplit.main;

import android.content.Context;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Build;
import android.text.TextUtils;
import android.util.DisplayMetrics;

import com.j256.simplezip.ZipFileInput;
import com.j256.simplezip.format.ZipFileHeader;
import com.reandroid.archive.ArchiveFile;
import com.reandroid.archive.InputSource;
import com.reandroid.archive.ZipEntryMap;
import com.starry.FileUtils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;


public class DeviceSpecsUtil {

private final Context context;
public final String lang;
private final String densityType;
public static ZipFile zipFile = null;
public static ArchiveFile zipFile = null;

public DeviceSpecsUtil(Context context) {
this.context = context;
Expand All @@ -52,10 +52,10 @@ public List<String> getListOfSplits(Uri splitAPKUri) throws IOException {
try(InputStream is = context.getContentResolver().openInputStream(splitAPKUri)) {
if(couldNotRead) FileUtils.copyFile(is, file = new File(context.getCacheDir(), file.getName()));
}
Enumeration<ZipArchiveEntry> entries = (zipFile = new ZipFile(file)).getEntries();
ZipEntryMap entries = (zipFile = new ArchiveFile(file)).createZipEntryMap();
// Do not close this ZipFile it could be used later in merger
while (entries.hasMoreElements()) {
String name = entries.nextElement().getName();
for(InputSource inputSource : entries.toArray()) {
String name = inputSource.getName();
if (name.endsWith(".apk")) splits.add(name);
}
}
Expand Down
173 changes: 106 additions & 67 deletions app/src/main/java/com/reandroid/apk/ApkBundle.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

import static com.abdurazaaqmohammed.AntiSplit.main.MainActivity.rss;


import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
Expand All @@ -26,88 +25,69 @@
import com.abdurazaaqmohammed.AntiSplit.main.DeviceSpecsUtil;
import com.abdurazaaqmohammed.AntiSplit.main.MainActivity;
import com.abdurazaaqmohammed.AntiSplit.main.MismatchedSplitsException;
import com.android.apksig.apk.ApkUtils;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.reandroid.apkeditor.merge.LogUtil;
import com.reandroid.archive.BlockInputSource;
import com.reandroid.archive.ZipEntryMap;
import com.reandroid.archive.block.ApkSignatureBlock;
import com.reandroid.arsc.chunk.TableBlock;
import com.reandroid.arsc.pool.builder.StringPoolMerger;
import com.reandroid.utils.collection.ArrayCollection;

import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.zip.ZipFile;

public class ApkBundle implements Closeable {
private final Map<String, ApkModule> mModulesMap;

private APKLogger apkLogger;
public ApkBundle(){
this.mModulesMap=new HashMap<>();
}

public ApkModule mergeModules() throws IOException {
return mergeModules(false);
}
public ApkModule mergeModules(boolean force) throws IOException {
List<ApkModule> moduleList=getApkModuleList();
if(moduleList.isEmpty()) throw new FileNotFoundException("Nothing to merge, empty modules");
if(moduleList.isEmpty()){
throw new FileNotFoundException("Nothing to merge, empty modules");
}
ApkModule result = new ApkModule(generateMergedModuleName(), new ZipEntryMap());
result.setAPKLogger(apkLogger);
result.setLoadDefaultFramework(false);

mergeStringPools(result);

ApkModule base=getBaseModule();
if(base==null) base = getLargestTableModule();
result.merge(base);
if(base == null){
base = getLargestTableModule();
}
result.merge(base, force);
ApkSignatureBlock signatureBlock = null;
for(ApkModule module:moduleList){
ApkSignatureBlock asb = module.getApkSignatureBlock();
if(module==base){
if(asb != null) signatureBlock = asb;
if(asb != null){
signatureBlock = asb;
}
continue;
}
if(signatureBlock == null) signatureBlock = asb;
result.merge(module);
if(signatureBlock == null){
signatureBlock = asb;
}
result.merge(module, force);
}

result.setApkSignatureBlock(signatureBlock);

if(result.hasTableBlock()) {
if(result.hasTableBlock()){
TableBlock tableBlock=result.getTableBlock();
tableBlock.sortPackages();
tableBlock.refresh();
}
result.getZipEntryMap().autoSortApkFiles();
return result;
}
private void mergeStringPools(ApkModule mergedModule) throws IOException {
if(!hasOneTableBlock() || mergedModule.hasTableBlock()) return;
LogUtil.logMessage("Merging string pools ... ");
TableBlock createdTable = new TableBlock();
BlockInputSource<TableBlock> inputSource=
new BlockInputSource<>(TableBlock.FILE_NAME, createdTable);
mergedModule.getZipEntryMap().add(inputSource);

StringPoolMerger poolMerger = new StringPoolMerger();

for(ApkModule apkModule:getModules()) if (apkModule.hasTableBlock()) poolMerger.add(apkModule.getVolatileTableStringPool());

poolMerger.mergeTo(createdTable.getTableStringPool());

LogUtil.logMessage("Merged string pools="+poolMerger.getMergedPools()
+", style="+poolMerger.getMergedStyleStrings()
+", strings="+poolMerger.getMergedStrings());
}
private String generateMergedModuleName(){
Set<String> moduleNames=mModulesMap.keySet();
String merged="merged";
Expand Down Expand Up @@ -144,7 +124,24 @@ public ApkModule getBaseModule(){
return null;
}
public List<ApkModule> getApkModuleList(){
return new ArrayList<>(mModulesMap.values());
return new ArrayCollection<>(mModulesMap.values());
}
public void loadApkDirectory(File dir) throws IOException{
loadApkDirectory(dir, false);
}
public void loadApkDirectory(File dir, boolean recursive) throws IOException {
if(!dir.isDirectory()) throw new FileNotFoundException("No such directory: " + dir);
List<File> apkList = recursive ? ApkUtil.recursiveFiles(dir, ".apk") : ApkUtil.listFiles(dir, ".apk");
if(apkList.isEmpty())
throw new FileNotFoundException("No '*.apk' files in directory: " + dir);
logMessage("Found apk files: "+apkList.size());
for(File file:apkList){
logVerbose("Loading: "+file.getName());
String name = ApkUtil.toModuleName(file);
ApkModule module = ApkModule.loadApkFile(file, name);
module.setAPKLogger(apkLogger);
addModule(module);
}
}

public void loadApkDirectory(File dir, boolean recursive, Context context) throws IOException, MismatchedSplitsException, InterruptedException {
Expand All @@ -157,17 +154,24 @@ public void loadApkDirectory(File dir, boolean recursive, Context context) throw
int base = -1;
for(int i = 0; i < size; i++){
File file = apkList.get(i);
try(ZipFile zf = new ZipFile(file);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
InputStream is = zf.getInputStream(zf.getEntry("AndroidManifest.xml"))) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1) byteArrayOutputStream.write(buffer, 0, bytesRead);
versionCodes[i] = ApkUtils.getVersionCodeFromBinaryAndroidManifest(ByteBuffer.wrap(byteArrayOutputStream.toByteArray()));
if(DeviceSpecsUtil.isBaseApk(file.getName())) base = versionCodes[i];
} catch (Exception e) {
versionCodes[i] = -1;
}
// try(ArchiveFile archiveFile = new ArchiveFile(file)) {
// archiveFile.
// }
// try(ZipFile zf = new ZipFile(file);
// ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
// InputStream is = zf.getInputStream(zf.getEntry("AndroidManifest.xml"))) {
// byte[] buffer = new byte[1024];
// int bytesRead;
// while ((bytesRead = is.read(buffer)) != -1) byteArrayOutputStream.write(buffer, 0, bytesRead);
// versionCodes[i] = ApkUtils.getVersionCodeFromBinaryAndroidManifest(ByteBuffer.wrap(byteArrayOutputStream.toByteArray()));
// if(DeviceSpecsUtil.isBaseApk(file.getName())) base = versionCodes[i];
// } catch (Exception e) {
// versionCodes[i] = -1;
// }
String name = ApkUtil.toModuleName(file);
ApkModule module = ApkModule.loadApkFile(file, name);
versionCodes[i] = module.getVersionCode();
if(DeviceSpecsUtil.isBaseApk(file.getName())) base = versionCodes[i];
}
if(base == -1) {
// It is a valid usage to merge only some files and then merge that merged file with the base later.
Expand Down Expand Up @@ -201,18 +205,18 @@ public void loadApkDirectory(File dir, boolean recursive, Context context) throw
MainActivity act = ((MainActivity) context);
act.getHandler().post(() ->
act.runOnUiThread(new MaterialAlertDialogBuilder(context).setTitle(rss.getString(R.string.warning)).setMessage(rss.getString(R.string.mismatch, s.replaceFirst(", ", "")))
.setPositiveButton("OK", (dialog, which) -> {
for(String filename : s.split(", ")) {
File f = new File(dir, filename);
if(f.delete()) apkList.remove(f);
}
latch.countDown();
}).setNegativeButton(rss.getString(R.string.cancel), (dialog, which) -> {
act.startActivity(new Intent(act, MainActivity.class));
act.finishAffinity();
latch.countDown();
})
.create()::show));
.setPositiveButton("OK", (dialog, which) -> {
for(String filename : s.split(", ")) {
File f = new File(dir, filename);
if(f.delete()) apkList.remove(f);
}
latch.countDown();
}).setNegativeButton(rss.getString(R.string.cancel), (dialog, which) -> {
act.startActivity(new Intent(act, MainActivity.class));
act.finishAffinity();
latch.countDown();
})
.create()::show));
latch.await();
}
load(apkList);
Expand All @@ -231,6 +235,21 @@ public void addModule(ApkModule apkModule){
mModulesMap.remove(name);
mModulesMap.put(name, apkModule);
}
public boolean containsApkModule(String moduleName){
return mModulesMap.containsKey(moduleName);
}
public ApkModule removeApkModule(String moduleName){
return mModulesMap.remove(moduleName);
}
public ApkModule getApkModule(String moduleName){
return mModulesMap.get(moduleName);
}
public List<String> listModuleNames(){
return new ArrayList<>(mModulesMap.keySet());
}
public int countModules(){
return mModulesMap.size();
}
public Collection<ApkModule> getModules(){
return mModulesMap.values();
}
Expand All @@ -244,7 +263,27 @@ private boolean hasOneTableBlock(){
}
@Override
public void close() throws IOException {
for(ApkModule module : mModulesMap.values()) module.close();
for(ApkModule module : mModulesMap.values()) {
module.close();
}
mModulesMap.clear();
}
public void setAPKLogger(APKLogger logger) {
this.apkLogger = logger;
}
private void logMessage(String msg) {
if(apkLogger!=null){
apkLogger.logMessage(msg);
}
}
private void logError(String msg, Throwable tr) {
if(apkLogger!=null){
apkLogger.logError(msg, tr);
}
}
private void logVerbose(String msg) {
if(apkLogger!=null){
apkLogger.logVerbose(msg);
}
}
}
Loading

0 comments on commit a64c9bf

Please sign in to comment.