Unresolved reference ‘AnchoredDraggableDefaults when generating Signed APK

Summary

The issue of Unresolved reference ‘AnchoredDraggableDefaults’ occurs when generating a signed APK, despite the app building and running successfully in debug mode from Android Studio. This problem arises from the use of experimental APIs in Jetpack Compose, specifically the AnchoredDraggable component.

Root Cause

The root cause of this issue is the use of experimental APIs without properly configuring the project to include these APIs in the release build. The AnchoredDraggable component and its related functions, such as AnchoredDraggableDefaults, are part of the ExperimentalFoundationApi. When building a signed APK, the compiler may not include these experimental APIs by default, leading to the Unresolved reference error.

Why This Happens in Real Systems

This issue occurs in real systems due to the following reasons:

  • Experimental APIs are not enabled by default for release builds.
  • The Android build process may optimize or exclude experimental code in release builds to reduce the APK size and improve performance.
  • ProGuard or R8 obfuscation and optimization tools may remove or rename experimental classes and functions, causing unresolved reference errors.

Real-World Impact

The impact of this issue includes:

  • Failed builds: The inability to generate a signed APK due to unresolved references.
  • Delayed releases: The need to troubleshoot and resolve the issue before releasing the app.
  • Increased development time: The time spent on debugging and configuring the project to support experimental APIs.

Example or Code

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun someFunction(){
    val swipeState = remember { 
        AnchoredDraggableState( 
            initialValue = false, 
            anchors = DraggableAnchors { 
                false at 0f 
                true at endPx 
            } 
        ) 
    }
    //...
    val flingBehavior = AnchoredDraggableDefaults.flingBehavior(
        state = swipeState, 
        positionalThreshold = { distance -> distance * 0.5f }, 
        animationSpec = spring( 
            dampingRatio = Spring.DampingRatioLowBouncy, 
            stiffness = Spring.StiffnessLow 
        ) 
    )
}

How Senior Engineers Fix It

Senior engineers fix this issue by:

  • Enabling experimental APIs in the project’s build configuration.
  • Configuring ProGuard or R8 to keep the experimental classes and functions.
  • Using stable APIs instead of experimental ones, if possible.
  • Verifying the build configuration to ensure that experimental APIs are included in the release build.

Why Juniors Miss It

Junior engineers may miss this issue due to:

  • Lack of experience with experimental APIs and their limitations.
  • Insufficient knowledge of the Android build process and optimization tools.
  • Inadequate testing of the app in different build configurations.
  • Failure to read and understand the documentation and warnings related to experimental APIs.