Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
- name: Build
run: ./gradlew assemble
- name: Upload artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: build-artifacts
path: |
Expand Down
8 changes: 6 additions & 2 deletions docs/plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,14 @@ appSizer {
```

### Run the analysis

If you need to analyze apk files generated from the aab file according to device specs:
```bash
./gradlew app:appSizeAnalysis[Release|Debug] --no-configure-on-demand --no-configuration-cache
```
Or if you need to analyze the apk file that is the result of the assemble task, you can execute the following command:
```bash
./gradlew app:apkSizeAnalysis[Release|Debug] --no-configure-on-demand --no-configuration-cache
```

## Configuration
Use the registered `appSizer` extension block to the app module's `build.gradle` to configure App Sizer Plugin
Expand Down Expand Up @@ -88,7 +92,7 @@ appSizer {
variant.setIgnore(variant.flavors.contains("your-ignore-flavor"))
}
apk {
// APK Generation
// APK Generation from aab
}
Copy link
Contributor

@MinhNguyen-nvm MinhNguyen-nvm Feb 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the other comment, I mean, let's keep the "apk" extension as well

}
...
Expand Down
2 changes: 2 additions & 0 deletions docs/task_graph.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ flowchart TD
A(generateApkDebug)
B(generateArchiveDepDebug)
C(appSizeAnalysisDebug)
D(apkSizeAnalysisDebug)


C --> A
C --> B
D --> B
```
6 changes: 5 additions & 1 deletion sample/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ appSizer {
To run the App Sizer analysis using the Gradle plugin:

1. Open a terminal in the sample project directory.
2. Execute the following command:
2. If you need to analyze apk files generated from the aab file according to device specs:
```
./gradlew app:appSizeAnalysisProRelease --no-configure-on-demand
```
Or if you need to analyze the apk file that is the result of the assemble task, you can execute the following command:
```
./gradlew app:appSizeAnalysisProRelease --no-configure-on-demand
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
package com.grab.plugin.sizer

import com.android.build.gradle.AppExtension
import com.android.build.gradle.api.ApplicationVariant
import com.android.build.gradle.api.BaseVariant
import com.android.build.gradle.internal.dsl.BuildType
import com.android.build.gradle.internal.dsl.ProductFlavor
Expand All @@ -37,14 +38,17 @@ import com.grab.plugin.sizer.dependencies.*
import com.grab.plugin.sizer.tasks.AppSizeAnalysisTask
import com.grab.plugin.sizer.tasks.GenerateApkTask
import com.grab.plugin.sizer.tasks.GenerateArchivesListTask
import com.grab.plugin.sizer.tasks.capitalize
import com.grab.plugin.sizer.utils.isAndroidApplication
import com.grab.plugin.sizer.utils.isAndroidLibrary
import com.grab.plugin.sizer.utils.isJava
import com.grab.plugin.sizer.utils.isKotlinJvm
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.file.Directory
import org.gradle.api.tasks.TaskProvider
import org.gradle.kotlin.dsl.listProperty
import org.gradle.kotlin.dsl.the

/*
Expand All @@ -71,55 +75,95 @@ internal class TaskManager(
val variantFilter = DefaultVariantFilter(variant)
pluginExtension.input.variantFilter?.execute(variantFilter)
if (!variantFilter.ignored) {
val generateApkTask = GenerateApkTask.registerTask(
project,
pluginExtension,
variant
)

val generateArchivesListTask = GenerateArchivesListTask.registerTask(
project,
project = project,
variant = variant,
flavorMatchingFallbacks = getProductFlavor(variant)?.matchingFallbacks ?: emptyList(),
buildTypeMatchingFallbacks = getOriginalBuildType(variant).matchingFallbacks,
enableMatchDebugVariant = pluginExtension.input.enableMatchDebugVariant
)

val appSizeAnalysisTask = AppSizeAnalysisTask.registerTask(
project,
variant,
pluginExtension,
generateApkTask,
generateArchivesListTask,
)
registerAppSizeTaskDep(project, variant, this, appSizeAnalysisTask)
runCatching {
registerCollectDependenciesTask(project, variant, this)
}.onFailure {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we still crash Gradle to print a full stacktrace?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the crash is very useful in this case. We have a few variants for which we can't create a task graph, but we also don't want to find them all and try to declare them in the variant filter. So we're better off just ignoring the log message

project.logger.error("Can't create tasks for ${project.name} with variant ${variant.name}")
}.onSuccess { collectAppDependenciesTask ->
createAabAnalysisTask(project, variant, generateArchivesListTask).configure {
dependsOn(collectAppDependenciesTask)
}
createApkAnalysisTask(project, variant, generateArchivesListTask).configure {
dependsOn(collectAppDependenciesTask)
}
}
}
}
}
}

private fun registerAppSizeTaskDep(
private fun createApkAnalysisTask(
project: Project,
variant: ApplicationVariant,
generateArchivesListTask: TaskProvider<GenerateArchivesListTask>
) = AppSizeAnalysisTask.registerTask(
name = "apk",
project = project,
variant = variant,
pluginExtension = pluginExtension,
apkDirectories = variant.packageApplicationProvider.map {
project.objects.listProperty<Directory>().value(listOf(it.outputDirectory.get()))
},
generateArchivesListTask = generateArchivesListTask,
)

private fun createAabAnalysisTask(
project: Project,
variant: ApplicationVariant,
generateArchivesListTask: TaskProvider<GenerateArchivesListTask>
): TaskProvider<AppSizeAnalysisTask> {
val generateApkFromAabTask = GenerateApkTask.registerTask(
project,
pluginExtension,
variant
)

val appSizeAnalysisTask = AppSizeAnalysisTask.registerTask(
name = "app",
project = project,
variant = variant,
pluginExtension = pluginExtension,
apkDirectories = generateApkFromAabTask.map { it.outputDirectories },
generateArchivesListTask = generateArchivesListTask,
)

return appSizeAnalysisTask
}

private fun registerCollectDependenciesTask(
project: Project,
variant: BaseVariant,
appExtension: AppExtension,
depTask: TaskProvider<out Task>
) {
): TaskProvider<Task> {
val dependenciesComponent = DaggerDependenciesComponent.factory().create(
project = project,
variantInput = variant.toVariantInput(),
flavorMatchingFallbacks = appExtension.getProductFlavor(variant)?.matchingFallbacks ?: emptyList(),
buildTypeMatchingFallbacks = appExtension.getOriginalBuildType(variant).matchingFallbacks,
enableMatchDebugVariant = pluginExtension.input.enableMatchDebugVariant
)
val collectDependenciesTask = project.tasks.register("collectAppDependencies${variant.name.capitalize()}")

val markAsChecked = mutableSetOf<String>()
dfs(project, markAsChecked, dependenciesComponent, depTask)
dfs(project, markAsChecked, dependenciesComponent, collectDependenciesTask)

return collectDependenciesTask
}

private fun dfs(
project: Project,
markAsChecked: MutableSet<String>,
dependenciesComponent: DependenciesComponent,
depTask: TaskProvider<out Task>
depTask: TaskProvider<Task>
) {
if (markAsChecked.contains(project.path)) return
markAsChecked.add(project.path)
Expand All @@ -135,7 +179,7 @@ internal class TaskManager(

private fun handleSubProject(
project: Project,
task: TaskProvider<out Task>,
task: TaskProvider<Task>,
variantExtractor: VariantExtractor
) {
when {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@

package com.grab.plugin.sizer.configuration

import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.ListProperty
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ open class InputExtension @Inject constructor(objects: ObjectFactory) {
var largeFileThreshold: Long = DEFAULT_LARGE_FILE
var enableMatchDebugVariant = false


fun variantFilter(action: Action<VariantFilter>) {
variantFilter = action
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,13 @@ import com.grab.sizer.report.db.InfluxDBConfig
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.Directory
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.MapProperty
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.*
import java.io.File

Expand Down Expand Up @@ -157,17 +160,18 @@ internal abstract class AppSizeAnalysisTask : DefaultTask() {

companion object {
fun registerTask(
name: String = "app",
project: Project,
variant: BaseVariant,
pluginExtension: AppSizePluginExtension,
generateApkTask: TaskProvider<GenerateApkTask>,
apkDirectories: Provider<ListProperty<Directory>>,
generateArchivesListTask: TaskProvider<GenerateArchivesListTask>,
): TaskProvider<AppSizeAnalysisTask> {
return project.tasks.register(
"appSizeAnalysis${variant.name.capitalize()}", AppSizeAnalysisTask::class.java
"${name}SizeAnalysis${variant.name.capitalize()}", AppSizeAnalysisTask::class.java
) {
this.variantInput.set(variant.toVariantInput())
this.apkDirectories.setFrom(generateApkTask.map { it.outputDirectories })
this.apkDirectories.setFrom(apkDirectories)
this.archiveDepJsonFile.set(generateArchivesListTask.map { it.archiveDepFile.get() })
this.libName.set(project.params().libraryName())
this.option.set(project.params().option())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import java.io.File

private const val EXT_AAR = "aar"
private const val EXT_JAR = "jar"
private const val EXT_APK = "apk"

class PluginInputProvider(
private val archiveDependencyStore: ArchiveDependencyStore,
Expand Down Expand Up @@ -79,7 +80,8 @@ class PluginInputProvider(
.filter { it.file.extension.equals(EXT_AAR, true) }

override fun provideApkFiles(): Sequence<File> {
return apksDirectory.listFiles()?.asSequence() ?: emptySequence()
return apksDirectory.listFiles()?.asSequence()?.filter { it.extension.equals(EXT_APK, true) }
?: emptySequence()
}

override fun provideR8MappingFile(): File? = r8MappingFile
Expand Down