What is ReDroid?
ReDroid is a lightweight alternative to the standard Android emulator that runs as a Docker container. ReDroid provides a full Android system in a container, significantly reducing startup time and resource consumption compared to traditional emulators.
ReDroid uses the host system's Linux kernel and is based on the anbox module project, enabling Android to run without CPU virtualization. This makes it an ideal solution for automated Android app testing in CI/CD environments where speed and efficiency are critical.
Comparison with Android Studio Emulator:
ReDroid is perfect for automated UI testing in CI/CD, especially when speed and resource efficiency are important. The standard Android Studio emulator is better suited for local development, debugging, and testing requiring full device emulation.
Manual Testing
Start the ReDroid container (Docker) and wait about a minute for it to load:
docker run -d --name redroid --privileged -p 5555:5555 redroid/redroid:15.0.0_64only-latest sleep 30 Connect to the running container via ADB:
adb connect localhost:5555 adb devices Install both APK files on ReDroid:
adb -s localhost:5555 install ./app/build/outputs/apk/debug/app-debug.apk adb -s localhost:5555 install ./app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk Run your Espresso/UI tests with ADB:
adb -s localhost:5555 shell am instrument -w your.package.name.test/androidx.test.runner.AndroidJUnitRunner Export logs after testing:
adb -s localhost:5555 logcat -d > android-log.txt After completing the tests, remove the container:
docker stop redroid && docker rm redroid Preparing an Android Project for UI Testing
Step 1: Configuring Dependencies in app/build.gradle
gradle:
android { defaultConfig { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } } dependencies { // Core components for UI testing androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' androidTestImplementation 'androidx.test:runner:1.5.2' androidTestImplementation 'androidx.test:rules:1.5.0' // Additional Espresso libraries for advanced testing androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.5.1' androidTestImplementation 'androidx.test.espresso:espresso-intents:3.5.1' // JUnit for test environment integration androidTestImplementation 'androidx.test.ext:junit:1.1.5' } Step 2: Creating an Example UI Test with Espresso
Create the file app/src/androidTest/java/com/example/app/MainActivityTest.java:
java:
package com.example.app; import androidx.test.espresso.matcher.ViewMatchers; import androidx.test.ext.junit.rules.ActivityScenarioRule; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.LargeTest; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.click; import static androidx.test.espresso.assertion.ViewAssertions.matches; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; import static androidx.test.espresso.matcher.ViewMatchers.withId; import static androidx.test.espresso.matcher.ViewMatchers.withText; @RunWith(AndroidJUnit4.class) @LargeTest public class MainActivityTest { @Rule public ActivityScenarioRule<MainActivity> activityRule = new ActivityScenarioRule<>(MainActivity.class); @Test public void welcomeTextIsDisplayed() { // Check that the welcome text field is displayed onView(withId(R.id.welcome_text)) .check(matches(isDisplayed())) .check(matches(withText("Hello World!"))); } @Test public void buttonClickChangesText() { // Click the button onView(withId(R.id.action_button)) .perform(click()); // Check that the text has changed onView(withId(R.id.welcome_text)) .check(matches(withText("Button Clicked!"))); } } Configuring Jenkins for UI Test Automation with ReDroid
Step 1: Installing Required Jenkins Plugins
In the Jenkins interface, go to "Configure Jenkins" > "Manage Plugins" and install:
Docker Pipeline
Gradle Plugin
HTML Publisher Plugin
JUnit Plugin
Allure Jenkins Plugin (optional for enhanced reporting)
Step 2: Creating a Jenkinsfile for the Pipeline
Create a Jenkinsfile in the project root:
groovy:
pipeline { agent any environment { // Environment variables ANDROID_HOME = '/opt/android-sdk' REDROID_IMAGE = 'redroid/redroid:15.0.0_64only-latest' REDROID_CONTAINER = 'android-ui-test-container' ADB_PORT = '5555' TEST_RESULTS_DIR = 'app/build/outputs/androidTest-results' TEST_REPORT_DIR = 'app/build/reports/androidTests' } stages { stage('Checkout') { steps { checkout scm } } stage('Build APKs') { steps { sh './gradlew clean assembleDebug assembleDebugAndroidTest' } } stage('Start ReDroid Container') { steps { script { // Stop and remove the container if it exists sh "docker stop ${REDROID_CONTAINER} || true" sh "docker rm ${REDROID_CONTAINER} || true" // Run ReDroid in Docker sh """ docker run -d --name ${REDROID_CONTAINER} \ --privileged \ -p ${ADB_PORT}:${ADB_PORT} \ -e REDROID_PROP_ro.debuggable=1 \ -e REDROID_PROP_service.adb.tcp.port=${ADB_PORT} \ ${REDROID_IMAGE} """ // Wait for ReDroid to start sh "sleep 30" } } } stage('Connect to ReDroid and Install APKs') { steps { script { // Connect to the device via ADB sh "adb connect localhost:${ADB_PORT}" sh "adb devices" // Wait for the system to fully load sh "adb wait-for-device" // Install the app APK and tests sh "adb -s localhost:${ADB_PORT} install -r app/build/outputs/apk/debug/app-debug.apk" sh "adb -s localhost:${ADB_PORT} install -r app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk" } } } stage('Run UI Tests') { steps { script { // Create directories for results sh "mkdir -p ${TEST_RESULTS_DIR}" // Get the app package name def packageName = sh( script: "aapt dump badging app/build/outputs/apk/debug/app-debug.apk | grep package | awk '{print \$2}' | sed s/name=//g | sed s/\\'//g", returnStdout: true ).trim() // Run UI tests sh """ adb -s localhost:${ADB_PORT} shell am instrument -w \ -e debug false \ -e junit.output.format=xml \ -e additionalTestOutputDir=/sdcard/test-results \ ${packageName}.test/androidx.test.runner.AndroidJUnitRunner """ // Copy results from the device sh "adb -s localhost:${ADB_PORT} pull /sdcard/test-results ${TEST_RESULTS_DIR}" // Collect logs sh "adb -s localhost:${ADB_PORT} logcat -d > ${TEST_RESULTS_DIR}/device-log.txt" // Take a screenshot for diagnostics (optional) sh "adb -s localhost:${ADB_PORT} shell screencap -p /sdcard/screen.png" sh "adb -s localhost:${ADB_PORT} pull /sdcard/screen.png ${TEST_RESULTS_DIR}/" } } } } post { always { // Publish JUnit results junit "${TEST_RESULTS_DIR}/**/*.xml" // Publish test reports publishHTML([ allowMissing: true, alwaysLinkToLastBuild: true, keepAll: true, reportDir: "${TEST_REPORT_DIR}/connected", reportName: 'Espresso Test Report', reportFiles: 'index.html' ]) // Stop and remove the container script { sh "docker stop ${REDROID_CONTAINER} || true" sh "docker rm ${REDROID_CONTAINER} || true" } // Clean up ADB sh "adb disconnect localhost:${ADB_PORT} || true" // Archive artifacts archiveArtifacts artifacts: "${TEST_RESULTS_DIR}/**/*", allowEmptyArchive: true } } } Scrcpy
Scrcpy is a lightweight, free, open-source utility for displaying and controlling Android device screens on a computer. It works over USB (ADB) or Wi-Fi without requiring any mobile apps on the device.
Usage Examples:
Connect and start (device connected via USB):
scrcpy Connect via Wi-Fi (knowing the device's IP address):
adb connect 192.168.1.5:5555 scrcpy -s 192.168.1.5:5555 Change video resolution:
scrcpy -m 1024 Record device video:
scrcpy --record file.mp4 Control the device without displaying the screen (keyboard and mouse input only):
scrcpy -N If you need visual monitoring of test execution, you can integrate Scrcpy into the pipeline:
stage('Visual Debug with Scrcpy') { when { expression { return params.ENABLE_VISUAL_DEBUG } } steps { script { // Install Scrcpy if not already installed sh ''' if ! command -v scrcpy &> /dev/null; then apt-get update && apt-get install -y scrcpy fi ''' // Start Scrcpy to record test execution sh "mkdir -p ${TEST_RESULTS_DIR}/recordings" for (int i = 0; i < DEVICE_COUNT; i++) { def adbPort = BASE_ADB_PORT + i sh """ nohup scrcpy --no-display --record=${TEST_RESULTS_DIR}/recordings/device-${i}-recording.mp4 \ --serial=localhost:${adbPort} & """ } // Limit recording duration sh "sleep 60" // Record the first minute of testing sh "pkill scrcpy || true" } } Kubernetes
Why Use ReDroid in Kubernetes
ReDroid in Kubernetes simplifies Android app testing. Here are the key benefits:
Parallel Tests — Run multiple virtual Android devices simultaneously, saving testing time.
Lower Resource Costs — ReDroid is lightweight, and Kubernetes efficiently distributes the load across servers.
Automatic Management — The system automatically starts, restarts, and stops Android containers without manual intervention.
Easy CI/CD Integration — Seamlessly integrates with existing Jenkins or GitLab CI pipelines.
Test Isolation — Each test environment operates independently without interfering with others.
Centralized Management — Everything is controlled through a single interface.
Budget Savings — Virtual devices replace expensive physical phones.
Consistent Conditions — All tests run in the same environment, improving result reliability.
Hardware Acceleration Access — Can be configured to use GPU for better performance.
This solution is ideal for teams needing to regularly test Android apps in different configurations quickly and predictably.
apiVersion: apps/v1 kind: StatefulSet metadata: name: redroid-farm namespace: android-testing spec: serviceName: "redroid" replicas: 3 # Number of parallel device instances selector: matchLabels: app: redroid-device template: metadata: labels: app: redroid-device spec: securityContext: runAsUser: 0 # Run as root containers: - name: redroid image: redroid/redroid:15.0.0_64only-latest securityContext: privileged: true # Required for redroid ports: - containerPort: 5555 name: adb env: - name: REDROID_PROP_ro.debuggable value: "1" - name: REDROID_PROP_service.adb.tcp.port value: "5555" - name: ANDROID_ARCH value: "x86_64" resources: requests: cpu: 2 memory: 3Gi limits: cpu: 4 memory: 6Gi volumeMounts: - name: dri mountPath: /dev/dri - name: kvm mountPath: /dev/kvm lifecycle: preStop: exec: command: ["/system/bin/reboot", "-p"] volumes: - name: dri hostPath: path: /dev/dri - name: kvm hostPath: path: /dev/kvm nodeSelector: hardware-acceleration: "true" # Select nodes with GPU/hardware acceleration Wireshark and ReDroid: Capturing and Analyzing Android App Network Traffic
Wireshark combined with ReDroid provides powerful tools for testing and debugging Android app network interactions. This combination is particularly useful for analyzing API requests, checking connection security, and debugging network issues.
Key Features:
Real Traffic Monitoring — Wireshark lets you see all network packets exchanged between the Android app in ReDroid and external services.
Easy Setup — Since ReDroid runs as a Docker container, its network traffic is easily captured through Docker networking without additional tools on the device itself.
Secure Traffic Analysis — With proper setup, you can even inspect HTTPS traffic (using tools like mitmproxy with ReDroid).
Performance Issue Detection — Easily identify slow requests and app performance delays from network data.
Automated API Testing — Record and replay network interaction scenarios for testing.
Network Setup for Testing:
Run ReDroid with special network parameters:
docker run --name redroid-test --network host redroid/redroid:11.0.0-latest Configure traffic capture in Wireshark, filtering for the specific ReDroid container traffic:
ip.addr == [container IP address] For HTTPS traffic, configure a proxy in ReDroid via ADB:
adb connect localhost:5555 adb shell settings put global http_proxy "localhost:8080" Start mitmproxy for HTTPS decryption:
mitmproxy --listen-port 8080 This solution helps developers and testers better understand how their Android apps interact with the network, identify security issues, and optimize network interactions without needing physical devices or complex emulator setups.
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.