REAndroid / ARSCLib

Android binary resources read/write library
Apache License 2.0
220 stars 44 forks source link

Slow apk merging for large resource.arsc files #26

Closed xiaoyvyv closed 1 year ago

xiaoyvyv commented 1 year ago

When the resource.arsc file of base.apk is very large, such as 10-20MB. Merge apks will take a significant amount of time, especially when running on Android devices. I found that the following area can be optimized. If the baseModule exists, it can be directly used as the root node of Merge. Instead of creating a new module and merging the baseModule.


public class ApkBundle {
    ...

    public ApkModule mergeModules() throws IOException {
        List<ApkModule> moduleList=getApkModuleList();
        if(moduleList.size()==0){
            throw new FileNotFoundException("Nothing to merge, empty modules");
        }

        // This place can be optimized, Use the baseMode when it present in aps dir as the mergeRoot module instead of create a new module.
        ApkModule result=new ApkModule(generateMergedModuleName(), new APKArchive());
        result.setAPKLogger(apkLogger);

        mergeStringPools(result);

        ApkModule base=getBaseModule();
        if(base==null){
            base=getLargestTableModule();
        }
        result.merge(base);
        for(ApkModule module:moduleList){
            if(module==base){
                continue;
            }
            result.merge(module);
        }
        if(result.hasTableBlock()){
            TableBlock tableBlock=result.getTableBlock();
            tableBlock.sortPackages();
            tableBlock.refresh();
        }
        result.getApkArchive().sortApkFiles();
        return result;
    }

    ...
}

I have made some rough modifications, there may be issues

public ApkModule mergeModules() throws IOException {
         List<ApkModule> moduleList = getApkModuleList();
         if (moduleList.size() == 0) {
             throw new FileNotFoundException("Nothing to merge, empty modules");
         }

         ApkModule result = getBaseModule();
         if (result == null) {
             result = getLargestTableModule();
         }

         result.setModuleName(generateMergedModuleName());
         result.setAPKLogger(apkLogger);

         mergeStringPools(result);

         for (ApkModule module : moduleList) {
             if (module == result) {
                 continue;
             }
             result.merge(module);
         }
         if (result.hasTableBlock()) {
             TableBlock tableBlock = result.getTableBlock();
             tableBlock.sortPackages();
             tableBlock.refresh();
         }
         result.getApkArchive().sortApkFiles();
         return result;
     }
REAndroid commented 1 year ago

StringPool should be created/merged at first because styled strings should be placed at the top row. On your mod either you will loose styled strings or duplicate strings will be created.

        long start = System.currentTimeMillis();
        mergeModules();
        long elapsed = System.currentTimeMillis() - start;
xiaoyvyv commented 1 year ago

GBoard.zip

xiaoyvyv commented 1 year ago

StringPool should be created/merged at first because styled strings should be placed at the top row. On your mod either you will loose styled strings or duplicate strings will be created.

* Can you share your apk files?

* I am not testing it on android platform right now, if you can please record elapsed time for merging like
        long start = System.currentTimeMillis();
        mergeModules();
        long elapsed = System.currentTimeMillis() - start;

It takes about 120 seconds on Android, but it's much faster on my Mac.

REAndroid commented 1 year ago

GBoard.zip

Your link is not working

xiaoyvyv commented 1 year ago

GBoard.zip

Your link is not working

https://fileport.io/SpWUM2TLt8Cs

REAndroid commented 1 year ago

It takes about 120 seconds on Android, but it's much faster on my Mac.

Do you mean 12 seconds? I have tested with huge apk with 125Mb (2.5M resources) the max time recorded is 25 seconds

Check the latest commit, it has much improvements

xiaoyvyv commented 1 year ago

It takes about 120 seconds on Android, but it's much faster on my Mac.

Do you mean 12 seconds? I have tested with huge apk with 125Mb (2.5M resources) the max time recorded is 25 seconds

Check the latest commit, it has much improvements

I ran the test again using the latest commit, and the improvement is significant. It now only takes 20 seconds. That's fantastic!