microsoft / react-native-code-push

React Native module for CodePush
http://appcenter.ms
Other
8.98k stars 1.47k forks source link

Unable to get the hash of the binary's bundled resources in Release build of android #838

Closed adb-shell closed 7 years ago

adb-shell commented 7 years ago

Description

Whenever i make a release build and run code-push debug android to debug it says

Unable to get the hash of the binary's bundled resources "codepush.gradle" may have not been added to the build definition.

Reproduction

my build.gradle is `apply from: "../node_modules/react-native/react.gradle" apply from: "../node_modules/react-native-code-push/android/codepush.gradle"

signingConfigs { release { storeFile file("../myreleasekey") storePassword "" keyAlias "alias" keyPassword "" } }` debug{ //similar debug configs. } release { minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt'), file('proguard-project.txt') signingConfig signingConfigs.release }

compile project(':react-native-code-push') ` STEPS TO RE-PRODUCE: 1.i will do offline bundling for the first time that is using the below command react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output ...

2.since i have signing config in gradle i will run ./gradlew assembleRelease to create a release build

3.to transfer it to my phone i use adb command.

Additional Information

This error occured while testing it in the physical device.

sergey-akhalkov commented 7 years ago

Hi @NULLPointerGuy, thanks for reaching us. Could you please try to remove 1st step from you repro? Due to ./gradlew assembleRelease command already contains logic that will generate and inject offline bundle into you apk. Let me know if any changes.

adb-shell commented 7 years ago

Hi @sergey-akhalkov Found the issue had not added proguard-rules for react-native, hence closing it !!

sergey-akhalkov commented 7 years ago

@NULLPointerGuy got it, thanks for the response!

smk524198002 commented 7 years ago

hi ~ i have the same problem. Can you tell me how to solve it. I am new . Thanks.

sergey-akhalkov commented 7 years ago

Hi @smk524198002, thanks for reaching us, please verify if your project is configured correctly using this manual. Especially pay attention on this line: apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"

Please let me know if any updates.

joshuapinter commented 7 years ago

I find that if I run gradlew assembleRelease I don't get this error message because it properly runs the codepush.gradle script. However, if I run Generate Signed APK... from the Build menu in Android Studio, I get this message and I find that it doesn't run the codepush.gradle commands.

Any idea why Generate Signed APK would be doing something different than gradlew assembleRelease?

sergey-akhalkov commented 7 years ago

Hi @joshuapinter, as I can remember - I've faced with differences between apks produced by gradlew assembleRelease command and by Android Studio a long time ago. I don't know why (please let me know if you have any ideas), but the release apk generated by Android Studio does not have build-in js bundle for React Native apps, that is the reason why I'm usually using gradlew assembleRelease command.

So I have the following workflow:

  1. execute gradlew assembleRelease
  2. Generate Signed APK via Android Studio
  3. Verify if everything works well
joshuapinter commented 7 years ago

Thanks for the reply @sergey-akhalkov. Yes, that's the process we have to use as well. I assumed Generate Signed APK would run gradlew assembleRelease and then sign the APKs that get produced but I guess not. Thanks.

zkrige commented 6 years ago

Please add this to documentation. It makes no sense that this isnt actually IN the docs

joshuapinter commented 6 years ago

Just as a follow-up, we actually are signing our APK with just gradlew assembleRelease now too, so there's no need to use Generate Signed APK in Android Studio.

You can Google how to do this but here's what we're using in our build.gradle:

// Load keystore from keystore.properties in the project root directory. Without this the APKs cannot be signed.
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file("keystore.properties")

if ( keystorePropertiesFile.exists() ) {
    keystoreProperties.load( new FileInputStream(keystorePropertiesFile) )
} else {
    println "Cannot Sign APKs: keystore.properties file is missing so not signing."
}

if ( keystoreProperties.getProperty("RELEASE_STORE_FILE") ) {
    signingConfigs {
        release {
            storeFile     file( keystoreProperties.getProperty("RELEASE_STORE_FILE") )
            storePassword keystoreProperties.getProperty("RELEASE_STORE_PASSWORD")
            keyAlias      keystoreProperties.getProperty("RELEASE_KEY_ALIAS")
            keyPassword   keystoreProperties.getProperty("RELEASE_KEY_PASSWORD")
        }
    }
}

And then in your root directory, you need a file called keystore.properties with the following structure:

RELEASE_STORE_FILE=
RELEASE_STORE_PASSWORD=
RELEASE_KEY_ALIAS=
RELEASE_KEY_PASSWORD=

Works like a treat!

JasonFehr commented 6 years ago

Thanks, I think you guys just saved the day for us!

I have no idea why generating the signed APK in Android Studio gave that "Unable to get the hash of the binary's bundled resources "codepush.gradle"" error, but using gradlew assembleRelease solved everything for some reason.

Fr33maan commented 5 years ago

I'm signing the apk with gradle but I face the same issue

kostiantyn-solianyk commented 3 years ago

same issue even in 2021

charleston10 commented 3 years ago

also.. same issue even in 2021 :`(

alexnekrashevich commented 2 years ago

Hello dear colleagues.

This simple workaround may help you, if you get this error while using Gradle build.

Why does this issue occur?

If you import codepush.gradle as suggested, it shall process the CodePushHash generation successfully. At the same time, we use AssetManager to get access to this file, usually situated in assets subfolder somewhere. On debugging, we have noticed that it does not see CodePushHash, thus causing the issue.

You can check it out yourself by log this in getHashForBinaryContents method from CodePushUpdateUtils.java

for (String item : context.getAssets().list(""))
              CodePushUtils.log(item);

Why doesn't it occur on every project?

We suggest that this is related to the asset management and to the folder structure of a particular project. Thus, for now we decided not to make changes to the CodePush code so that we can avoid unexpected behaviour in the future.

Instead, we propose a workaround which had worked on our test project.

Why do the solutions from this thread sometimes work, and sometimes - not?

We guess that these implementations and fixes do not resolve the root cause, but trigger Gradle buildOutputCleanup over time. Talking about my personal experience, I just had to wait for the next day, and the build process went significantly faster, while CodePushHash strangely became visible to AssetManager, most likely due to the Gradle cache.

What can actually resolve the issue?

Please add this to the android {...} in your app's build.gradle:

sourceSets {
  release {
    assets {
      srcDirs = ['path/to/your/build/output/folder']
    }
  }
}

Worth to mention: this should be the folder for your build variant (e.g. release), where CodePushHash is situated. For example: build/generated/assets/react/testapp/release

Can we specify multiple srcDirs with CodePushHash, e.g. when we build several apps inside one project?

You can try, but it is likely to cause a conflict (Error: Duplicate resources).

But you can do the following, to dynamically set the srcDir based on your build variant:

def appFlavor

switch(gradle.startParameter.taskNames[0]) {
  case ":app:yourBuildTaskName":
    appFlavor = "testapp"
    break
}
sourceSets {
  release {
    assets {
      srcDirs = appFlavor ? ["build/generated/assets/react/${appFlavor}/release"] : []
    }
  }
}

Sometimes, the order can also count. In my case, I put sourceSets definition to the very end of android {}, after applicationVariants.all {}, while def + switch/case - before that. It worked fine.

You can tweak this however you desire and try different options, overall I hope that this will help :)

Pushkar952 commented 1 year ago

Hello dear colleagues.

This simple workaround may help you, if you get this error while using Gradle build.

Why does this issue occur?

If you import codepush.gradle as suggested, it shall process the CodePushHash generation successfully. At the same time, we use AssetManager to get access to this file, usually situated in assets subfolder somewhere. On debugging, we have noticed that it does not see CodePushHash, thus causing the issue.

You can check it out yourself by log this in getHashForBinaryContents method from CodePushUpdateUtils.java

for (String item : context.getAssets().list(""))
              CodePushUtils.log(item);

Why doesn't it occur on every project?

We suggest that this is related to the asset management and to the folder structure of a particular project. Thus, for now we decided not to make changes to the CodePush code so that we can avoid unexpected behaviour in the future.

Instead, we propose a workaround which had worked on our test project.

Why do the solutions from this thread sometimes work, and sometimes - not?

We guess that these implementations and fixes do not resolve the root cause, but trigger Gradle buildOutputCleanup over time. Talking about my personal experience, I just had to wait for the next day, and the build process went significantly faster, while CodePushHash strangely became visible to AssetManager, most likely due to the Gradle cache.

What can actually resolve the issue?

Please add this to the android {...} in your app's build.gradle:

sourceSets {
  release {
    assets {
      srcDirs = ['path/to/your/build/output/folder']
    }
  }
}

Worth to mention: this should be the folder for your build variant (e.g. release), where CodePushHash is situated. For example: build/generated/assets/react/testapp/release

Can we specify multiple srcDirs with CodePushHash, e.g. when we build several apps inside one project?

You can try, but it is likely to cause a conflict (Error: Duplicate resources).

But you can do the following, to dynamically set the srcDir based on your build variant:

def appFlavor

switch(gradle.startParameter.taskNames[0]) {
  case ":app:yourBuildTaskName":
    appFlavor = "testapp"
    break
}
sourceSets {
  release {
    assets {
      srcDirs = appFlavor ? ["build/generated/assets/react/${appFlavor}/release"] : []
    }
  }
}

Sometimes, the order can also count. In my case, I put sourceSets definition to the very end of android {}, after applicationVariants.all {}, while def + switch/case - before that. It worked fine.

You can tweak this however you desire and try different options, overall I hope that this will help :)

Has this solution worked for anyone?

fantasyado commented 1 year ago

Hi, I upgrade app to RN 0.72.4 and react-native-code-push 8.1.0 it seems good on dev mode. but gives error in release mode. dev:

image

release:

image

don't know what's wrong there...

Sameer-Piramal commented 10 months ago

Hi, I upgrade app to RN 0.72.4 and react-native-code-push 8.1.0 it seems good on dev mode. but gives error in release mode. dev: image

release: image

don't know what's wrong there...

I am having the same Problem, you found a solution?