Skip to content
This repository was archived by the owner on May 20, 2025. It is now read-only.

Conversation

Abbondanzo
Copy link
Contributor

@Abbondanzo Abbondanzo commented Sep 9, 2022

Temporary workaround

Until this is merged, you can do the following to work around the issue: in the build.gradle file located in your app module (i.e. my-project/android/app/build.gradle, not the one in the directory up), add the following lines at the end of the file to replicate the fix:

android.buildTypes.each { buildType ->
    // to prevent incorrect long value restoration from strings.xml we need to wrap it with double quotes
    // https://github.com/microsoft/cordova-plugin-code-push/issues/264
    buildType.resValue 'string', "CODE_PUSH_APK_BUILD_TIME", String.format("\"%d\"", System.currentTimeMillis())
}

There's nothing wrong with generating this resource twice, Android will let you know if it detects both. To confirm that the file has been generated, navigate to my-project/android/app/build/generated/res/resValues/(debug|release)/values/gradleResValues.xml and you should see the CODE_PUSH_APK_BUILD_TIME resource value in there.


PR Description

Relevant issues:

My build setup:
We've got a very jank patch of CodePush running, but the problem lies in resource generation. Nevertheless, here's where we're at:

Motivation:
React Native versions 0.66.0 and up are encouraged to use Android Gradle Plugin 4.2+, so almost certainly anyone who comes across this library will run into some issue regarding this resource value not generating.

Context:
The provided suggestion in almost every one of these issues was to move the resValue call to evaluation time rather than having it run after evaluation time. And this is an important distinction; I'll try to explain why here.

Somewhere around Android Gradle Plugin release 4.2 all the way thru to today, the internals for the ComponentCreationConfig that AGP's GenerateResValues task relies on was changed. I spent a good several hours poking around with a debugger to see what was called, and when. The resValue function of the BaseFlavor, which stores a mapping of resource keys to their respective values, is correctly called for all resource values. This includes the CodePush SDK built time resource value being set here. However, what ended up changing was that halfway between configuration, the map was read from the VariantDSLInfo class and made immutable as part of the task's inputs. Conveniently, any future calls to set new resource values would still be written to the flavor's map internally but would be ignored since the task's MapProperty provider does not change.

As a result, AGP does not honor any resValue calls after evaluation is complete. While it should be throwing an error as it's already doing if you try to configure via a library variant, it is far less strict and will not throw an error if you try to configure from, say a build type or flavor. The GenerateResValues task reaches out to the variant for its resource values, and the VariantImpl reaches over to the VariantDSLInfoImpl which collects from the BaseConfigImpl. After it does all this, it marks the map of resource values immutable only inside of the VariantImpl but we're free to make additions that don't get honored from any futher in that chain.

All of this is to say: TL;DR there are no exceptions thrown by AGP despite the fact that there should be. Either the task should lazily ask the property provider to produce the mapping upon execution, or the various configuration implementations should throw exceptions if you try to modify them. Indeed some do, but not in this case.

Alternatives:
There are a couple ways around this change, but I went with the change that felt like it made the most sense.

  • Works ✅: replacing android.buildTypes.each with android.defaultConfig
  • Works ✅: wrapping the code block in its own gradle.afterProject closure
  • Does not work ❌: wrapping the code block in a gradle.afterEvaluate closer. In fact, any closure that uses the word evaluated with the word after does not work
  • Does not work ❌: setting resources via library or application variant. For reasons aforementioned, this seems to be the only case of safeguarding

@Abbondanzo Abbondanzo requested a review from a team as a code owner September 9, 2022 05:34
@ddikodroid
Copy link

@chrisglein @jedashford @andreidubov @alexandergoncharov-zz
could you review and merge this PR?

@thewulf7
Copy link
Member

@ddikodroid thanks for the PR!

We have couple of question regarding it:

  • Will it still work on existing projects (with very old AGP). If not it's OK, but needs to be documented
  • Should AGP version be bumped in the project?

@Abbondanzo
Copy link
Contributor Author

Abbondanzo commented Sep 13, 2022

* Will it still work on existing projects (with very old AGP). If not it's OK, but needs to be documented

I can confirm that this works with AGP 3.2.0 on Gradle 4.8.1, which is the minimum required version that Android Studio Chipmunk requires. I tried testing with 1.3.0 and 2.2.3, but I hit so many problems with our build setup that I conceded:

Android Studio error Successful resource generation
Screen Shot 2022-09-13 at 8 56 00 AM image
* Should AGP version be bumped in the project?

Most definitely. If not for the reasons aforementioned, the demo project is rocking AGP 4.2.2. It's probably out-of-scope for this PR and I'd like to leave it up to your team, but I'm also happy to cut another PR with an upgrade (just boils down to how old you want to support). A peer dependency can be set for react-native to strictly filter out older versions and throw an error should someone try to install, but that might constitute a minor version bump on this package as well.

I've put together a table below of each of the React Native minor versions, their release dates, and the version of AGP that they recommend:

Minor Version AGP Release Date
57 3.1.4 Sep 12, 2018
58 3.2.1 Jan 24, 2019
59 3.3.1 Mar 12, 2019
60 3.4.1 Jul 03, 2019
61 3.4.2 Aug 27, 2019
62 3.5.2 Mar 26, 2020
63 3.5.3 Jul 08, 2020
64 4.1.0 Mar 12, 2021
65 4.2.1 Aug 17, 2021
66 4.2.2 Oct 01, 2021
67 4.2.2 Jan 18, 2022
68 7.0.4 Mar 30, 2022
69 7.1.1 Jun 22, 2022
70 7.2.1 Sept 5, 2022

@ddikodroid
Copy link

@ddikodroid thanks for the PR!

i'm not creating the PR, i just help the author to be noticed🙌🏻 hope it will get merged soon

@lc-mm
Copy link

lc-mm commented Sep 22, 2022

Moving the resValue call as was done in the PR did work for me but not until I added back it. to the front of it.

I am using react native 0.69.5 (ejected from expo 46)

-gradle.projectsEvaluated {
-    android.buildTypes.each {
-        // to prevent incorrect long value restoration from strings.xml we need to wrap it with double quotes
-        // https://github.com/microsoft/cordova-plugin-code-push/issues/264
-        it.resValue 'string', "CODE_PUSH_APK_BUILD_TIME", String.format("\"%d\"", System.currentTimeMillis())
-    }
+android.buildTypes.each {
+    // to prevent incorrect long value restoration from strings.xml we need to wrap it with double quotes
+    // https://github.com/microsoft/cordova-plugin-code-push/issues/264
+    it.resValue 'string', "CODE_PUSH_APK_BUILD_TIME", String.format("\"%d\"", System.currentTimeMillis())
+}
     
+gradle.projectsEvaluated { 
     android.applicationVariants.all { variant ->
         def nodeModulesPath;
         if (config.root) {

@Abbondanzo
Copy link
Contributor Author

Moving the resValue call as was done in the PR did work for me but not until I added back it. to the front of it.

Good catch! I've fixed this in 3733a6b.

@lc-mm
Copy link

lc-mm commented Sep 22, 2022

Moving the resValue call as was done in the PR did work for me but not until I added back it. to the front of it.

Good catch! I've fixed this in 3733a6b.

Thanks that is working

@vzts
Copy link

vzts commented Nov 26, 2022

@appcenter-fte Can you please check this one ?
This issue is blocking android builds from receiving codepush updates.

@developerdanx
Copy link

Seriously this issue is still open without the attention from the Microsoft Team? We are having the same problem in Android...

@knro
Copy link

knro commented Dec 30, 2022

Why isn't this merged yet??

@hugohow
Copy link

hugohow commented Jan 10, 2023

Have you planned to publish it in a new version ?

@buuhvprojects
Copy link

Solução temporária

Até que isso seja mesclado, você pode fazer o seguinte para contornar o problema: no build.gradlearquivo localizado no módulo do seu aplicativo (ou seja my-project/android/app/build.gradle, não no diretório up), adicione as seguintes linhas no final do arquivo para replicar a correção :

android.buildTypes.each { buildType ->
    // to prevent incorrect long value restoration from strings.xml we need to wrap it with double quotes
    // https://github.com/microsoft/cordova-plugin-code-push/issues/264
    buildType.resValue 'string', "CODE_PUSH_APK_BUILD_TIME", String.format("\"%d\"", System.currentTimeMillis())
}

Não há nada de errado em gerar esse recurso duas vezes, o Android avisará se detectar os dois. Para confirmar que o arquivo foi gerado, navegue até my-project/android/app/build/generated/res/resValues/(debug|release)/values/gradleResValues.xmle você verá o CODE_PUSH_APK_BUILD_TIMEvalor do recurso lá.

Descrição de RP

Questões relevantes:

Minha configuração de compilação: temos um patch muito instável do CodePush em execução, mas o problema está na geração de recursos. No entanto, aqui é onde estamos:

Motivação: as versões 0.66.0 e superiores do React Native são incentivadas a usar o Android Gradle Plugin 4.2+, portanto, quase certamente qualquer pessoa que se deparar com esta biblioteca terá algum problema em relação à geração desse valor de recurso.

Contexto: A sugestão fornecida em quase todos esses problemas foi mover a resValuechamada para o tempo de avaliação em vez de executá-la após o tempo de avaliação. E esta é uma distinção importante; Vou tentar explicar o porquê aqui.

Em algum lugar entre a versão 4.2 do Android Gradle Plugin até hoje, os componentes internos da tarefa ComponentCreationConfigdo AGP foram alterados. GenerateResValuesPassei várias horas fuçando com um depurador para ver o que era chamado e quando. A resValuefunção do BaseFlavor, que armazena um mapeamento das chaves de recurso para seus respectivos valores, é chamada corretamente para todos os valores de recurso. Isso inclui o valor do recurso de tempo criado do CodePush SDK sendo definido aqui. No entanto, o que acabou mudando foi que no meio do caminho entre a configuração, o mapa foi lido da VariantDSLInfoturma e tornado imutável como parte das entradas da tarefa. Convenientemente, quaisquer chamadas futuras para definir novos valores de recursos ainda seriam gravadas no _tipo_map internamente, mas seria ignorado, pois o MapPropertyprovedor da tarefa não muda.

Como resultado, o AGP não aceita nenhuma resValuechamada após a conclusão da avaliação. Embora deva estar gerando um erro como já está ocorrendo se você tentar configurar por meio de uma variante de biblioteca , é muito menos rigoroso e não gerará um erro se você tentar configurar a partir de, digamos, um tipo de compilação ou sabor. A GenerateResValuestarefa alcança a variante para obter seus valores de recursos e VariantImplalcança o VariantDSLInfoImplque coleta do arquivo BaseConfigImpl. Depois de fazer tudo isso, ele marca o mapa de valores de recursos imutáveis ​​apenas dentro da VariantImplcadeia, mas estamos livres para fazer acréscimos que não são honrados por nenhum outro membro dessa cadeia.

Tudo isso é para dizer: TL;DR não há exceções lançadas pelo AGP, apesar do fato de que deveria haver. A tarefa deve solicitar preguiçosamente ao provedor de propriedade para produzir o mapeamento durante a execução ou as várias implementações de configuração devem gerar exceções se você tentar modificá-las. De fato, alguns o fazem, mas não neste caso.

Alternativas: Existem algumas maneiras de contornar essa mudança, mas optei pela mudança que parecia fazer mais sentido.

  • Funciona✅: substituindo android.buildTypes.eachporandroid.defaultConfig
  • Funciona✅: envolvendo o bloco de código em seu próprio gradle.afterProjectfechamento
  • Não funciona❌: envolvendo o bloco de código em um gradle.afterEvaluateclose. Na verdade, qualquer encerramento que use a palavra avaliada com a palavra depois não funciona
  • Não funciona❌: configuração de recursos via biblioteca ou variante de aplicativo. Pelas razões acima expostas, este parece ser o único caso de salvaguarda

thanks, its worked for me

@DmitriyKirakosyan
Copy link
Contributor

@hugohow The release with this fix included is published.

retyui added a commit to retyui/CodePushCiCd that referenced this pull request Feb 4, 2023
@vardan0107
Copy link

vardan0107 commented Feb 28, 2023

I am still facing this issue even after updating codepush to 7.1.0
code is working only after adding this line in default config

resValue 'string', "CODE_PUSH_APK_BUILD_TIME", String.format("\"%d\"", System.currentTimeMillis())

configurations:
"react-native": "0.68.5"
com.android.tools.build:gradle:7.3.1

@mosdehcom
Copy link

mosdehcom commented Feb 11, 2024

@Abbondanzo @thewulf7
I have faced the same problem with CodePush (8.2.1):
Workaround helped, but permanent solution is required or documentation should be updated to include the workaround in case it is a permanent solution.
Thank for revisiting this.

"react": "18.2.0",
"react-native": "0.72.6",
"react-native-code-push": "^8.2.1",


Gradle 8.0.1

Build time: 2023-02-17 20:09:48 UTC
Revision: 68959bf76cef4d28c678f2e2085ee84e8647b77a

Kotlin: 1.8.10
Groovy: 3.0.13
Ant: Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM: 17.0.10 (Eclipse Adoptium 17.0.10+7)
OS: Mac OS X 14.3.1 aarch64

@Abbondanzo
Copy link
Contributor Author

Abbondanzo commented Feb 12, 2024

@Abbondanzo @thewulf7 I have faced the same problem with CodePush (8.2.1): Workaround helped, but permanent solution is required or documentation should be updated to include the workaround in case it is a permanent solution. Thank for revisiting this.

Which workaround are you using? The fix should be available in every version of CodePush greater than 7.1.0 (if you're following the setup instructions for Android here)

@mosdehcom
Copy link

@Abbondanzo @thewulf7 I have faced the same problem with CodePush (8.2.1): Workaround helped, but permanent solution is required or documentation should be updated to include the workaround in case it is a permanent solution. Thank for revisiting this.

Which workaround are you using? The fix should be available in every version of CodePush greater than 7.1.0 (if you're following the setup instructions for Android here)

Hi, I have used the below in android/app/build.gradle

android.buildTypes.each { buildType ->
    // to prevent incorrect long value restoration from strings.xml we need to wrap it with double quotes
    // https://github.com/microsoft/cordova-plugin-code-push/issues/264
    buildType.resValue 'string', "CODE_PUSH_APK_BUILD_TIME", String.format("\"%d\"", System.currentTimeMillis())
}

I am using Multi-Deployment Testing and problem was only with "secondary" deployment releaseStaging

buildTypes {
        debug {
            signingConfig signingConfigs.debug
            // Note: CodePush updates shouldn't be tested in Debug mode as they're overriden by the RN packager. However, because CodePush checks for updates in all modes, we must supply a key.
            resValue "string", "CodePushDeploymentKey", '""'
        }
        releaseStaging {
            // 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"
            
            resValue "string", "CodePushDeploymentKey", '"XKaXQyxNyk6kOe9crJAOdDhWL5owuOsZsATIX"'
            // Note: It's a good idea to provide matchingFallbacks for the new buildType you create to prevent build issues
            // Add the following line if not already there
            matchingFallbacks = ['release']
        }   
        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"
            resValue "string", "CodePushDeploymentKey", '"lJOLXjccOLBFhbgfDsnDI1NFi3ofibXfEEsM-"'
        }
    }

@rmhn10
Copy link

rmhn10 commented Aug 2, 2024

Moving the resValue call as was done in the PR did work for me but not until I added back it. to the front of it.

I am using react native 0.69.5 (ejected from expo 46)

-gradle.projectsEvaluated {
-    android.buildTypes.each {
-        // to prevent incorrect long value restoration from strings.xml we need to wrap it with double quotes
-        // https://github.com/microsoft/cordova-plugin-code-push/issues/264
-        it.resValue 'string', "CODE_PUSH_APK_BUILD_TIME", String.format("\"%d\"", System.currentTimeMillis())
-    }
+android.buildTypes.each {
+    // to prevent incorrect long value restoration from strings.xml we need to wrap it with double quotes
+    // https://github.com/microsoft/cordova-plugin-code-push/issues/264
+    it.resValue 'string', "CODE_PUSH_APK_BUILD_TIME", String.format("\"%d\"", System.currentTimeMillis())
+}
     
+gradle.projectsEvaluated { 
     android.applicationVariants.all { variant ->
         def nodeModulesPath;
         if (config.root) {

Thanks..! That worked for me, but is this a mature approach? or do we have some other approaches too?

@IlyaBausovAkvelon
Copy link

@rmhn10 Hi, What React Native Code Push version do you use?

@rmhn10
Copy link

rmhn10 commented Aug 14, 2024

@rmhn10 Hi, What React Native Code Push version do you use?

7.0.4
But Now I have upgraded the package to 7.1.0 because of Api level 34 and now its working fine.

@IlyaBausovAkvelon
Copy link

@rmhn10 Great!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.