Reduce the size of an APK file

8

Is it possible to reduce the size of an APK file by changing the way it is compressed?

It is well known that an APK file is just a signed, aligned ZIP file. However, I have run some tests, and if the contents of an APK file is extracted, and then compressed again to a new ZIP file, its size decreases further.

But if I rename this ZIP file back to APK, Google Play complains that the file is neither signed nor aligned.

How to solve this?

* I know other techniques for reducing APK files, how to use ProGuard to obfuscate and optimize the file, remove duplicate assets and resources, and more. Is it even possible to decrease the final size of the APK by changing its compression?

    
asked by anonymous 12.09.2014 / 19:59

2 answers

6

Yes, you can reduce the size of an APK file by just changing its compression.

You can use any ZIP utility, such as WinZip, WinRAR, or 7-Zip. I used 7-Zip.

To execute these commands, I created a .BAT script, but here I explain step-by-step script lines (my APK file is C:\Android\Teste.apk ).

First make sure that the temporary folder used in the process is empty, in my case C:\Android\TempAPK :

if exist C:\Android\TempAPK (
del /S /Q C:\Android\TempAPK
rd /S /Q C:\Android\TempAPK
)
md C:\Android\TempAPK

Then, I extract the content of the APK to this temporary folder:

"C:\Program Files-Zipz.exe" x C:\Android\Teste.apk -oC:\Android\TempAPK

Next, you should exclude the folder META-INF , along with its content (I did not use the deltree command because I did not find it in Windows 8):

del C:\Android\TempAPK\META-INF /S /Q
rd C:\Android\TempAPK\META-INF

Then, I compress the files again to a file named Teste.zip using the Deflate method (this is MANDATORY ), and with the compression settings to the maximum:

cd C:\Android
"C:\Program Files-Zipz.exe" a -tzip C:\Android\Teste.zip .\TempAPK\* -mm=Deflate -mpass=15 -mfb=258

Now you need to sign this ZIP, using the jarsigner tool, which comes with JDK (in my case, it is JDK 1.7.0_10):

cd "C:\Program Files\Java\jdk1.7.0_10\bin"
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore C:\Android\keystore\keystore.bin -storepass <SENHA DA KEYSTORE> -keypass <SENHA DA KEY> C:\Android\Teste.zip <ALIAS DA KEY>

Now just align the ZIP file using the zipalign tool, creating the final APK, and clear all temporary files (note the path of the SDK):

cd C:\Android\sdk\build-tools\android-4.4W
del C:\Android\Teste.apk
zipalign 4 C:\Android\Teste.zip C:\Android\Teste.apk

del /S /Q C:\Android\TempAPK
rd /S /Q C:\Android\TempAPK
del C:\Android\Teste.zip

This reduced the size of my APK from 330kB to 274kB.

More about signing on the Google website:

Signing Your Applications

Building and Running from the Command Line

    
12.09.2014 / 19:59
5

With the inspiration and excerpts from the Rafael solution, below is my adaptation for the Linux platform.

Requirements:

  • 7zip, to install: sudo apt-get install p7zip-full .
  • unzip.
  • jarsigner, located in JDK.
  • zipalign, located in the build-tools/versao_do_buildtools/zipalign folder of the Android SDK.
  • The script is:

    #!/bin/sh
    
    # Interrompe o script ao primeiro erro
    set -e
    
    # Nome do keystore que ira usar no jarsigner
    keystore_name=nome_do_keystore 
    
    # Guardo o nome do usuario corrente
    me=$(whoami)
    
    # Variavel que guarda a localizacao do keystore, usado no jarsigner
    keystore_location=/home/$me/.android/$keystore_name.jks
    
    # Caminho para o diretorio onde esta o apk
    apk_directory=caminho_para_o_seu_apk
    
    # Caminho do apk com o nome
    apk_location=$apk_directory/nome_do_seu_apk.apk
    
    # Caminho para o apk final, pronto para producao
    apk_location_aligned=$apk_directory/nome_do_seu_apk-release.apk
    
    # Alias name usado na keystore
    alias_name=seu_alias_name
    
    echo 'Fazendo a descompressão do apk'
    
    unzip "$apk_location" -d "$apk_directory/apk-uncompressed"
    
    echo 'Apagando o META-INF'
    
    rm -r -f "$apk_directory/apk-uncompressed/META-INF"
    
    echo 'Apagando APK antigo'
    rm -f "$apk_location"
    
    echo 'Comprimindo novamente com maior eficiencia'
    7z a -tzip "$apk_location" "$apk_directory/*" -mm=Deflate -mpass=15 -mfb=258
    
    echo 'Apagando pasta temporaria'
    rm -r -f "$apk_directory/apk-uncompressed"
    
    echo 'iniciando jarsigner'
    jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore "$keystore_location" "$apk_location" "$alias_name"
    echo 'jarsigner finalizado'
    
    echo 'iniciando zipalign'
    # Corrigir local para o zipalign conforme o necessario
    /home/$me/android-studio/sdk/build-tools/20.0.0/zipalign -v 4 "$apk_location" "$apk_location_aligned"
    echo 'zipalign finalizado'
    

    I need to make some adaptations depending on the variables I left, some directories may vary depending on the organization of the person and the Linux distribution (I used Ubuntu).

    I made this process in my apk, reduced the size from 986.5 kB to 787.0 kB , a gain of 199.5kB . Of course, the reduction will vary from apk to apk, depending on the number of resources it uses (xml, png's) and the libraries you use.

        
    12.09.2014 / 22:29