Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Android] Requiring images with Gradle 4 fails release builds #16906

Closed
Almouro opened this issue Nov 21, 2017 · 122 comments
Closed

[Android] Requiring images with Gradle 4 fails release builds #16906

Almouro opened this issue Nov 21, 2017 · 122 comments
Labels
Impact: Regression Describes a behavior that used to work on a prior release, but stopped working recently. Issue: Author Provided Repro This issue can be reproduced in Snack or an attached project. Platform: Android Android applications. Ran Commands One of our bots successfully processed a command. Resolution: Fixed A PR that fixes this issue has been merged. Resolution: Locked This issue was locked by the bot.

Comments

@Almouro
Copy link
Contributor

Almouro commented Nov 21, 2017

Hello guys,

I ran into this issue when updating Gradle and Android Studio.

Thanks for your help!

Is this a bug report?

Yes

Have you read the Contributing Guidelines?

Yes

Environment

Environment:
OS: macOS Sierra 10.12.6
Node: 8.5.0
Yarn: 1.3.2
npm: 5.3.0
Watchman: 4.7.0
Xcode: Xcode 9.1 Build version 9B55
Android Studio: 3.0 AI-171.4408382

Packages: (wanted => installed)
react: 16.0.0 => 16.0.0
react-native: 0.50.3 => 0.50.3

Target Platform: Android (22)

Steps to Reproduce

Requiring images with latest gradle fails release builds

I created a small test project but here are the steps to reproduce it:

  1. Init a new project: react-native init Test
  2. Update to latest Gradle:
  • Open Android Studio and install recommended version
  • Build from Android Studio, it should ask you to update build tools, do so
  1. Require an image in index.js
  2. Run cd android && ./gradlew assembleRelease

Expected Behavior

The command ./gradlew assembleRelease should not fail

Actual Behavior

Running ./gradlew assembleRelease when the image is required from the JS fails with:

/Users/almouro/bam/uefa/TestGradle3/android/app/build/intermediates/res/merged/release/drawable-mdpi/image.png: error: uncompiled PNG file passed as argument. Must be compiled first into .flat file..
error: failed parsing overlays.

If the image is not required, the command works fine.

Reproducible Demo

git clone https://github.com/Almouro/react-native-with-gradle-4
yarn
cd android
./gradlew assembleRelease

Workaround

Adding android.enableAapt2=false to android/gradle.properties fixes the issue but it is only a workaround.

@Almouro Almouro changed the title Requiring images with latest gradle fails release builds [Android] Requiring images with latest gradle fails release builds Nov 21, 2017
@macs03

This comment has been minimized.

@strawferry

This comment has been minimized.

@vladp
Copy link

vladp commented Nov 24, 2017

+1 have same issue with react-native 0.50
setting android.enableAapt2=false to android/gradle.properties
helps with this issue. However, I am running into a next problem (and not sure if this due to the above setting).

  Task :app:bundleReleaseJsAndAssets
 Scanning folders for symlinks in /home/v/devel/mine/proj/mob/rn.common/node_modules (12ms)
 Scanning folders for symlinks in /home/v/devel/mine/proj/mob/rn.common/node_modules (10ms)
 Loading dependency graph, done.
 warning: the transform cache was reset.
 bundle: start
 bundle: finish
 bundle: Writing bundle output to: /home/v/tmp/u1b/app/intermediates/assets/release/index.android.bundle
 bundle: Done writing bundle output
 bundle: Copying 18 asset files
 bundle: Done copying assets
 
/home/v/tmp/u1b/app/intermediates/res/merged/release/drawable-mdpi/src_jsapp_img_material_ic_local_library_black_48dp_android_drawablexxhdpi_ic_local_library_black_48dp.png: error: Invalid filename.  Unable to add.
 

The file

/home/v/tmp/u1b/app/intermediates/res/merged/release/drawable-mdpi/src_jsapp_img_material_ic_local_library_black_48dp_android_drawablexxhdpi_ic_local_library_black_48dp.png

indeed, is not present in the merged/release directory. But I have no idea who generates that file name for what reason/etc.

@Almouro
Copy link
Contributor Author

Almouro commented Nov 27, 2017

My understanding is that the React Native bundleJS gradle task copies all the images in the android merged resources folder, but aapt now expects images there to be compiled in .flat files.

@vladp
Copy link

vladp commented Nov 28, 2017

@Almouro I sorted out the issue with
src_jsapp_img_material_ic_local_library_black_48dp_android_drawablexxhdpi_ic_local_library_black_48dp.png

it turns out that something in aapt (or somewhere in gradle) chokes on image file names that are located in deep directory structures.
The above name was created by concatenating (with '_') the directory tree where local_library_black_48dp.png was. I basically moved the file into a simpler directory structure, then updated my require ('path_to_image/..) in my index.android.js and that particular problem went away

the need to do the android.enableAapt2=false workaround is still there, unfortunately

@wmonecke
Copy link

wmonecke commented Jan 16, 2018

Same error:

Scanning 766 folders for symlinks in /Users/waltermonecke/Code_Projects/reactNative/lisdo/node_modules (15ms)
Scanning 766 folders for symlinks in /Users/waltermonecke/Code_Projects/reactNative/lisdo/node_modules (100ms)
Loading dependency graph, done.
warning: the transform cache was reset.
bundle: start
bundle: finish
bundle: Writing bundle output to: /Users/waltermonecke/Code_Projects/reactNative/lisdo/android/app/build/intermediates/assets/release/index.android.bundle
bundle: Done writing bundle output
bundle: Copying 106 asset files
bundle: Done copying assets

/Users/waltermonecke/Code_Projects/reactNative/lisdo/android/app/build/intermediates/res/merged/release/drawable-hdpi/node_modules_reactnativerouterflux_node_modules_reactnavigation_src_views_assets_backicon.png: error: uncompiled PNG file passed as argument. Must be compiled first into .flat file..
error: failed parsing overlays.

node_modules:
"react": "16.0.0-alpha.12",
"react-native": "0.48.3",

Has anyone had any success fixing this? I can't test the production app because of this.

@otoinsa

This comment has been minimized.

@dioxide

This comment has been minimized.

@praburaja

This comment has been minimized.

@wuyunqiang
Copy link

I have the same issue.
I Adding android.enableAapt2=false to android/gradle.properties
but no effect.

@SharpMobileCode
Copy link

This bug has been a pain since we've upgraded to Android 3.x and setting android.enableAapt2 = false is not a sustainable long term workaround. It's disappointing that there is no traction on this serious issue.

@nklhtv

This comment has been minimized.

@allison7
Copy link

Can't use android.enableAapt2=false since then other necessary components fail. A bad situation to find this near the end of a project.

@hugoh59

This comment has been minimized.

@xzilja
Copy link
Contributor

xzilja commented Feb 3, 2018

android.enableAapt2=false works (when there are no images in drawable)

@andreiciceu

This comment has been minimized.

@heuism

This comment has been minimized.

@PPTing

This comment has been minimized.

@sibelius

This comment has been minimized.

@Alexispap
Copy link

Alexispap commented Feb 8, 2018

  1. Delete the tmp files of the images that were created during the build process. (in tmp\YOURAPP\app\intermediates\res\merged\release\drawable....). The exact path is given by the compiler error.
  2. Search for files that have a @-suffix different from @2x or @3x in your app folder and delete them. See https://facebook.github.io/react-native/docs/images.html
  3. Sometimes the issue stems from images of a module you use. Search for the images with wrong suffix in the respective node_modules folder and delete them.
  4. DON'T USE the common workaround (which consists in disabling aapt2).

@CFKevinRef
Copy link
Contributor

CFKevinRef commented Feb 8, 2018

tl;dr - I think the bundling step in react.gradle should hand off to the Android build system much earlier in the build process

I may have killed a few birds with one stone while working out a solution for something unrelated.

I wanted to bundle the js ahead of time, then build multiple variants using that same bundle. The solution I came up with also allows you to keep AAPT2 enabled, which was a major plus.

First I set a few environment variables, REACT_NATIVE_JS_DIR and REACT_NATIVE_ASSETS_DIR.

Then I bundle with --bundle-output "$REACT_NATIVE_JS_DIR/index.android.bundle" --assets-dest "$REACT_NATIVE_ASSETS_DIR".

The build.gradle adds those to the main source set:

// not needed anymore in this setup:
// apply from: "../../node_modules/react-native/react.gradle"
android {
    ...
    sourceSets {
        // Android includes "main" in all application variants
        main {
            assets.srcDirs += System.env.REACT_NATIVE_JS_DIR
            res.srcDirs += System.env.REACT_NATIVE_ASSETS_DIR
        }
    }
}

Overall this feels a lot friendlier to the Android build system, as the resources and assets actually go through the merge${VariantName}Assets and merge${VariantName}Resources tasks. As a bonus, my universal APK was even 4% smaller.

I have a feeling that react.gradle could be modified to do something similar, like:

  • Output to "build/generated" instead of "build/intermediates"
  • Append those directories to the source sets like above
  • Make merge${VariantName}Assets and merge${VariantName}Resources depend on the bundling step
    • Currently this is reversed - it requires the merge tasks to happen first, then tries to output to those already-merged (and AAPT2-processed) intermediate directories, with a fair amount of hard-coded paths and build task dependency ordering

I'll try to find some time to put a PR together if that sounds reasonable.

@jeaye
Copy link

jeaye commented Feb 11, 2018

@CFKevinRef I've verified your approach works, as long as REACT_NATIVE_ASSETS_DIR isn't actually pointing to ./android/app/build/intermediates/res/merged/$build_type. This did it for me:

android_intermediates=$(mktemp -d)
export REACT_NATIVE_JS_DIR=$android_intermediates/assets/$build_type_lower
export REACT_NATIVE_ASSETS_DIR=$android_intermediates/res/merged/$build_type_lower

It's not a great long-term solution, though, since avoiding the default gradle support may cause issues down the road, when new behavior is added, or something is changed. For now, it does allow things to work with AAPT2. Thank you!

It'd be great to see that PR and have this ball rolling.

@samehmikhail
Copy link

samehmikhail commented Feb 12, 2018

Until this got fixed, there is another workaround similar to solution proposed by @CFKevinRef. This solution also allows you to keep using AAPT2. Workaround consists of three steps

  • change default bundling output folder to be in src/ directory instead of build folder. You can do this by changing react properties at the top of your build.gradle (app build gradle)
ext.react = [
        bundleInRelease        : true,
        resourcesDirRelease   : "src/release/res"
]
apply from: "../react.gradle" /*Check file for more information*/
apply plugin: 'com.android.application'

please note that properties names are dynamic and depends on your target names, bundleIn, resourcesDir

  • Add generated files to git ignore, to keep your native resources folder clean
    android/app/src/*/res/*/reactnative_*.png
    android/app/src/*/res/*/node_modules_*.png
  • Reverse dependency between this react gradle task (bundling) and merging assets and resources.
    This is the hardest part, you need to change this file {project_root_dir}/node_modules/react-native/react.gradle, In my case I copied this file to my project and keep updating it with each react release. The change is quite simple
    replace
currentBundleTask.dependsOn("merge${targetName}Resources")
currentBundleTask.dependsOn("merge${targetName}Assets")

with

runBefore("merge${targetName}Resources", currentBundleTask)
runBefore("merge${targetName}Assets", currentBundleTask)

@CFKevinRef
Copy link
Contributor

Please give #17967 a try. You should be able to just replace your react.gradle with that one.

Also if you have some old projects lying around based on the Android Gradle Plugin 1.x or 2.x I would appreciate a test as well!

@iqbalshirol
Copy link

I had the same issue. But did not fix with - android.enableAapt2=false, as this has issues with other drawable resources in the project.

Fixed it with adding org.gradle.configureondemand=true in build.gradle, which shall disable the 'bundleReleaseJsAndAssets' task to run, which is the best solution and works in any condition. Hope this helps.

@Peretz30

This comment has been minimized.

@hramos
Copy link
Contributor

hramos commented Sep 6, 2018

This should be fixed in 0.57 (see da6a5e0).

@marcosbenevides
Copy link

Until this got fixed, there is another workaround similar to solution proposed by @CFKevinRef. This solution also allows you to keep using AAPT2. Workaround consists of three steps

  • change default bundling output folder to be in src/ directory instead of build folder. You can do this by changing react properties at the top of your build.gradle (app build gradle)
ext.react = [
        bundleInRelease        : true,
        resourcesDirRelease   : "src/release/res"
]
apply from: "../react.gradle" /*Check file for more information*/
apply plugin: 'com.android.application'

please note that properties names are dynamic and depends on your target names, bundleIn, resourcesDir

  • Add generated files to git ignore, to keep your native resources folder clean
    android/app/src/*/res/*/reactnative_*.png
    android/app/src/*/res/*/node_modules_*.png
  • Reverse dependency between this react gradle task (bundling) and merging assets and resources.
    This is the hardest part, you need to change this file {project_root_dir}/node_modules/react-native/react.gradle, In my case I copied this file to my project and keep updating it with each react release. The change is quite simple
    replace
currentBundleTask.dependsOn("merge${targetName}Resources")
currentBundleTask.dependsOn("merge${targetName}Assets")

with

runBefore("merge${targetName}Resources", currentBundleTask)
runBefore("merge${targetName}Assets", currentBundleTask)

THIS WORKED FOR ME, THANK YOU!

@lucidtheory
Copy link

This works for me on latest RN

I did have to remove android.enableAapt2=false from android/gradle.properties first because I had added it there before as the temp fix.

Thanks RN team

@AdrianZghibarta
Copy link

Is this fix also added to 0.56.0 RN version?

@i6mi6
Copy link

i6mi6 commented Sep 24, 2018

The reason it didn't work for me was because my gradle.properties file was missing ...

@mrruby
Copy link

mrruby commented Oct 4, 2018

React Native 0.48 I found solution for my issues, updating
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10-all.zip
classpath 'com.android.tools.build:gradle:3.2.0'
and
https://stackoverflow.com/questions/44446523/unable-to-load-script-from-assets-index-android-bundle-on-windows/44476757#44476757

@kaushikwavhal
Copy link

android.enableAapt2=false initially did not work for me until i did sudo gem install cocoapods on OSX.
On ubuntu, sudo apt-get install libncurses5:i386 libstdc++6:i386 zlib1g:i386 should make it work.

@valerybodak
Copy link

@marcosbenevides

Could you please clarify what is your version of React and React Native? And maybe you will provide your full react.gradle file. Thanks in advance!

@khemrajsharma
Copy link

This should be fixed in 0.57 (see da6a5e0).

I have "react-native": "^0.57.1", this issue still occurs.

@SandroMachado
Copy link
Contributor

@khemrajsharma you need to bump to the version 0.57.3.

@MwirabuaTimothy
Copy link

@SandroMachado react-native@0.57.3 expects peer dependency react@16.6.0-alpha.8af6728 which is still buggy

@MwirabuaTimothy
Copy link

The issue seemed to disappeared after I stepped back to this and deleted my build folder and rebuilt.

    "react": "16.5.0",
    "react-native": "0.57.1"

@SandroMachado
Copy link
Contributor

I am using the 0.57.3 and didn't find any significant bug.

@valerybodak
Copy link

@rumax
Do yo use react-native-toast-native library in your project? It was a reason of the issue with uncompiled PNG for me. I have a react native 0.57.0

@claudioviola
Copy link

I had the same issue. But did not fix with - android.enableAapt2=false, as this has issues with other drawable resources in the project.

Fixed it with adding org.gradle.configureondemand=true in build.gradle, which shall disable the 'bundleReleaseJsAndAssets' task to run, which is the best solution and works in any condition. Hope this helps.

@iqbalshirol thanks for your suggestion. My project works again but what does org.gradle.configureondemand do? Doesn't configure the native libraries in node_modules? Is it necessary?

This is my list of native libraries at the moment:

"react-native-animatable": "^1.3.0",
    "react-native-config": "^0.11.5",
    "react-native-countdown-component": "^1.7.3",
    "react-native-dropdownalert": "^3.5.0",
    "react-native-firebase": "^5.0.0",
    "react-native-image-pan-zoom": "^2.1.9",
    "react-native-modal-overlay": "^1.2.3",
    "react-native-modalbox": "^1.6.0",
    "react-native-qrcode-svg": "^5.1.0",
    "react-native-splash-screen": "3.0.6",
    "react-native-svg": "^6.5.2",
    "react-native-table-component": "^1.1.8",
    "react-native-version-number": "^0.3.4",
    "react-native-version-up": "^1.0.9",
    "react-navigation": "^2.5.5",

Thank you!

gnprice added a commit to zulip/zulip-mobile that referenced this issue Oct 24, 2018
This became the default with Android Gradle Plugin version 3.0.0:
  https://developer.android.com/studio/releases/gradle-plugin#3-0-0
So turning it off returns us to the behavior before we recently
took that upgrade.

Without this line, we run into this issue when attempting to make a
release build:
  facebook/react-native#16906
That issue was closed long ago when an intended fix was merged, but
then that was reverted.  The fix went back in as da6a5e043 upstream,
which is in v0.57.0, so we'll get it when we take that upgrade;
hopefully that then fixes this for real.
@sunithakk
Copy link

android.enableAapt2=false

android.enableAapt2=false not working for me.is there any other solution?

@DeependraCSE
Copy link

android/app/build/intermediates/res/merged/debug/drawable-hdpi/node_modules_reactnavigationstack_dist_v iews_assets_backicon.png: error: uncompiled PNG file passed as argument. Must be compiled first into .flat file.. error: failed parsing overlays.

this is the issue for me
Adding android.enableAapt2=false to android/gradle.properties
is work for me

@SandroMachado
Copy link
Contributor

It is fixed in >=0.57.3.

@facebook facebook locked as resolved and limited conversation to collaborators Oct 30, 2018
@react-native-bot react-native-bot added the Resolution: Locked This issue was locked by the bot. label Aug 4, 2019
KusStar pushed a commit to KusStar/react-native that referenced this issue Nov 11, 2020
Summary:
Mirrors facebook#17967 which was imported and reverted

Original:

Better integration with the Android Gradle-based build process, especially the changes introduced by the [Android Gradle Plugin 3.x and AAPT2](https://developer.android.com/studio/build/gradle-plugin-3-0-0-migration.html).

Fixes facebook#16906, the `android.enableAapt2=false` workaround is no longer required.

Bases the task generation process on the actual application variants present in the project. The current manual process of iterating build types and product flavors could break down when more than one dimension type is present (see https://developer.android.com/studio/build/build-variants.html#flavor-dimensions).

This also exposes a very basic set of properties in the build tasks, so that other tasks can more reliably access them:

```groovy
android.applicationVariants.all { variant ->
    // This is the generated task itself:
    def reactBundleTask = variant.bundleJsAndAssets
    // These are the outputs by type:
    def resFileCollection = reactBundleTask.generatedResFolders
    def assetsFileCollection = reactBundleTask.generatedAssetsFolders
}
```

I've tested various combinations of product flavors and build types ([Build Variants](https://developer.android.com/studio/build/build-variants.html)) to make sure this is consistent. This is a port of what we're currently deploying to our CI process.

[ ANDROID ] [ BUGFIX ] [ react.gradle ] - Support Android Gradle Plugin 3.x and AAPT2
[ ANDROID ] [ FEATURE ] [ react.gradle ] - Expose the bundling task and its outputs via ext properties

Pull Request resolved: facebook#20526

Differential Revision: D9164762

Pulled By: hramos

fbshipit-source-id: 544798a912df11c7d93070ddad5a535191cc3284
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Impact: Regression Describes a behavior that used to work on a prior release, but stopped working recently. Issue: Author Provided Repro This issue can be reproduced in Snack or an attached project. Platform: Android Android applications. Ran Commands One of our bots successfully processed a command. Resolution: Fixed A PR that fixes this issue has been merged. Resolution: Locked This issue was locked by the bot.
Projects
None yet
Development

Successfully merging a pull request may close this issue.