Skip to content

Conversation

@kediarov
Copy link
Contributor

@kediarov kediarov commented Jun 19, 2025

https://mapbox.atlassian.net/browse/MAPSAND-2026

First things first: why the @Keep annotation is not working?

The crash is happening when trying to call getDeclaredMethod("create...") of ModuleProvider which is being shrunk because the ModuleProvider is an interface inside, but not a member of Mapbox_ module so it is not affected by the outer @Keep annotation. ModuleProvider is generated when enableConfiguration = true.

Even though the Keep annotation docs say Do not use this within library code the Mapbox_ module is generated by annotation processor and is being added to the module with where the target class annotated with @MapboxModule is located.

The rule -keep @androidx.annotation.Keep class * {*;} to keep annotated targets is added to proguard-android file which is usually always added to every project.

com.mapbox.module.Mapbox_MapTelemetryModuleConfiguration$ModuleProvider
|- is referenced in keep rule:
|  proguard.txt:44:1
com.mapbox.maps.module.MapTelemetry com.mapbox.module.Mapbox_MapTelemetryModuleConfiguration$ModuleProvider.createMapTelemetry()
|- is referenced in keep rule:
|  default_proguard_files/global/proguard-android.txt-7.4.2:85:1

The direct solution is to add the @Keep annotation to the ModuleProvider. The other solution is to add -keep class com.mapbox.module.** {*;} but this rule is less accurate and more vague and might affect other classes in the package.

@kediarov kediarov requested review from a team and pengdev June 19, 2025 09:09
@kediarov kediarov self-assigned this Jun 19, 2025
const val kotlin = "1.4.10"
const val androidX = "1.1.0"
const val license = "0.8.5"
const val license = "0.9.0"
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 have aligned this version with the mapbox-maps-android project as 0.8.5 version is no longer available

@kediarov kediarov marked this pull request as ready for review June 19, 2025 09:17
@kediarov kediarov requested a review from a team as a code owner June 19, 2025 09:17
// if configuration is enabled, generate module instance provider field that has to be passed by the user
val providerInterface =
TypeSpec.interfaceBuilder(MODULE_CONFIGURATION_PROVIDER_CLASS_NAME)
.addAnnotation(Keep::class)
Copy link
Member

Choose a reason for hiding this comment

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

could you add some code snippets showcasing the generated code before the fix vs after the fix?

Copy link
Contributor Author

@kediarov kediarov Jun 19, 2025

Choose a reason for hiding this comment

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

The only change is at

@Keep
interface ModuleProvider

Before

package com.mapbox.module

import androidx.annotation.Keep
import com.mapbox.maps.module.MapTelemetry
import kotlin.Boolean
import kotlin.jvm.JvmStatic

/**
 * Configuration provider for MapTelemetry module.
 */
@Keep
object Mapbox_MapTelemetryModuleConfiguration {
  @JvmStatic
  val enableConfiguration: Boolean = true

  /**
   * Set this dependency provider before initializing any components of the modularized library.
   *
   * When you're not using the library anymore, you should pass `null` to clean up the provider
   * reference and prevent memory leaks.
   */
  @JvmStatic
  var moduleProvider: ModuleProvider? = null

  interface ModuleProvider {
    fun createMapTelemetry(): MapTelemetry
  }
}

After

package com.mapbox.module

import androidx.annotation.Keep
import com.mapbox.maps.module.MapTelemetry
import kotlin.Boolean
import kotlin.jvm.JvmStatic

/**
 * Configuration provider for MapTelemetry module.
 */
@Keep
object Mapbox_MapTelemetryModuleConfiguration {
  @JvmStatic
  val enableConfiguration: Boolean = true

  /**
   * Set this dependency provider before initializing any components of the modularized library.
   *
   * When you're not using the library anymore, you should pass `null` to clean up the provider
   * reference and prevent memory leaks.
   */
  @JvmStatic
  var moduleProvider: ModuleProvider? = null

  @Keep
  interface ModuleProvider {
    fun createMapTelemetry(): MapTelemetry
  }
}

Copy link
Member

Choose a reason for hiding this comment

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

Thanks! Did you also validate the fix in maps SDK?

@pengdev
Copy link
Member

pengdev commented Jun 19, 2025

@kediarov please also update the title of the PR with descriptions

@pengdev pengdev requested review from a team and natiginfo June 19, 2025 10:15
@kediarov kediarov changed the title kir/obfuscation-generated-module-configuration-files Generated module configuration files are obfuscated Jun 19, 2025
tools = "4.1.3"
kotlin = "1.4.10"
androidX = "1.1.0"
license = "0.9.0"
Copy link
Contributor Author

@kediarov kediarov Jun 19, 2025

Choose a reason for hiding this comment

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

Older version Is not available
Aligned with mapbox-maps-android

@kediarov kediarov changed the title Generated module configuration files are obfuscated Fix generated module configuration files being obfuscated Jun 19, 2025
@pengdev
Copy link
Member

pengdev commented Jun 19, 2025

@kediarov it's also good to update the snapshot version in https://github.com/mapbox/mapbox-base-android/blob/master/gradle.properties to 1.12.0-SNAPSHOT since you are going to publish 1.12.0 release

@pengdev pengdev requested a review from jush June 19, 2025 12:08
Copy link
Member

@pengdev pengdev left a comment

Choose a reason for hiding this comment

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

LGTM, thanks for the fix!

enableFeaturePreview("VERSION_CATALOGS")
dependencyResolutionManagement {
versionCatalogs {
create("baseLibs") {
Copy link
Member

Choose a reason for hiding this comment

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

out of curiosity, why rename it to baseLibs instead of the its default name?

// if configuration is enabled, generate module instance provider field that has to be passed by the user
val providerInterface =
TypeSpec.interfaceBuilder(MODULE_CONFIGURATION_PROVIDER_CLASS_NAME)
.addAnnotation(Keep::class)
Copy link
Member

Choose a reason for hiding this comment

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

nice catch! 💎

@natiginfo natiginfo mentioned this pull request Jun 23, 2025
@kediarov kediarov merged commit f07f51d into master Jun 23, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants