This is a sister article of Make Fastlane Snapshot Work with React Native. While
fastlane snapshot works with iOS app,
fastlane screengrab is its Android version that programmatically takes Android app screenshots using the UI Testing functionality supported by Android Studio. Although the screenshot requirement on Android Play Store is less stringent than that on Apple App Store (no hard requirement on dimension, can skip tablets, etc.), the journey of getting
fastlane screengrab to work with React Native is still quite a mouthful. Given that most articles on this topic that we can find are dated, we would like to share our fresh experience working with
Be Careful with The Documentation
The documentation on
screengrab is more up to date than the one on Android Screenshot, because the former specifies that the latest version of
screengrab is 2.0.0. The latter, however, provides a gem link to
screengrab, which says its current version is 1.0.0. Configuring
screengrab as 1.0.0 (more on this later) in the gradle dependency does not work.
Preparation for UI Testing
The documentation is not particularly detailed regarding how to modify the Android native code to prepare for UI Testing with expresso, AndroidJUnitRunner, and UI Automator. We have found that the following configurations are necessary.
minSdkVersion must be larger or equal to 18. This is to satisfy UI Automator’s requirement.
dependencies as follows
... // fastlane screengrab
androidTestImplementation "tools.fastlane:screengrab:2.0.0" // Espresso dependencies
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' // Hamcrest library
// Core library
// AndroidJUnitRunner and JUnit Rules
This configuration mainly comes from Android documentation on building instrumented unit test. However, notice that we do not include the dependency for UI Automator. This is because UI Automator is already provided by
screengrab. Including it again will lead to class duplication error. Also notice that we put version 2.0.0 for
defaultConfig as follows
Paste the following config in the manifest file.
<!-- Allows unlocking your device and activating its screen so UI tests can succeed -->
<uses-permission android:name="android.permission.WAKE_LOCK"/><!-- Allows for storing and retrieving screenshots -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><!-- Allows changing locales -->
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" /><!-- Indicates the use of the clean status bar feature -->
<!-- Allows for changing the status bar -->
Create UI Testing file
The UI Testing file should be created in this path
We have thus named our test file
ScreenshotTest.java. Below is a template to get one started on obtaining screenshots.
Notice that we use
onView(allOf(withContentDescription(id))) to capture a component which has
id as its
accessibilityLabel. We stumbled upon this solution in Gergő Nagygyörgy’s article. This is truly a godsend, as the method specified in the documentation simply does not work for us.
Add accessibilityLabel to Dummy Buttons
The method of programmatically capturing screenshot is the same as described in the previous article. In iOS UI Testing,
TouchableHighlight is recognizable via
testID, but in Android UI Testing, only
accessibilityLabel is recognized. This means, for example, in order to make the template shown above work, we must specify
accessibilityLabel="some_api_query_button" in the dummy button.
Setup Fastfile to run screengrab
Follow the instructions in the documentation to create a screenshot lane. Notice that we must build two APK for
screengrab, one is debug and the other AndroidTest. If any React Native code is modified, both builds must be rebuilt to reflect the change. If
ScreenshotTest.java is the only file modified, then only AndroidTest build needs to be rebuilt.
Below is our screenshot lane. We also use
Screengrabfile to configure
screengrab. For details, refer to the documentation.
desc 'Produce screenshots via screengrab'
lane :screenshots do
gradle(task: 'clean', project_dir: 'android/')
Keep Metro Bundler and Device Emulator Running
screengrab requires that both the metro bundler (i.e.
npx react-native start) and a desired Android device emulator to be running when screenshots are taken. Surprisingly, these two are not automatically spun up by
screengrab. In other words, we need to manually start metro bundler and device emulator before runninng
screengrab, or write scripts to initiate them in
Fastfile. One benefit of having the device emulator up is that we can observe in real time how the actions specified in
ScreenshotTest.java are executed.
We have presented our experience working with
fastlane screengrab on a React Native app. Overall, it is less annoying as
fastlane snapshot, but there are still quite a few hurdles to jump through. The parts we think the existing documentation is unclear are:
- The native code set up for UI Testing
- The method to capture react native component during UI Testing.
We hope this write up will help those who feel a bit overwhelmed when reading the
fastlane screengrab documentation for the first time (in our case, we were so overwhelmed that we had to stare at a blank wall to re-contemplate our lives).