Automatic Selectors for Jetpack Compose

Who can use this feature?
- Available with Mobile add-on.
- Available for admins, architects, and standard users.

Automatic Selectors for Jetpack Compose is currently in Beta. Added in Fullstory for Mobile Apps 1.55.0.

About automatic selectors

Automatic selectors for Jetpack Compose allows for full selectors to be generated on elements based on the @Composable method names, without the need to add Fullstory Modifiers.

Enabling Auto-Selector Support

Make sure Jetpack Compose support is enabled by following the Getting Started with Jetpack Compose help documentation. Be sure to set the composeSelectorVersion.

To opt in to the Beta for Automatic Selectors, set composeAutoSelectorsBetaEnabled to true in the fullstory properties block of the app's build.gradle file, as follows:

fullstory {
    ...
    composeAutoSelectorsBetaEnabled = true
}

Selector Changes

Without automatic selectors, only elements with Fullstory Modifiers or other automatically captured Modifiers appear in the selector. With automatic selectors enabled, a full selector is generated based on the @Composable method names called to generate each element. Modifiers are still added to and change the selector, but keep in mind they only affect the UI element they are ultimately attached to, not necessarily the @Composable in which they are first instantiated or passed as arguments to.

For example the following preview...

@Composable
fun CustomTextButton(
    modifier: Modifier, textModifier: Modifier, text: String, onClick: () -> Unit = {}
) {
    Button(onClick = onClick, modifier = modifier) {
        Text(text, textModifier)
    }
}
@Preview
@Composable
fun CustomTextButtonPreview() {
    CustomTextButton(
        Modifier.fsAttribute("attr1", "value1"),
        Modifier.fsAttribute("attr2", "value2"),
        "Click Me"
    )
}
 

...would generate the below selectors (with composeSelectorVersion set to 4 or higher).

Without auto-selectors: compose[attr1="value1"][semantic-role="button"] > compose[type="text"][attr2="value2"]

With auto-selectors: customtextbutton > button[attr1="value1"][semantic-role="button"] > text[type="text"][attr2="value2"]

Additional Processing

Generating auto-selectors requires additional information that isn't always available at runtime. In order to support this we modify the compilation process slightly and perform additional processing at build time. This is handled automatically by the plugin, but there are certain caveats to be called out.

@Composable method names

The names of all of the Composable methods and their containing classes are collected and stored in a .properties file in the app's assets.

SourceInformation methods

Jetpack Compose has some sourceInformation methods that are added to debuggable builds for tooling purposes (i.e. Layout Inspector). When Fullstory is enabled in a build, all of the KotlinCompile tasks are updated to include these methods in the .class file output. If multiple variants are assembled with the same gradle command, all KotlinCompile tasks in the task graph are affected, even if Fullstory is not enabled for all variants. These sourceInformation calls are removed when minification is enabled, but this should be kept in mind if creating any AARs or other artifacts to be used externally that are not minified.

If using JPC 1.7+ the sourceInformationMarkerStart and sourceInformationMarkerEnd methods will not be removed by minification when Fullstory is enabled. The compose-runtime library is transformed to remove the proguard rules that delete these methods when auto-selectors are enabled; this happens regardless of Fullstory being enabled or not. The source string arguments supplied to the sourceInformationMarkerStart method calls are removed by Fullstory, when enabled, so no additional information about the app's source code is exposed. When Fullstory is disabled, the removed proguard rules are regenerated, so there should be no effect on the compiled app.


Was this article helpful?

Got Questions?

Get in touch with a Fullstory rep, ask the community or check out our developer documentation.