'GIFs not animating in the Android version of my React Native app

I am struggling to get my GIFs to animate on the Android version of my RN application. The iOS version is animating the looping GIFs as expected but I only see a stuck "single frame" image from the GIF on the Android device.

According to the debugging and RN-documentation it's required to add a few lines of implementation to the dependencies within the /android/app/build.gradle, but even after cleaning the gradle (running ./gradlew clean in the /android folder) and deleting the cache of the RN app (running react-native start --reset-cache in the project root folder), I do not see any difference in my application.

I have googled and tried a lot. Based on my debugging adventure, I have tried and double-checked these suggestions, that seems to work for others but it doesn't seem to work for me...

  • I have tried several versions of the fresco-libraries that seems to be required and I have also tried placing the lines in both the bottom as well as the top of the dependencies.
  • Some answers also suggest to add one or more lines of code to the android/app/proguard-rules.pro but this doesn't change anything either.
  • I use GIFs in different ways of my application but it always has width and height included to the style property on the <Image />.
  • I have tried with GIF-uris from different CDNs and domains.
  • Reinstalled the app on my test devices.
  • Closed and reopened my code editors.

I'm using the following versions:

  • Java: 11.0.12
  • React Native: 0.65
  • Android SDK: 30.0.2
  • npm: 6.14.4

This is my full /android/app/build.gradle:

apply plugin: "com.android.application"

import com.android.build.OutputFile


project.ext.react = [
    enableHermes: false,  // clean and rebuild if changing
]

apply from: "../../node_modules/react-native/react.gradle"


def enableSeparateBuildPerCPUArchitecture = false
def enableProguardInReleaseBuilds = false
def jscFlavor = 'org.webkit:android-jsc:+'
def enableHermes = project.ext.react.get("enableHermes", false);

android {
    ndkVersion rootProject.ext.ndkVersion

    compileSdkVersion rootProject.ext.compileSdkVersion

    defaultConfig {
        applicationId "com.example.app"
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode 1
        versionName "1.0"
    }
    splits {
        abi {
            reset()
            enable enableSeparateBuildPerCPUArchitecture
            universalApk false  // If true, also generate a universal APK
            include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
        }
    }
    signingConfigs {
        debug {
            storeFile file('debug.keystore')
            storePassword 'android'
            keyAlias 'androiddebugkey'
            keyPassword 'android'
        }
    }
    buildTypes {
        debug {
            signingConfig signingConfigs.debug
        }
        release {
            // Caution! In production, you need to generate your own keystore file.
            // see https://reactnative.dev/docs/signed-apk-android.
            signingConfig signingConfigs.debug
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        }
    }

    // applicationVariants are e.g. debug, release
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            // For each separate APK per architecture, set a unique version code as described here:
            // https://developer.android.com/studio/build/configure-apk-splits.html
            // Example: versionCode 1 will generate 1001 for armeabi-v7a, 1002 for x86, etc.
            def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
            def abi = output.getFilter(OutputFile.ABI)
            if (abi != null) {  // null for the universal-debug, universal-release variants
                output.versionCodeOverride =
                        defaultConfig.versionCode * 1000 + versionCodes.get(abi)
            }

        }
    }
}

dependencies {

    implementation fileTree(dir: "libs", include: ["*.jar"])
    //noinspection GradleDynamicVersion
    implementation "com.facebook.react:react-native:+"  // From node_modules

    implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"

    debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
      exclude group:'com.facebook.fbjni'
    }

    debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
        exclude group:'com.facebook.flipper'
        exclude group:'com.squareup.okhttp3', module:'okhttp'
    }

    debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
        exclude group:'com.facebook.flipper'
    }

    if (enableHermes) {
        def hermesPath = "../../node_modules/hermes-engine/android/";
        debugImplementation files(hermesPath + "hermes-debug.aar")
        releaseImplementation files(hermesPath + "hermes-release.aar")
    } else {
        implementation jscFlavor
    }


    implementation project(':react-native-notifications')
    implementation 'com.google.firebase:firebase-core:16.0.0'
    implementation 'com.google.android.gms:play-services-ads:19.8.0'
    implementation "androidx.appcompat:appcompat:1.0.0"

    implementation 'com.facebook.fresco:fresco:2.4.0'
    implementation 'com.facebook.fresco:animated-gif:2.4.0'
    implementation 'com.facebook.fresco:webpsupport:2.4.0'
}

// Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) {
    from configurations.compile
    into 'libs'
}

apply plugin: 'com.google.gms.google-services'

apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)

Let me know if I've missed something obvious. I am definitely more experienced in iOS-development, so it is very possible that I missed something :-)



Solution 1:[1]

A easier fix would be using FastImage library which have Gif support build in with added benefits of caching and more

Solution 2:[2]

I had the same issue using react-native 0.66.3, and updating com.facebook.fresco:animated-gif to 2.6.0 in app/build.gradle worked for me

Solution 3:[3]

I myself had problems with GIF's on android and ended up moving over to animated webp's which google seems to embrace and even has their own conversion tools for. They've had android support for it for many years and seems to work much more consistantly. Might even work by changing the extension to webp instead of PNG?

https://frescolib.org/docs/webp-support.html

Solution 4:[4]

How do I display an animated gif in React Native?

add android/app/build.gradle

    // For animated GIF support
    compile 'com.facebook.fresco:animated-gif:1.+'

Solution 5:[5]

GIF and WebP support on Android

When building your own native code, GIF and WebP are not supported by default on Android.

You will need to add some optional modules in android/app/build.gradle, depending on the needs of your app.

dependencies {
  // If your app supports Android versions before Ice Cream Sandwich (API level 14)
  implementation 'com.facebook.fresco:animated-base-support:1.3.0'

  // For animated GIF support
  implementation 'com.facebook.fresco:animated-gif:2.5.0'

  // For WebP support, including animated WebP
  implementation 'com.facebook.fresco:animated-webp:2.5.0'
  implementation 'com.facebook.fresco:webpsupport:2.5.0'

  // For WebP support, without animations
  implementation 'com.facebook.fresco:webpsupport:2.5.0'
}

You can follow the official documentation Link

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Muhammed Yasir MT
Solution 2 Akme
Solution 3 Mike
Solution 4 iyoda
Solution 5 MD. IBRAHIM KHALIL TANIM