📜 ⬆️ ⬇️

Decrease apk size (reasonably)

Habr.com already had a similar article proving that it is possible to shrink an APK file from 1.5 MB to 1757 bytes or less. The purpose of this article is to reduce the size of the application to a reasonable limit, while retaining its functionality and to highlight some subtleties and implicit moments.

Start


Create a project in Android Studio, select Empty Activity. Then in the styles.xml file we replace the Activity with ActionBar

Theme.AppCompat.Light.DarkActionBar 

on Activity without ActionBar

 Theme.AppCompat.Light.NoActionBar 

Total:
')
image

In the APK analyzer see the following:



So, APK weighs 1.5 MB, despite the fact that it only displays the inscription “Hello World!”.

Stage one (minification)


In the file build.gradle we write:

 android { buildTypes { debug { minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile ('proguard-android.txt'), 'proguard-rules.pro' } } } 

Sync Android Studio for the changes to take effect.

Explanation:

 minifyEnabled true 
removes unnecessary code in the application
 shrinkResources true 
will remove unused resources from the APK.

Weight APK became 960 KB, without changes in work.

Stage two (adding functionality)


To make the application make sense, add functionality to it, for example, a clicker.

Code activity_main.xml
 <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/number" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" android:textSize="20dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <ImageButton android:id="@+id/imageButton" android:layout_width="90dp" android:layout_height="90dp" android:layout_marginBottom="32dp" android:layout_marginEnd="8dp" android:layout_marginStart="8dp" android:background="#000000FF" android:cropToPadding="false" android:scaleType="fitXY" android:visibility="visible" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:srcCompat="@mipmap/ic_launcher_round" /> </android.support.constraint.ConstraintLayout> 


Code MainActivity.java
 import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.MotionEvent; import android.view.View; import android.widget.ImageButton; import android.widget.TextView; public class MainActivity extends AppCompatActivity { SharedPreferences Settings; ImageButton button; TextView text; int num = 31; View.OnTouchListener on = new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { num--; if(num > 0) { text.setText(Integer.toString(num)); } else { num = 31; text.setText(",   "); } } return false; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Settings = getSharedPreferences("settings", Context.MODE_PRIVATE); if (Settings.contains("left")) num = Settings.getInt("left", 0); button = findViewById(R.id.imageButton); button.setOnTouchListener(on); text = findViewById(R.id.number); if(num > 0) { text.setText(Integer.toString(num)); } else { num = 31; text.setText(",   "); } } @Override protected void onPause() { super.onPause(); SharedPreferences.Editor editor = Settings.edit(); editor.putInt("left", num); editor.apply(); } } 

The application has acquired the following form:



Application size 1.1 MB, an increase of 140 KB.

Stage Three (remove android.support and AppCompat)


At the moment, the APK analyzer shows the following:



public class MainActivity extends AppCompatActivity with the public class MainActivity extends Activity in MainActivity.java. Press Alt + Enter for Android Studio to import the libraries.

The size of the application has not changed, but ...



Where is the button?

In fact, everything is in order, it remained clickable. But she just does not have a picture.

Go to activity_main.xml, find the line below

 app:srcCompat="@mipmap/ic_launcher_round" 

and change it to

 android:src="@mipmap/ic_launcher_round" 

Now everything is all right:



But the size has not changed.

Go back to build.gradle and clear the dependency block:

 dependencies { } 

And sync Android Studio ... with errors.

1. Go to the res / values ​​/ styles.xml file and replace all its contents with the following code:

 <resources> <style name="AppTheme" parent="android:Theme.DeviceDefault.NoActionBar"> </style> </resources> 

2. ConstraintLayout, which is used in Android Studio, depends on android.support, which has already been removed from the dependencies block, so we will replace ConstraintLayout with RelativeLayout, which does not depend on android.support.

Code activity_main.xml:
 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FFFFFF"> <TextView android:id="@+id/number" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:text="Hello World!" android:textSize="20dp" /> <ImageButton android:id="@+id/imageButton" android:layout_width="90dp" android:layout_height="90dp" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="32dp" android:background="#000000FF" android:scaleType="fitXY" android:src="@mipmap/ic_launcher_round" android:visibility="visible" /> </RelativeLayout> 


Compile the APK and see the result:



Our APK weighs 202 KB, which is 7.5 times smaller than its initial size.

Most of the resources are occupied, and we will deal with them.

1. Delete the files in the res / drawable folder and clear the res / mipmap folder
2. Draw your icon and button, then reduce its size using ImageOptim.

Button:



Icon:



3. Load them into Android Studio, to do this, select them in the folder, press Ctrl + C, go to Android Studio, select the res / drawable folder and press Ctrl + V, after which Andoid Studio will offer several options for where to transfer the images depending from their permission.

In the drawable folder, you can rename the file by selecting Refactor -> Rename.
The application icon is named i.png, the image for the b.png button

4. Now go to the file AndroidManifest.xml, lines

 android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" 

replace on

 android:icon="@drawable/i" android:roundIcon="@drawable/i" 

In the activity_main.xml file, replace the field in the ImageButton

 android:src="@mipmap/ic_launcher_round" 

on

 android:src="@drawable/b" 

Total


The final file size is 13.4 KB, which is 112 times smaller than the initial volume!

Summary code MainActivity.java
 import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; import android.view.MotionEvent; import android.view.View; import android.widget.ImageButton; import android.widget.TextView; public class MainActivity extends Activity { SharedPreferences Settings; ImageButton button; TextView text; int num = 31; View.OnTouchListener on = new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { num--; if(num > 0) { text.setText(Integer.toString(num)); } else { num = 31; text.setText(",   "); } } return false; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.m); Settings = getSharedPreferences("settings", Context.MODE_PRIVATE); if (Settings.contains("left")) num = Settings.getInt("left", 0); text = findViewById(R.id.number); button = findViewById(R.id.button); button.setOnTouchListener(on); if(num > 0) { text.setText(Integer.toString(num)); } else { num = 31; text.setText(",  "); } } @Override protected void onPause() { super.onPause(); SharedPreferences.Editor editor = Settings.edit(); editor.putInt("left", num); editor.apply(); } } 


The resulting code activity_main.xml
 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FFFFFF"> <TextView android:id="@+id/number" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:text="Hello World!" android:textSize="20dp" /> <ImageButton android:id="@+id/button" android:layout_width="90dp" android:layout_height="90dp" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="32dp" android:background="#000000FF" android:scaleType="fitXY" android:src="@drawable/b" android:visibility="visible" /> </RelativeLayout> 


This ends a reasonable decrease in the APK file, followed by instructions for further reducing the application to the detriment of development convenience.

We delete resources


Delete the res / values ​​folder, in the AndroidManifest.xml file, replace the application block with the following code:

 <application android:icon="@drawable/i" android:roundIcon="@drawable/i" android:label="Clicker" android:theme="@style/android:Theme.DeviceDefault.NoActionBar"> <activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /></intent-filter> </activity> </application> 

Also replace the identifiers with single-letter ones, rename the activity_main.xml file to m.xml

Change the click processing:

Delete the line

 button.setOnTouchListener(on); 

in MainLayout.java.
Replace function

 View.OnTouchListener on = new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { num--; if(num > 0) { text.setText(Integer.toString(num)); } else { num = 31; text.setText(",   "); } } return false; } }; 

on
 public void o(View v) { num--; if(num > 0) { text.setText(Integer.toString(num)); } else { num = 31; text.setText(",   "); } } 

In the file m.xml (formerly activity_main) in the ImageButton structure, add the line

 android:onClick="o" 

The total size was 10.2 KB , 147 times smaller than the initial size. I think this is a good result.



Code MainActivity.java
 import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; import android.view.View; import android.widget.ImageButton; import android.widget.TextView; public class MainActivity extends Activity { SharedPreferences Settings; ImageButton button; TextView text; int num = 31; public void o(View v) { num--; if(num > 0) { text.setText(Integer.toString(num)); } else { num = 31; text.setText(",   "); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.m); Settings = getSharedPreferences("settings", Context.MODE_PRIVATE); if (Settings.contains("left")) num = Settings.getInt("left", 0); text = findViewById(R.id.n); button = findViewById(R.id.b); if(num > 0) { text.setText(Integer.toString(num)); } else { num = 31; text.setText(",  "); } } @Override protected void onPause() { super.onPause(); SharedPreferences.Editor editor = Settings.edit(); editor.putInt("left", num); editor.apply(); } } 


M.xml code
 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FFFFFF"> <TextView android:id="@+id/n" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:textColor="#000000" android:textSize="20dp" /> <ImageButton android:id="@+id/b" android:layout_width="90dp" android:layout_height="90dp" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="32dp" android:background="#000000FF" android:scaleType="fitXY" android:src="@drawable/b" android:onClick="o" android:visibility="visible" /> </RelativeLayout> 

Source: https://habr.com/ru/post/417845/


All Articles