Getting Started with Jetpack Compose

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

Integrating Fullstory’s Jetpack Compose support has a few extra steps after integrating our main SDK into your app. Before you begin, follow the setup process described in our Getting Started with Android Capture article.

Fullstory Jetpack Compose support was added in Fullstory for Mobile Apps 1.43.0.

Minimum Jetpack Compose version

1.0.0

Maximum Jetpack Compose version

1.7.x

Added in Fullstory for Mobile Apps 1.53.0

 

After implementing the instructions from the article mentioned above, proceed with the steps below:

  • Enable Jetpack Compose support in your app’s fullstory gradle config. You need to explicitly enable Jetpack Compose support in your application because there are some key differences between Fullstory for Jetpack Compose and Classic Android that you should be aware of.
  • Choose a selector version in your app’s fullstory config. Doing so ensures that future versions of the Fullstory plugin do not change the behavior of your privacy rules.
  • Use Modifier.fsMask() , Modifier.fsUnmask(), and Modifier.fsExclude() as appropriate, on Jetpack Compose Composables to implement your code-first privacy rules. Although privacy rules work on classes, it may be preferable to directly apply masking rules to Composable objects in this version of the Fullstory plugin to ensure that changes in Jetpack Compose keep your application private.
  • Use Modifier.fsAddClass(String) or other Modifier helper methods on Composables to provide semantic information on elements that you might want to add selector-based privacy rules to or search for in the future. Fullstory for Jetpack Compose requires that you tag views directly in code that you might later interact with in the Fullstory web interface.

Enabling Jetpack Compose Support

Follow the same Getting Started with Android Capture help documentation for standard Android integration.

Once that is complete, enable Jetpack Compose support by setting composeEnabled to true in the fullstory properties block (the same block where the org id is set) of the App’s build.gradle file. You should also set composeSelectorVersion to 5 (explained below)

fullstory {
orgId ...
...
composeEnabled true
composeSelectorVersion 4

}

Using Jetpack Compose in Library Modules

Follow the instructions for Using Fullstory in Library Modules with an additional dependency for the Fullstory compose AAR.

dependencies {
...
implementation 'com.fullstory:compose:<PLUGIN VERSION>@aar'
}

Differences Between Classic Android and Jetpack Compose

Fullstory for Jetpack Compose supports Private by Default.

Fullstory for Jetpack Compose supports session replay Fullcapture with Private by Default, just like Fullstory for Classic Android. All Jetpack Compose UI elements will be masked by default, captured automatically, and visible in playback without any manual instrumentation. But there are a few key differences you should be aware of.

Fullstory for Jetpack Compose only supports manual attributes set in code.

The main difference between Fullstory’s Classic Android and Jetpack Compose implementation is that in order to unmask or exclude views, our current support for Jetpack Compose requires developers to take a code-first approach and to attribute views with Modifier.fsAddClass(String) or other Modifier helper methods. These helper methods can set privacy rules directly (i.e., Modifier.fsUnmask()) or add to selector annotations for selector-based rules (i.e., Modifier.setAttribute(String, String)).

@Composable
fun Counter (count: Int, updateCount: (Int) -> Unit) {
  Button(
   modifier = Modifier.fsUnmask()
    onClick = { updateCount (count + 1) },
    colors = ButtonDefaults.buttonColors (
      backgroundColor = if (count > 5) Color. Green else Color.White
    )
  ) {
    Text("I've been clicked $count times")
  }
}

Tap/Click Events

Jetpack Compose support captures most click events on views, similar to the Classic Android SDK. However, some click events, like those generated from a PressInteraction, are not currently captured. You will still see where the end-user is tapping on the screen (small blue dot), but the Jetpack Compose support does not currently support surfacing every possible click event.

Selectors

Selectors need to be added to all Composables that you wish to build usage analytics for.

Adding consistent and quality automatic selectors is not currently supported. However, if you want to search for if a user tapped on a Button or other element, you need to add selector information to that Composable using any of Modifier.fsAddClass(String), Modifier.fsTag(String) , Modifier.fsId(String), or Modifier.fsAttribute(String, String). You can then use the coded values in searches, build metrics based on element usage, configure watched elements and use all the tools Fullstory provides with the selector that you configure.

Note that in order to use manually configured selectors, you need to set composeSelectorVersion to at least version 1. While we strive to always preserve backwards compatibility, we may need to change how selectors are computed or matched that might not be possible to do without some breaking changes. Those changes will be guarded by a new composeSelectorVersion which will guarantee that your app’s rules and analytics won’t change until you opt-in to that new version.

Manual selectors can be enabled by setting composeSelectorVersion to a number greater than 0 in the fullstory grade properties (where you set the org id). Setting this to a number greater than 0 will enable selectors to be shown that are manually annotated (via Modifier.fsAddClass(String) and our other API methods that are invoked on a Modifier in Jetpack Compose). More information on valid composeSelectorVersion values, as well as what is captured, can be found in the Selector Versioning section below.

Selector Versioning

composeSelectorVersion value Selector Information in Playback
0 All selectors other than androidcomposeview are omitted.
1

Only Composables manually-annotated by the Modifier helper methods are shown.

2

New Feature: Support for adding automatically generated semantic_role attributes on Composables.

Bug Fix: Composables annotated with fsTag(String) will now correctly set the tag name instead of adding a tag attribute.

3

New Feature: Automatically generated type attributes for text and input fields (e.g.- "text", "password", "number").

New Feature: Support for capturing of unmasked text on Composables. Search for and filter elements by text.

4

Breaking change: The semantic_role attribute was renamed to semantic-role. When upgrading to this selector version, make sure any selector privacy rules are also updated to reflect this change.

New Feature: Propagate test-tag and content-description attributes when declared on Composables.

5 New Feature: Support for adding automatically generated layout-id attributes on Composables.


Modifier Helper Methods

Manual annotation of Composables that will show up in selectors on playback are achieved through Fullstory-specific helper methods on androidx.compose.ui.Modifier.

Manual Selector Annotation Methods

Modifier Method Description View Method Analogue
Modifier.fsAttribute(name: String, value: String) Adds an attribute to the selector with the given name value pair. https://developer.fullstory.com/mobile/android/auto-capture/set-attribute/
Modifier.fsAddClass(cls: String) Adds the specified class to the selector https://developer.fullstory.com/mobile/android/auto-capture/add-class/
Modifier.fsId(id: String) Adds an id to the specified selector, similar to setting an Android layout XML id N/A
Modifier.fsTag(tag: String) Sets a tag attribute of the selector https://developer.fullstory.com/mobile/android/auto-capture/set-tag-name/


Privacy Rule Convenience Methods

Modifier Method Description
Modifier.fsExclude() Equivalent to invoking Modifier.fsAddClass("fs-exclude")
Modifier.fsMask() Equivalent to invoking Modifier.fsAddClass("fs-mask")
Modifier.fsUnmask() Equivalent to invoking Modifier.fsAddClass("fs-unmask")
Modifier.fsExcludeWithoutConsent() Equivalent to invoking Modifier.fsAddClass("fs-exclude-without-consent")
Modifier.fsMaskWithoutConsent() Equivalent to invoking Modifier.fsAddClass("fs-mask-without-consent")
Modifier.fsUnmaskWithConsent() Equivalent to invoking Modifier.fsAddClass("fs-unmask-with-consent")


Known Issues

  • Some list views (like LazyList) are drawn incorrectly during playback when using Jetpack Compose < 1.1.0.
  • Fully transparent views are drawn (without transparency) during playback when using Jetpack Compose < 1.1.0.
  • Some transparent elements will not draw correctly during playback.
  • We have observed occasional performance impact in some cases while scrolling.
  • Some controls (like NavigationBarItem) will not capture the icon properly and will show up as an X during replay.

Note: Transitioning from the Jetpack Compose Early Access program

For customers that previously were part of Fullstory Jetpack Compose Early Access program in a build prior to Fullstory for Mobile Apps 1.39.0, an important behavior change occurred.

Please see this article for more information.

 


Was this article helpful?

Got Questions?

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