androidapk

How to remove V4 support library from this minimal "hello, world" Android project?


I'm trying to repeat steps from the tutorial on how to build a minimal .apk file. My motivation is that I want to learn about the inner workings of the related technologies in their minimal form and the .apk file mentioned on the website doesn't install on latest versions of Android. While I'm repeating the steps, I realized that I can't go below the .apk size of a 565KB and the generated .apk file is dominated by 255KB of classes.dex, which lists 246 classes. It's nowhere near sub-100KB size mentioned in the post, so I assumed I'm doing something wrong. It's not easy for me to translate steps to Kotlin version of Gradle config. I noticed I'm pulling in support library:

> dexdump classes.dex | grep 'Class descr' | grep support
  Class descriptor  : 'Landroid/support/v4/app/RemoteActionCompatParcelizer;'
  Class descriptor  : 'Landroid/support/v4/graphics/drawable/IconCompatParcelizer;'

I assume that's not necessary in the resulting file, how to get rid of "support" library entirely?

Here's my project file (also hosted on Github for convenience and in case I missed anything):

app/src/main/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <application
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

settings.gradle.kts

pluginManagement {
    repositories {
        google {
            content {
                includeGroupByRegex("com\\.android.*")
                includeGroupByRegex("com\\.google.*")
                includeGroupByRegex("androidx.*")
            }
        }
        mavenCentral()
        gradlePluginPortal()
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}

rootProject.name = "basic_views_activity"
include(":app")

build.gradle.kts

// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
    alias(libs.plugins.android.application) apply false
}

app/build.gradle.kts

plugins {
    alias(libs.plugins.android.application)
}

android {



    namespace = "com.example.basic_views_activity"
    compileSdk = 34

    configurations.all {
        exclude(group = "com.android.support", module = "support-v4")
    }

    defaultConfig {
        applicationId = "com.example.basic_views_activity"
        minSdk = 28
        targetSdk = 34
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        debug {
            isMinifyEnabled = true
            isShrinkResources = true
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )

        }
        release {
            isMinifyEnabled = true
            isShrinkResources = true
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
    buildFeatures {
        viewBinding = true
    }
}

dependencies {
    implementation(libs.constraintlayout)
}

app/proguard-rules.pro

-keep class com.example.basic_views_activity.** { *; }
-keep class com.example.basic_views_activity.MainActivity { *; }

app/src/main/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <application
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

app/src/main/java/com/example/basic_views_activity/MainActivity.java

package com.example.basic_views_activity;

import android.os.Bundle;

import com.example.basic_views_activity.databinding.ActivityMainBinding;

import android.app.Activity;

public class MainActivity extends Activity {

    private ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());


    }

}

app/src/main/res/layout/activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:text="Hello World!" />

Solution

  • You are pulling in androidx.constraintlayout:constraintlayout:2.1.4 via implementation(libs.constraintlayout). You do not need this library, based on the source in the question, as I do not see you using ConstraintLayout anywhere.

    If you run a Gradle dependency report, you should see that it depends on three other libraries (androidx.appcompat:appcompat:1.2.0, androidx.core:core:1.3.2, and androidx.constraintlayout:constraintlayout-core:1.0.4). And, if you continue down the report, you will eventually find which of those three is pulling in the support-v4 code.

    FWIW, removing ConstraintLayout is covered in this section of the document that you are following.