screenshot-tests-for-android: API 17: java.lang.RuntimeException: Failed to create the directory for screenshots. Is your sdcard directory read-only?

Executing the screenshots with connectedTest fails on an emulator with SDK 17 and succeeds at SDK 21.

Repro steps:

Create an emulator with SDK 17

echo no | avdmanager create avd --force -n test -k "system-images;android-17;default;armeabi-v7a"
mksdcard -l e 512M test-sd.img # Needed for Facebooks screenshot testing.
$ANDROID_HOME/emulator/emulator -avd test -sdcard test-sd.img -no-audio -no-window &

execute connectedCheck task and it’ll fail.

When using this setup it works without any problems:

echo no | avdmanager create avd --force -n test -k "system-images;android-21;default;armeabi-v7a"
mksdcard -l e 512M test-sd.img # Needed for Facebooks screenshot testing.
$ANDROID_HOME/emulator/emulator -avd test -sdcard test-sd.img -no-audio -no-window &

About this issue

  • Original URL
  • State: open
  • Created 6 years ago
  • Comments: 23 (12 by maintainers)

Most upvoted comments

This problem happens on Android 10 (Q), too, due to the introduction of scoped external storage. Adding android:requestLegacyExternalStorage="true" to the <application> in the AndroidManifest.xml helps as a temporary workaround.

Hi, @xiphirx this issue seems to be related to the relation between the APK generated with your test code and the APK generated with your production code. The first time you install both APKs while running the instrumentation tests from Android Studio or the command line an ID is assigned to both APKs. However, if for some reason this id is not the same for both APKs, the testing APK will not be able to access the production APK resources. This is Id can be configured in the application node declaration inside any AndroidManifest with this label: android:sharedUserId. The Andorid docs specify this about this param:

The name of a Linux user ID that will be shared with other apps. By default, Android assigns each app its own unique user ID. However, if this attribute is set to the same value for two or more apps, they will all share the same ID — provided that their certificate sets are identical. Apps with the same user ID can access each other’s data and, if desired, run in the same process.

I don’t know why the error seems to be related to the directory creation. The folder where the screenshots are being recorded is in the SD card and the permission is granted. Assigning different IDs seems to the testing APK and the production APK seems to be related but I don’t fully understand why because I’ve got this library working in projects with the default sharedUserId configuration.

I found the solution because a shot library user reported me this error and we created a sample project where (I don’t understand why) Android generates different id’s for the testing and production APKs.

To fix this you can configure your testing AndoridManifest with the same id the production APK uses. You can use a special flavor or build type AndroidManiefst if you don’t want to add this param to your production manifest

This could be the testing manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.snapshottesting.test"
    android:sharedUserId="com.example.snapshottesting.uid">
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
</manifest>

and this the production manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.snapshottesting"
    android:sharedUserId="com.example.snapshottesting.uid">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

I’m uploading here two Android projects where you can see the error. The first one will fail when running the tests and the second one, with the same code but adding the userSharedId config will work. You can run the tests by executing ./gradlew executeScreenshotTests -Precord.

SnapshotTesting failing.zip SnapshotTesting working.zip

I hope it helps 😃

Can we re-open this to indicate it’s still a problem? I’m having the same issue and suggested workaround doesn’t work