-
Notifications
You must be signed in to change notification settings - Fork 691
[Crashlytics] Fix release build cache invalidation #8185
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
8e04c7c
6520b46
6918ab9
7e1c779
e7499f3
dcfd122
0502746
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -26,21 +26,32 @@ import com.google.firebase.crashlytics.buildtools.mappingfiles.MappingFileIdWrit | ||||||||||
| import java.io.File | |||||||||||
| import org.gradle.api.DefaultTask | |||||||||||
| import org.gradle.api.Project | |||||||||||
| import org.gradle.api.file.ConfigurableFileCollection | |||||||||||
| import org.gradle.api.file.DirectoryProperty | |||||||||||
| import org.gradle.api.file.RegularFileProperty | |||||||||||
| import org.gradle.api.provider.Property | |||||||||||
| import org.gradle.api.tasks.CacheableTask | |||||||||||
| import org.gradle.api.tasks.Internal | |||||||||||
| import org.gradle.api.tasks.Input | |||||||||||
| import org.gradle.api.tasks.InputFiles | |||||||||||
| import org.gradle.api.tasks.OutputDirectory | |||||||||||
| import org.gradle.api.tasks.OutputFile | |||||||||||
| import org.gradle.api.tasks.PathSensitive | |||||||||||
| import org.gradle.api.tasks.PathSensitivity | |||||||||||
| import org.gradle.api.tasks.TaskAction | |||||||||||
| import org.gradle.api.tasks.TaskProvider | |||||||||||
| import org.gradle.kotlin.dsl.register | |||||||||||
|
|
|||||||||||
| /** Inject mapping file id task. */ | |||||||||||
| @CacheableTask | |||||||||||
| abstract class InjectMappingFileIdTask : DefaultTask() { | |||||||||||
| @get:Internal abstract val useBlankMappingFileId: Property<Boolean> | |||||||||||
| @get:Input abstract val useBlankMappingFileId: Property<Boolean> | |||||||||||
|
|
|||||||||||
| @get:[InputFiles PathSensitive(PathSensitivity.RELATIVE)] | |||||||||||
| abstract val obfuscatableSources: ConfigurableFileCollection | |||||||||||
|
|
|||||||||||
| @get:[InputFiles PathSensitive(PathSensitivity.NONE)] | |||||||||||
| abstract val obfuscatableClasspath: ConfigurableFileCollection | |||||||||||
|
|
|||||||||||
| @get:OutputFile abstract val mappingFileIdFile: RegularFileProperty | |||||||||||
| @get:OutputDirectory abstract val resourceDir: DirectoryProperty | |||||||||||
|
|
|||||||||||
|
|
@@ -66,32 +77,45 @@ abstract class InjectMappingFileIdTask : DefaultTask() { | ||||||||||
| ) | |||||||||||
| } | |||||||||||
|
|
|||||||||||
| /** | |||||||||||
| * Check if a mapping file id file already exists, and that the mapping file id is blank - meaning | |||||||||||
| * no obfuscation is enabled. The Crashlytics SDK always needs a mapping file id. | |||||||||||
| */ | |||||||||||
| private fun blankMappingFileIdExists(): Boolean { | |||||||||||
| val file: File = mappingFileIdFile.get().asFile | |||||||||||
| return file.exists() && file.readText() == CrashlyticsBuildtools.BLANK_MAPPING_FILE_ID | |||||||||||
| } | |||||||||||
|
|
|||||||||||
| internal companion object { | |||||||||||
| @Suppress("UnstableApiUsage") // isMinifyEnabled | |||||||||||
| @Suppress("UnstableApiUsage") // isMinifyEnabled, compileClasspath | |||||||||||
| fun register( | |||||||||||
| project: Project, | |||||||||||
| variant: ApplicationVariant, | |||||||||||
| crashlyticsExtension: CrashlyticsVariantExtension, | |||||||||||
| ): TaskProvider<InjectMappingFileIdTask> { | |||||||||||
| val useBlank = | |||||||||||
| !crashlyticsExtension.mappingFileUploadEnabled.getOrElse(variant.isMinifyEnabled) | |||||||||||
|
|
|||||||||||
| val injectMappingFileIdTaskProvider = | |||||||||||
| project.tasks.register<InjectMappingFileIdTask>( | |||||||||||
| "injectCrashlyticsMappingFileId${variant.name.capitalized()}" | |||||||||||
| ) { | |||||||||||
| this.useBlankMappingFileId.set( | |||||||||||
| !crashlyticsExtension.mappingFileUploadEnabled.getOrElse(variant.isMinifyEnabled) | |||||||||||
| ) | |||||||||||
| this.useBlankMappingFileId.set(useBlank) | |||||||||||
| this.mappingFileIdFile.set(buildFile(project, variant, "mappingFileId.txt")) | |||||||||||
|
|
|||||||||||
| outputs.upToDateWhen { useBlankMappingFileId.get() && blankMappingFileIdExists() } | |||||||||||
| // Only fingerprint inputs when obfuscation is on. In blank-id mode the id is constant | |||||||||||
| // and source/classpath changes are irrelevant to the mapping handle. | |||||||||||
| // | |||||||||||
| // Discover user source files via project.fileTree("src") rather than | |||||||||||
| // variant.sources.java/kotlin.all. AGP's accessor includes generated source dirs | |||||||||||
| // (R.java, deeplinks, view-binding, etc.) whose producer tasks depend on the same | |||||||||||
| // mergeResources pipeline that consumes THIS task's output, which would close a cycle. | |||||||||||
| // AGP 8.1.4 has no `static` getter (added in 8.6) that would expose the non-generated | |||||||||||
| // subset, so we hand-roll the discovery from on-disk source-set conventions. | |||||||||||
| if (!useBlank) { | |||||||||||
| this.obfuscatableSources.from( | |||||||||||
| project.fileTree("src").matching { patterns -> | |||||||||||
| patterns.include( | |||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We tried something like this before, it looked more like But this created circular dependencies when apps used things like compose. If source depends on resources, and resources depend on sources, we have a circular dependency. Can you confirm if this has the same problem?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ran both implementations against the real
Compose alone is not a trigger, the trigger is view/data binding. So the circular dependency will only be present if I use The |
|||||||||||
| "**/java/**/*.java", | |||||||||||
| "**/java/**/*.kt", | |||||||||||
| "**/kotlin/**/*.java", | |||||||||||
| "**/kotlin/**/*.kt", | |||||||||||
| ) | |||||||||||
| patterns.exclude("test/**", "androidTest/**", "test*/**", "androidTest*/**") | |||||||||||
| } | |||||||||||
| ) | |||||||||||
| } | |||||||||||
| } | |||||||||||
|
|
|||||||||||
| // It is not possible to disable Android resources in the AGP app plugin. | |||||||||||
|
|
|||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@OOS93 Applied your suggestion