Skip to content Skip to sidebar Skip to footer

Take Screenshot Of A Composable Fun Programmatically In Jetpack Compose

I would like to capture the UI emitted by Jetpack compose as a Bitmap. In XML this was done like this: Basically takes a view as an input parameter and returns it as a Bitmap. //ta

Solution 1:

Taking screenshots from a composable is possible in tests. For taking screenshots in production code see this question and this issue.

First, make sure you have the following dependency in your build script (along with other required Compose dependencies):

debugImplementation("androidx.compose.ui:ui-test-manifest:<version>")

Here is a complete example for saving, reading, and comparing screenshots: (Please refer to this post for setting up write permissions and so on for the tests)

classScreenshotTest{

    @get:Ruleval composeTestRule = createComposeRule()

    @TestfuntakeAndSaveScreenshot() {
        composeTestRule.setContent { MyComposableFunction() }
        val node = composeTestRule.onRoot()
        val screenshot = node.captureToImage().asAndroidBitmap()
        saveScreenshot("screenshot.png", screenshot)
    }

    @TestfunreadAndCompareScreenshots() {
        composeTestRule.setContent { MyComposableFunction() }
        val node = composeTestRule.onRoot()
        val screenshot = node.captureToImage().asAndroidBitmap()

        val context = InstrumentationRegistry.getInstrumentation().targetContext
        val path = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
        val file = File(path, "screenshot.png")
        val saved = readScreenshot(file)

        println("Are screenshots the same: ${screenshot.sameAs(saved)}")
    }

    privatefunreadScreenshot(file: File) = BitmapFactory.decodeFile(file.path)

    privatefunsaveScreenshot(filename: String, screenshot: Bitmap) {
        val context = InstrumentationRegistry.getInstrumentation().targetContext
        // Saves in /Android/data/your.package.name.test/files/Pictures on external storageval path = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
        val file = File(path, filename)
        file.outputStream().use { stream ->
            screenshot.compress(Bitmap.CompressFormat.PNG, 100, stream)
        }
    }
}

Thanks to Google Codelabs for this.

Solution 2:

I would look at how JP-Compose testing does this.

A good starting point could be the android-compose-codelab, see:

/**
 * Simple on-device screenshot comparator that uses golden images present in
 * `androidTest/assets`. It's used to showcase the [AnimationClockTestRule] used in
 * [AnimatingCircleTests].
 *
 * Minimum SDK is O. Densities between devices must match.
 *
 * Screenshots are saved on device in `/data/data/{package}/files`.
 */@RequiresApi(Build.VERSION_CODES.O)funassertScreenshotMatchesGolden(
    goldenName: String,
    node: SemanticsNodeInteraction
) {
    val bitmap = node.captureToImage().asAndroidBitmap()
}

from ScreenshotComparator.kt. You can find captureToImage() here in the AndroidHelpers.kt.

Also you can find here the ImageBitmap.kt, where asAndroidBitmap() only makes sure that, the underlying "common" version of the ImageBitmap is actually an android.graphics.Bitmap on Android (this is to make the code more platform agnostic, so that it can be run on the JVM/desktop as well)

Post a Comment for "Take Screenshot Of A Composable Fun Programmatically In Jetpack Compose"