stripe-react-native: Google Pay: Missing annotations

Describe the bug Android builds fail because of an annotations error. I am migrating a react-native project to a monorepo managed with nx. It seems like a misconfiguration related to gradle and linting. The project builds after I remove the @stripe/stripe-react-native package.

This does not occur if I install the package on a new project with the react-native cli.

I have tried tweaking the gradle versions, but continue to run into this. Could someone please provide pointers to resolving this.

> Task :stripe_stripe-react-native:packageDebugResources FAILED

Deprecated Gradle features were used in this build, making it incompatible with Gradle 8.0.

You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.

See https://docs.gradle.org/7.3.3/userguide/command_line_interface.html#sec:command_line_warnings
58 actionable tasks: 2 executed, 56 up-to-date
ERROR:/Users/esfxra/monorepo/apps/test-app/node_modules/@stripe/stripe-react-native/android/src/main/res/layout/googlepay_button_dark.xml: Resource and asset merger: /Users/esfxra/monorepo/apps/test-app/node_modules/@stripe/stripe-react-native/android/src/main/res/layout/googlepay_button_dark.xml is not annotated as @Input
    java.lang.IllegalStateException: /Users/esfxra/monorepo/apps/test-app/node_modules/@stripe/stripe-react-native/android/src/main/res/layout/googlepay_button_dark.xml is not annotated as @Input
FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':stripe_stripe-react-native:packageDebugResources'.
> /Users/esfxra/monorepo/apps/test-app/node_modules/@stripe/stripe-react-native/android/src/main/res/layout/googlepay_button_dark.xml: Error: is not annotated as @Input

To Reproduce Steps to reproduce the behavior:

  1. Run npm install @stripe/stripe-react-native
  2. Integrate the <StripeProvider>{...}</StripeProvider> component
  3. Run npx nx run wifi-app:run-android
  4. See error

This is a repo scaffolded with nx where the error can be reproduced [RN 0.69]:

And this is a repo scaffolded by the react-native cli with no errors [RN 0.69]:

Expected behavior N/A

Screenshots N/A

Desktop (please complete the following information): N/A

Smartphone (please complete the following information):

  • Device: Pixel 3
  • OS: Android

Additional context N/A

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 5
  • Comments: 48 (3 by maintainers)

Most upvoted comments

I’ve fixed this issue by using patch-package to patch the @react-native-community/cli-platform-android package so it loads the dependencies from the root node_modules folder. The issue definitely seems to be related to symlinks, which gradle doesn’t know how to handle (at least it seems that way from my research). Here’s the patch:

diff --git a/node_modules/@react-native-community/cli-platform-android/native_modules.gradle b/node_modules/@react-native-community/cli-platform-android/native_modules.gradle
index 4a63eaf..05b4511 100644
--- a/node_modules/@react-native-community/cli-platform-android/native_modules.gradle
+++ b/node_modules/@react-native-community/cli-platform-android/native_modules.gradle
@@ -469,7 +469,7 @@ class ReactNativeModules {
         def nameCleansed = name.replaceAll('[~*!\'()]+', '_').replaceAll('^@([\\w-.]+)/', '$1_')
         reactNativeModuleConfig.put("name", name)
         reactNativeModuleConfig.put("nameCleansed", nameCleansed)
-        reactNativeModuleConfig.put("androidSourceDir", androidConfig["sourceDir"])
+        reactNativeModuleConfig.put("androidSourceDir", androidConfig["sourceDir"].replace('apps/your-app-name/', ""))
         reactNativeModuleConfig.put("packageInstance", androidConfig["packageInstance"])
         reactNativeModuleConfig.put("packageImportPath", androidConfig["packageImportPath"])
         reactNativeModuleConfig.put("libraryName", androidConfig["libraryName"])

Can this be reopened, only package that has this issue

I approached this issue with this patch;

  1. Delete the layout folder node_modules/@stripe/stripe-react-native/android/src/main/res/layout

  2. Comment the layouts inside initialize() method of node_modules/@stripe/stripe-react-native/android/src/main/java/com/reactnativestripesdk/GooglePayButtonView.kt

package com.reactnativestripesdk

import android.view.LayoutInflater
import android.widget.FrameLayout
import com.facebook.react.uimanager.ThemedReactContext

class GooglePayButtonView(private val context: ThemedReactContext) : FrameLayout(context) {
  private var buttonType: String? = null

  fun initialize() {
  //  val type =
  //    when (buttonType) {
  //      "pay" -> R.layout.pay_with_googlepay_button
  //      "standard" -> R.layout.googlepay_button
  //      else -> R.layout.googlepay_button
  //    }

  //  val button = LayoutInflater.from(context).inflate(
  //    type, null
  //  )

  //  addView(button)
  }

  fun setType(type: String) {
    buttonType = type
  }
}
  1. If you have added these dependencies into your build.gradle file, just comment them.
// implementation 'com.google.android.material:material:1.3.0'
// implementation 'com.stripe:stripe-android:20.12.+'

You need to do the same process whenever you execute npm install but if you want to automate this process follow the below steps.

  1. Create a shell script like this patch.sh and assign 777 permission, sudo chmod +x patch.sh
#!/bin/bash

ORIGINAL_DIR="node_modules/@stripe/stripe-react-native/android/src/main"
FIXED_DIR="patched_node_modules/@stripe/stripe-react-native/android/src/main"

# Remove the layout directory
rm -rf "$ORIGINAL_DIR/res/layout"

# Replace the file
cp "$FIXED_DIR/java/com/reactnativestripesdk/GooglePayButtonView.kt" "$ORIGINAL_DIR/java/com/reactnativestripesdk/GooglePayButtonView.kt"

echo "Successfully patched node_modules!"
  1. Create a patched Kotlin file inside patched_node_modules/@stripe/stripe-react-native/android/src/main/java/com/reactnativestripesdk/GooglePayButtonView.kt
package com.reactnativestripesdk

import android.view.LayoutInflater
import android.widget.FrameLayout
import com.facebook.react.uimanager.ThemedReactContext

class GooglePayButtonView(private val context: ThemedReactContext) : FrameLayout(context) {
  private var buttonType: String? = null

  fun initialize() {
  //  val type =
  //    when (buttonType) {
  //      "pay" -> R.layout.pay_with_googlepay_button
  //      "standard" -> R.layout.googlepay_button
  //      else -> R.layout.googlepay_button
  //    }

  //  val button = LayoutInflater.from(context).inflate(
  //    type, null
  //  )

  //  addView(button)
  }

  fun setType(type: String) {
    buttonType = type
  }
}
  1. Add postinstall script inside package.json
  "scripts": {
    ...
    "postinstall": "./patch.sh"
  },

That’s it now until the Stripe team fixes this issue, we can survive.

I have just started investigating, and it seems like the issue is indeed related to Gradle and the .xml files not being inside the root project (but only symlinked there).

As mentioned above, removing the .xml files and their references fixes the build.

Simple Patch
diff --git a/android/src/main/java/com/reactnativestripesdk/GooglePayButtonView.kt b/android/src/main/java/com/reactnativestripesdk/GooglePayButtonView.kt
index 0b3b6206cea2ac7348599840bff746b2085a9f49..1b35e01a9c1eeb71051de4800362d1dbf99b3612 100644
--- a/android/src/main/java/com/reactnativestripesdk/GooglePayButtonView.kt
+++ b/android/src/main/java/com/reactnativestripesdk/GooglePayButtonView.kt
@@ -9,22 +9,6 @@ class GooglePayButtonView(private val context: ThemedReactContext) : FrameLayout
   private var buttonType: String? = null
 
   fun initialize() {
-    val type =
-      when (buttonType) {
-        "pay" -> R.layout.pay_with_googlepay_button_no_shadow
-        "pay_dark" -> R.layout.pay_with_googlepay_button_dark
-        "pay_shadow" -> R.layout.pay_with_googlepay_button
-        "standard" -> R.layout.googlepay_button_no_shadow
-        "standard_dark" -> R.layout.googlepay_button_dark
-        "standard_shadow" -> R.layout.googlepay_button
-        else -> if (isNightMode()) R.layout.googlepay_button_dark else R.layout.googlepay_button
-      }
-
-    val button = LayoutInflater.from(context).inflate(
-      type, null
-    )
-
-    addView(button)
   }
 
   fun setType(type: String) {
diff --git a/android/src/main/res/layout/googlepay_button.xml b/android/src/main/res/layout/googlepay_button.xml
deleted file mode 100755
index 94cab75a3fa2d3f14b94f58686948b24e1ee7257..0000000000000000000000000000000000000000
--- a/android/src/main/res/layout/googlepay_button.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:clickable="true"
-    android:focusable="true"
-    android:layout_width="match_parent"
-    android:layout_height="48sp"
-    android:background="@drawable/googlepay_button_background"
-    android:padding="2sp"
-    android:contentDescription="@string/googlepay_button_content_description">
-    <LinearLayout
-        android:duplicateParentState="true"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:weightSum="2"
-        android:gravity="center_vertical"
-        android:orientation="vertical">
-        <ImageView
-            android:layout_weight="1"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:scaleType="fitCenter"
-            android:duplicateParentState="true"
-            android:src="@drawable/googlepay_button_content"/>
-    </LinearLayout>
-    <ImageView
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:scaleType="fitXY"
-        android:duplicateParentState="true"
-        android:src="@drawable/googlepay_button_overlay"/>
-</RelativeLayout>
diff --git a/android/src/main/res/layout/googlepay_button_dark.xml b/android/src/main/res/layout/googlepay_button_dark.xml
deleted file mode 100644
index db04022525ceb9fbf07c09fe89d73a8b891ea3e7..0000000000000000000000000000000000000000
--- a/android/src/main/res/layout/googlepay_button_dark.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:clickable="true"
-    android:focusable="true"
-    android:layout_width="match_parent"
-    android:layout_height="48sp"
-    android:background="@drawable/googlepay_button_background_dark"
-    android:padding="2sp"
-    android:contentDescription="@string/googlepay_button_content_description">
-    <LinearLayout
-        android:duplicateParentState="true"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:weightSum="2"
-        android:gravity="center_vertical"
-        android:orientation="vertical">
-        <ImageView
-            android:layout_weight="1"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:scaleType="fitCenter"
-            android:duplicateParentState="true"
-            android:src="@drawable/googlepay_button_content_dark"/>
-    </LinearLayout>
-    <ImageView
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:scaleType="fitXY"
-        android:duplicateParentState="true"
-        android:src="@drawable/googlepay_button_overlay_dark"/>
-</RelativeLayout>
diff --git a/android/src/main/res/layout/googlepay_button_no_shadow.xml b/android/src/main/res/layout/googlepay_button_no_shadow.xml
deleted file mode 100755
index 41f09f7b597a633dccaa1d3ed9513d2c7e11ac7f..0000000000000000000000000000000000000000
--- a/android/src/main/res/layout/googlepay_button_no_shadow.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:clickable="true"
-    android:focusable="true"
-    android:layout_width="match_parent"
-    android:layout_height="48sp"
-    android:background="@drawable/googlepay_button_no_shadow_background"
-    android:paddingTop="2sp"
-    android:contentDescription="@string/googlepay_button_content_description">
-    <LinearLayout
-        android:duplicateParentState="true"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:weightSum="2"
-        android:gravity="center_vertical"
-        android:orientation="vertical">
-        <ImageView
-            android:layout_weight="1"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:scaleType="fitCenter"
-            android:duplicateParentState="true"
-            android:src="@drawable/googlepay_button_content"/>
-    </LinearLayout>
-    <ImageView
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:scaleType="fitXY"
-        android:duplicateParentState="true"
-        android:src="@drawable/googlepay_button_overlay"/>
-</RelativeLayout>
diff --git a/android/src/main/res/layout/pay_with_googlepay_button.xml b/android/src/main/res/layout/pay_with_googlepay_button.xml
deleted file mode 100755
index 9ac6e8aebb811319f26562fcee7d3e3a70c9f574..0000000000000000000000000000000000000000
--- a/android/src/main/res/layout/pay_with_googlepay_button.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:clickable="true"
-    android:focusable="true"
-    android:layout_width="match_parent"
-    android:layout_height="48sp"
-    android:background="@drawable/googlepay_button_background"
-    android:padding="2sp"
-    android:contentDescription="@string/pay_with_googlepay_button_content_description">
-    <LinearLayout
-        android:duplicateParentState="true"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:weightSum="2"
-        android:gravity="center_vertical"
-        android:orientation="vertical">
-        <ImageView
-            android:layout_weight="1"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:scaleType="fitCenter"
-            android:duplicateParentState="true"
-            android:src="@drawable/pay_with_googlepay_button_content"/>
-    </LinearLayout>
-    <ImageView
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:scaleType="fitXY"
-        android:duplicateParentState="true"
-        android:src="@drawable/googlepay_button_overlay"/>
-</RelativeLayout>
\ No newline at end of file
diff --git a/android/src/main/res/layout/pay_with_googlepay_button_dark.xml b/android/src/main/res/layout/pay_with_googlepay_button_dark.xml
deleted file mode 100644
index 000c46b680f9b97d14c4e2b9d3e5d1ddccc45318..0000000000000000000000000000000000000000
--- a/android/src/main/res/layout/pay_with_googlepay_button_dark.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:clickable="true"
-    android:focusable="true"
-    android:layout_width="match_parent"
-    android:layout_height="48sp"
-    android:background="@drawable/googlepay_button_background_dark"
-    android:padding="2sp"
-    android:contentDescription="@string/pay_with_googlepay_button_content_description">
-    <LinearLayout
-        android:duplicateParentState="true"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:weightSum="2"
-        android:gravity="center_vertical"
-        android:orientation="vertical">
-        <ImageView
-            android:layout_weight="1"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:scaleType="fitCenter"
-            android:duplicateParentState="true"
-            android:src="@drawable/pay_with_googlepay_button_content_dark"/>
-    </LinearLayout>
-    <ImageView
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:scaleType="fitXY"
-        android:duplicateParentState="true"
-        android:src="@drawable/googlepay_button_overlay_dark"/>
-</RelativeLayout>
diff --git a/android/src/main/res/layout/pay_with_googlepay_button_no_shadow.xml b/android/src/main/res/layout/pay_with_googlepay_button_no_shadow.xml
deleted file mode 100755
index e1f0a73595d6f24a0ac05a6bb33513f337592c28..0000000000000000000000000000000000000000
--- a/android/src/main/res/layout/pay_with_googlepay_button_no_shadow.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:clickable="true"
-    android:focusable="true"
-    android:layout_width="match_parent"
-    android:layout_height="48sp"
-    android:background="@drawable/googlepay_button_no_shadow_background"
-    android:padding="4sp"
-    android:contentDescription="@string/pay_with_googlepay_button_content_description">
-    <LinearLayout
-        android:duplicateParentState="true"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:weightSum="2"
-        android:gravity="center_vertical"
-        android:orientation="vertical">
-        <ImageView
-            android:layout_weight="1"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:scaleType="fitCenter"
-            android:duplicateParentState="true"
-            android:src="@drawable/pay_with_googlepay_button_content"/>
-    </LinearLayout>
-    <ImageView
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:scaleType="fitXY"
-        android:duplicateParentState="true"
-        android:src="@drawable/googlepay_button_overlay"/>
-</RelativeLayout>
\ No newline at end of file

I won’t be able to get to this super soon, but hope to debug it eventually. I’m curious if this only affects stripe-react-native, or is a more widespread issue with .xml assets

I’ve fixed this issue by using patch-package to patch the @react-native-community/cli-platform-android package so it loads the dependencies from the root node_modules folder. The issue definitely seems to be related to symlinks, which gradle doesn’t know how to handle (at least it seems that way from my research). Here’s the patch:

diff --git a/node_modules/@react-native-community/cli-platform-android/native_modules.gradle b/node_modules/@react-native-community/cli-platform-android/native_modules.gradle
index 4a63eaf..05b4511 100644
--- a/node_modules/@react-native-community/cli-platform-android/native_modules.gradle
+++ b/node_modules/@react-native-community/cli-platform-android/native_modules.gradle
@@ -469,7 +469,7 @@ class ReactNativeModules {
         def nameCleansed = name.replaceAll('[~*!\'()]+', '_').replaceAll('^@([\\w-.]+)/', '$1_')
         reactNativeModuleConfig.put("name", name)
         reactNativeModuleConfig.put("nameCleansed", nameCleansed)
-        reactNativeModuleConfig.put("androidSourceDir", androidConfig["sourceDir"])
+        reactNativeModuleConfig.put("androidSourceDir", androidConfig["sourceDir"].replace('apps/your-app-name/', ""))
         reactNativeModuleConfig.put("packageInstance", androidConfig["packageInstance"])
         reactNativeModuleConfig.put("packageImportPath", androidConfig["packageImportPath"])
         reactNativeModuleConfig.put("libraryName", androidConfig["libraryName"])

I used this patch on my project which is a mono repo by Nx, It solved the Stripe issue but causes another issue for ‘react-native-gesture-handler’

[react-native-gesture-handler] Multiple versions of Gesture Handler were detected. Only one instance of react-native-gesture-handler can be installed in a project. You need to resolve the conflict manually. Check out the documentation: https://docs.swmansion.com/react-native-gesture-handler/docs/troubleshooting#multiple-instances-of-gesture-handler-were-detected

I followed the react-native-gesture-handler approach in their documentation to resolve this issue too, but did not work!

@aslamanver please note that the PlatformPayButton (or GooglePayButton if you’re on an older version) component will not work anymore with your changes. This patch linked further above does not have that side effect

That patch does not work in our case

Hi @retro @andreacab2, how you guys can make it work? I tried the solution but it doesn’t work in my case

Same issue here. Any news about this ?

Closing this for now since it seems like an issue with nx. Hope to hear back from them in that issue linked above, and if there are actionable changes on our end to make, happy to follow up and take care of that

Hi, I have the same problem since I tried to upgrade to react native 0.69. I also use nx but Gradle 7.