@expensify/react-native-wallet 0.1.41 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,6 +5,7 @@
5
5
  - ♻️ Universal solution (Apple Wallet and Google Wallet)
6
6
  - 💳 Easy and secure addition of payment cards from your app directly
7
7
  - 💰 Supports Visa, MasterCard, Amex and Discover payment cards
8
+ - 🔐 UAPP (Unified Android Push Provisioning) support for enhanced security
8
9
  - 🎉 Expo support (expo-plugin)
9
10
 
10
11
  ## Getting started
@@ -21,7 +22,7 @@ To be able to interact with the Google Wallet on the Android please make sure to
21
22
  1. Visit [the Google Pay Android Push Provisioning API documentation](https://developers.google.com/pay/issuers/apis/push-provisioning/android/) and request access to it.
22
23
 
23
24
  2. Once getting an approval from the Google team
24
- 1. Download the [TapAndPay SDK](https://developers.google.com/pay/issuers/apis/push-provisioning/android/releases).
25
+ 1. Download the [TapAndPay SDK](https://developers.google.com/pay/issuers/apis/push-provisioning/android/releases). The library uses the UAPP APIs (`PaymentCredentialsGenerator`, `PushTokenizeResult`), so older SDK versions without them will not compile. Tested with 18.10.1.
25
26
  2. Unzip it and extract the SDK into the `/android/libs` folder in your React Native project (if there is no `libs` folder, create one).
26
27
  3. Add `/android/libs` to `.gitignore`.
27
28
 
@@ -134,7 +135,7 @@ In your `app.json` file, add the following configuration:
134
135
  "@expensify/react-native-wallet",
135
136
  {
136
137
  enableApplePayProvisioning: true,
137
- googleTapAndPaySdkPath: "./libs/tapandpay-v18.7.0.zip", // path to the Google Tap & Pay SDK zip file
138
+ googleTapAndPaySdkPath: "./libs/tapandpay-v18.10.1.zip", // path to the Google Tap & Pay SDK zip file
138
139
  },
139
140
  ],
140
141
  ]
@@ -157,6 +158,7 @@ Here you can find data elements used in the library, essential to work with Goog
157
158
 
158
159
  ### Android
159
160
  - **Opaque Payment Card** (OPC) - a binary blob of information Google Pay receives from the issuer app that could be presented to TSP to receive a token.
161
+ - **Google Opaque Payment Card** (Google OPC) - an encrypted version of the OPC required for UAPP (Unified Android Push Provisioning) flow. This is generated by your backend using Google's encryption keys during the provisioning process. [Learn more about UAPP →](./docs/UAPP.md)
160
162
  - **Token Service Provider** (TSP) - a service that enhances payment security by replacing a credit card number during transactions with a unique digital identifier - token. The TSP specifies the tokenization service used to create a given token e.g. Visa, MasterCard, American Express.
161
163
  - **Token Reference ID** - a unique identifying number to refer to a DPAN (Dynamic Personal Account Number). Token Providers will assign each DPAN an issuer token ID at the time of tokenization.
162
164
 
@@ -168,7 +170,7 @@ Here you can find data elements used in the library, essential to work with Goog
168
170
  - **Ephemeral Public Key** - a key used by elliptic curve cryptography (ECC) (Base 64 encoded).
169
171
 
170
172
  # API Reference
171
- The library offers seven functions for seamless integration and use of the Apple Wallet and Google Wallet APIs. Additionally, it includes one listener that informs when the added card has been activated. Below, these functions are described along with the data types involved.
173
+ The library offers functions for seamless integration and use of the Apple Wallet and Google Wallet APIs. Additionally, it includes listeners and handlers for managing provisioning events. Below, these functions are described along with the data types involved.
172
174
 
173
175
  ## Functions
174
176
 
@@ -178,26 +180,49 @@ The library offers seven functions for seamless integration and use of the Apple
178
180
  | **checkWalletAvailability** | Checks if the wallet is ready and initializes it if possible. | None | `boolean` | ✅ | ✅ |
179
181
  | **getCardStatusBySuffix** | Retrieves the current status of a card in the wallet. | `lastDigits: string`<br>(The last few digits of the card number) | `CardStatus` | ✅ | ✅ |
180
182
  | **getCardStatusByIdentifier** | Returns the state of a card based on a platform-specific identifier. On Android, it's `Token Reference ID` and on iOS, it's `Primary Account Identifier`. | `identifier: string`,<br>`tsp: string` | `CardStatus` | ✅ | ✅ |
181
- | **addCardToGoogleWallet** | Initiates native Push Provisioning flow for adding a card to the Google Wallet. | `data`: `AndroidCardData` | `TokenizationStatus` | ❌ | ✅ |
183
+ | **hasEligibleTokenizationTarget** | Checks whether the card can still be added to a Google Wallet target (the phone or a paired wearable). Google recommends it for the "Add to Google Wallet" button when wearables are supported, because a card already on the phone can still be added to a watch. | `last4Digits: string`,<br>`network: string`,<br>`issuerName: string` | `boolean` | ❌ | ✅ |
184
+ | **addCardToGoogleWallet** | Initiates native Push Provisioning flow for adding a card to the Google Wallet. Requires a handler that returns the payment credentials for the UAPP flow. [Learn more →](./docs/UAPP.md) | `data`: `AndroidCardData`,<br>`handlePaymentCredentials`: `(data: onPaymentCredentialsRequestPayload) => Promise<AndroidPaymentCredentialsResponse>` | `TokenizationStatus` | ❌ | ✅ |
182
185
  | **resumeAddCardToGoogleWallet** | Resumes the Push Provisioning flow for adding a card to the Google Wallet using existing token reference ID. | `data`: `AndroidResumeCardData` | `TokenizationStatus` | ❌ | ✅ |
183
186
  | **listTokens** | Lists all tokens currently stored in the Google Wallet. | None | `TokenInfo[]` | ❌ | ✅ |
184
187
  | **addCardToAppleWallet** | Initiates native Push Provisioning flow for adding a card to the Apple Wallet. | `data`: `IOSCardData`,<br>`issuerEncrypt-`<br>`PayloadCallback: IOSIssuerCallback` | `void` | ✅ | ❌ |
185
188
 
186
-
187
189
  ## Data Types
188
190
 
189
191
  | Type | Description | Fields |
190
192
  |------|-------------|--------|
191
193
  | **AndroidWalletData** | Specific information for Android devices required for wallet transactions. | `deviceID: string`,<br>`walletAccountID: string` |
192
- | **AndroidCardData** | Data related to a card that is to be added on Android platform wallets. | `network: string`,<br>`opaquePaymentCard: string`,<br>`cardHolderName: string`,<br>`lastDigits: string`,<br>`userAddress: UserAddress` |
194
+ | **AndroidCardData** | Data related to a card that is to be added on Android platform wallets. | `network: string`,<br>`opaquePaymentCard: string`,<br>`cardHolderName: string`,<br>`lastDigits: string`,<br>`userAddress: UserAddress`,<br>`isVirtualCard?: boolean`,<br>`isBounceProvisioned?: boolean` |
193
195
  | **AndroidResumeCardData** | Simplified data structure for resuming card addition to Google Wallet using existing token reference ID. | `network: string`,<br>`tokenReferenceID: string`,<br>`cardHolderName?: string`,<br>`lastDigits?: string` |
196
+ | **AndroidPaymentCredentialsResponse** | Response object containing encrypted payment credentials for UAPP flow. [Learn more →](./docs/UAPP.md) | `opaquePaymentCard: string`,<br>`googleOpaquePaymentCard: string` |
197
+ | **onPaymentCredentialsRequestPayload** | Payload received when Google Wallet requests payment credentials during UAPP provisioning. [Learn more →](./docs/UAPP.md) | `requestId: string`,<br>`serverSessionId: string`,<br>`walletId: string`,<br>`tokenRequestorId: string \| null`,<br>`opaquePaymentCard: string` |
194
198
  | **UserAddress** | Structured address used for cardholder verification. | `name: string`,<br>`addressOne: string`,<br>`addressTwo: string`,<br>`city: string`,<br>`administrativeArea: string`,<br>`countryCode: string`,<br>`postalCode: string`,<br>`phoneNumber: string` |
195
199
  | **IOSCardData** | Data related to a card that is to be added on iOS platform. | `network: string`,<br>`activationData: string`,<br>`encryptedPassData: string`,<br>`ephemeralPublicKey: string`,<br>`cardHolderTitle: string`,<br>`cardHolderName: string`,<br>`lastDigits: string`,<br>`cardDescription: string`,<br>`cardDescriptionComment: string` |
196
- | **onCardActivatedPayload** | Data used by listener to notice when a card's status changes. | `tokenId: string`,<br> `status: 'activated' \| 'canceled'`<br> |
200
+ | **onCardActivatedPayload** | Data used by listener to notice when a card's status changes. | `tokenId?: string \| null`,<br> `status: 'activated' \| 'canceled'`<br> |
197
201
  | **IOSIssuerCallback** | This callback is invoked with a nonce, its signature, and a certificate array obtained from Apple. It is expected that you will forward these details to your server or the card issuer's API to securely encrypt the payload required for adding cards to the Apple Wallet. | `(nonce: string, nonceSignature: string, certificate: string[]) => IOSEncryptPayload` |
198
202
  | **IOSEncryptPayload** | An object containing the necessary elements to complete the addition of a card to Apple Wallet. | `encryptedPassData: string`,<br>`activationData: string`,<br>`ephemeralPublicKey: string` |
199
203
  | **TokenInfo** | Information about a token stored in Google Wallet. | `identifier: string`,<br>`lastDigits: string`,<br>`tokenState: number` |
200
204
 
205
+ ### AndroidCardData Optional Fields
206
+
207
+ The `AndroidCardData` type includes two optional boolean fields that provide additional information about the card being provisioned:
208
+
209
+ #### `isVirtualCard?: boolean`
210
+
211
+ Indicates whether the card being provisioned is a virtual card. Virtual cards are digitally-generated card numbers that are linked to a physical card account. They provide enhanced security by:
212
+ - Allowing users to make online purchases without exposing their physical card number
213
+ - Enabling easy cancellation and regeneration without affecting the physical card
214
+ - Providing transaction-specific or merchant-specific card numbers
215
+
216
+ When set to `true`, this flag informs Google Wallet that the card being provisioned is a virtual card, which may affect how the card is displayed and managed in the wallet interface.
217
+
218
+ #### `isBounceProvisioned?: boolean`
219
+
220
+ Indicates whether the card has been provisioned through "bounce provisioning". Bounce provisioning is a two-step provisioning flow where:
221
+ 1. The user initially provisions a card directly through Google Wallet (outside your app)
222
+ 2. Your app later "bounces" or redirects the user back to complete additional verification or setup steps
223
+
224
+ This flag helps Google Wallet track cards that were initially added through the Google Wallet app but require additional app-specific configuration or verification. When set to `true`, it signals that this card was previously provisioned through the Google Wallet interface and is now being completed or updated through your application.
225
+
201
226
  ## Card Status
202
227
 
203
228
  | Type | Possible Values |
@@ -283,17 +308,44 @@ const base64ToHex = (base64: string): string => Buffer.from(base64, "base64").to
283
308
 
284
309
  This will depend on the implementation of your backend/issuer so make sure to check with them otherwise IOS might fail to provision the card.
285
310
 
311
+ # UAPP (Unified Android Push Provisioning)
312
+
313
+ For Android applications that require enhanced security for card provisioning, this library supports UAPP (Unified Android Push Provisioning) flow with Google Wallet.
314
+
315
+ 📖 **[Read the complete UAPP documentation →](./docs/UAPP.md)**
316
+
317
+ The UAPP guide covers:
318
+ - What UAPP is and how it works
319
+ - Step-by-step setup instructions
320
+ - Backend implementation requirements
321
+ - Error handling and troubleshooting
322
+ - Complete code examples
323
+
286
324
  # Publishing your app
287
325
 
288
326
  To successfully publish your app, you will need to navigate through a series of mandatory test cases on both platforms.
289
327
 
290
328
  ### Android
291
329
 
330
+ > [!WARNING]
331
+ > **Testing is mandatory before production release.** Your access to the Google Wallet production environment may be revoked if you do not provide the required test evidence for launch approval. Complete all testing requirements before deploying your app.
332
+
292
333
  Before deploying your app to the Google Play Store, make sure you have taken care of the security when implementing Push Provisioning and properly tested your code. To accomplish it, please familiarize yourself with [the Google's App Push Provisioning best practices](https://developers.google.com/pay/issuers/apis/push-provisioning/android/best-practices).
293
334
 
294
335
  The latest information about deploying apps with Google TapAndPay SDK can be found in the [pre-launch process](https://developers.google.com/pay/issuers/apis/push-provisioning/android/launch-process#step_3_issuer_app_product_review) and [beta tests](https://developers.google.com/pay/issuers/apis/push-provisioning/android/beta-testing) sections in Google documentation. Make sure to complete all of the steps specified by Google connected to the __Google's branding__, __API safety__, and __app stability__.
295
336
 
296
- The app will need to be reviewed by Google. During this process, it will need to pass 4 mandatory test cases that are specified [here](https://developers.google.com/pay/issuers/apis/push-provisioning/android/test-cases). They verify how your app handles card state tracking in different scenarios.
337
+ #### Testing Requirements
338
+
339
+ The app will need to be reviewed by Google. During this process, it will need to pass 4 mandatory test cases that are specified in the [official Google testing documentation](https://developers.google.com/pay/issuers/apis/push-provisioning/android/test-cases). They verify how your app handles card state tracking in different scenarios.
340
+
341
+ **Key testing criteria include:**
342
+ - Proper handling of card states (active, pending, suspended, etc.)
343
+ - Correct UI behavior when cards are already provisioned
344
+ - Secure handling of sensitive payment data
345
+ - Compliance with Google's branding guidelines
346
+ - Proper error handling and user feedback
347
+
348
+ Please refer to the [complete testing criteria documentation](https://developers.google.com/pay/issuers/apis/push-provisioning/android/test-cases) before submitting your app for review.
297
349
 
298
350
  > [!NOTE]
299
351
  >Please make sure to hide the `Add to Google Wallet` buttons when cards are already added to the wallet.
@@ -29,12 +29,17 @@ object Utils {
29
29
  .setPhoneNumber(addressMap.getString("phoneNumber") ?: "")
30
30
  .build()
31
31
 
32
+ val isVirtual = if (hasKey("isVirtualCard")) this.getBoolean("isVirtualCard") else false
33
+ val isBounce = if (hasKey("isBounceProvisioned")) this.getBoolean("isBounceProvisioned") else false
34
+
32
35
  return CardData(
33
36
  network = this.getString("network") ?: "",
34
37
  opaquePaymentCard = this.getString("opaquePaymentCard") ?: "",
35
38
  cardHolderName = this.getString("cardHolderName") ?: "",
36
39
  lastDigits = this.getString("lastDigits") ?: "",
37
- userAddress = userAddress
40
+ userAddress = userAddress,
41
+ isVirtualCard = isVirtual,
42
+ isBounceProvisioned = isBounce,
38
43
  )
39
44
  }
40
45
 
@@ -5,6 +5,15 @@ import android.app.Activity.RESULT_CANCELED
5
5
  import android.app.Activity.RESULT_OK
6
6
  import android.content.ActivityNotFoundException
7
7
  import android.content.Intent
8
+ import androidx.core.content.IntentCompat
9
+ import com.expensify.wallet.Utils.getAsyncResult
10
+ import com.expensify.wallet.Utils.toCardData
11
+ import com.expensify.wallet.error.InvalidNetworkError
12
+ import com.expensify.wallet.event.OnCardActivatedEvent
13
+ import com.expensify.wallet.model.CardData
14
+ import com.expensify.wallet.model.CardStatus
15
+ import com.expensify.wallet.model.TokenizationStatus
16
+ import com.expensify.wallet.model.WalletData
8
17
  import com.facebook.react.bridge.ActivityEventListener
9
18
  import com.facebook.react.bridge.Arguments
10
19
  import com.facebook.react.bridge.Promise
@@ -15,25 +24,35 @@ import com.facebook.react.bridge.ReactMethod
15
24
  import com.facebook.react.bridge.ReadableMap
16
25
  import com.facebook.react.bridge.WritableMap
17
26
  import com.facebook.react.modules.core.DeviceEventManagerModule
27
+ import com.google.android.gms.common.api.ApiException
18
28
  import com.google.android.gms.tapandpay.TapAndPay
19
29
  import com.google.android.gms.tapandpay.TapAndPayClient
30
+ import com.google.android.gms.tapandpay.issuer.GeneratePaymentCredentialsException
31
+ import com.google.android.gms.tapandpay.issuer.GeneratePaymentCredentialsRequest
32
+ import com.google.android.gms.tapandpay.issuer.GeneratePaymentCredentialsResponse
33
+ import com.google.android.gms.tapandpay.issuer.GetTokenStatusRequest
34
+ import com.google.android.gms.tapandpay.issuer.HasEligibleTokenizationTargetRequest
35
+ import com.google.android.gms.tapandpay.issuer.ListTokensRequest
36
+ import com.google.android.gms.tapandpay.issuer.PaymentCredentialsGenerator
37
+ import com.google.android.gms.tapandpay.issuer.PushTokenizeExtraOptions
20
38
  import com.google.android.gms.tapandpay.issuer.PushTokenizeRequest
39
+ import com.google.android.gms.tapandpay.issuer.PushTokenizeResult
40
+ import com.google.android.gms.tapandpay.issuer.TokenizeRequest
41
+ import kotlinx.coroutines.CompletableDeferred
21
42
  import kotlinx.coroutines.CoroutineScope
43
+ import kotlinx.coroutines.CoroutineStart
44
+ import kotlinx.coroutines.Deferred
22
45
  import kotlinx.coroutines.Dispatchers
23
46
  import kotlinx.coroutines.launch
24
47
  import kotlinx.coroutines.SupervisorJob
25
48
  import kotlinx.coroutines.cancel
26
- import com.expensify.wallet.Utils.getAsyncResult
27
- import com.expensify.wallet.Utils.toCardData
28
- import com.expensify.wallet.error.InvalidNetworkError
29
- import com.expensify.wallet.event.OnCardActivatedEvent
30
- import com.expensify.wallet.model.CardStatus
31
- import com.expensify.wallet.model.TokenizationStatus
32
- import com.expensify.wallet.model.WalletData
33
- import com.google.android.gms.common.api.ApiException
34
- import kotlinx.coroutines.Deferred
49
+ import kotlinx.coroutines.withTimeoutOrNull
35
50
  import java.nio.charset.Charset
36
51
  import java.util.Locale
52
+ import java.util.UUID
53
+ import java.util.concurrent.CompletableFuture
54
+ import java.util.concurrent.ConcurrentHashMap
55
+ import java.util.concurrent.Future
37
56
 
38
57
 
39
58
  class WalletModule internal constructor(context: ReactApplicationContext) :
@@ -41,11 +60,14 @@ class WalletModule internal constructor(context: ReactApplicationContext) :
41
60
  companion object {
42
61
  const val NAME = "RNWallet"
43
62
  const val REQUEST_CODE_PUSH_TOKENIZE: Int = 0xA001
63
+ const val REQUEST_CODE_RESUME_TOKENIZE: Int = 0xA003
44
64
  const val REQUEST_CREATE_WALLET: Int = 0xA002
45
65
 
46
66
  const val E_SDK_API = "SDK API Error"
47
67
  const val E_OPERATION_FAILED = "E_OPERATION_FAILED"
48
68
  const val E_INVALID_DATA = "E_INVALID_DATA"
69
+
70
+ const val PAYMENT_CREDENTIALS_TIMEOUT_MS = 60_000L
49
71
  }
50
72
 
51
73
  private val activity: Activity
@@ -57,6 +79,8 @@ class WalletModule internal constructor(context: ReactApplicationContext) :
57
79
  private var pendingPushTokenizePromise: Promise? = null
58
80
  private val moduleScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
59
81
 
82
+ private val pendingPaymentCredentials = ConcurrentHashMap<String, CompletableDeferred<GeneratePaymentCredentialsResponse>>()
83
+
60
84
  override fun initialize() {
61
85
  super.initialize()
62
86
  reactApplicationContext.addActivityEventListener(cardListener)
@@ -66,42 +90,100 @@ class WalletModule internal constructor(context: ReactApplicationContext) :
66
90
  super.invalidate()
67
91
  moduleScope.cancel()
68
92
  reactApplicationContext.removeActivityEventListener(cardListener)
93
+ pendingPaymentCredentials.clear()
69
94
  }
70
95
 
71
96
  private val cardListener = object : ActivityEventListener {
72
97
  override fun onActivityResult(
73
98
  activity: Activity, requestCode: Int, resultCode: Int, data: Intent?
74
99
  ) {
75
- if (requestCode == REQUEST_CREATE_WALLET) {
76
- pendingCreateWalletPromise?.resolve(resultCode == RESULT_OK)
77
- pendingCreateWalletPromise = null
78
- } else if (requestCode == REQUEST_CODE_PUSH_TOKENIZE) {
79
- val localPromise = pendingPushTokenizePromise
80
- pendingPushTokenizePromise = null
81
- if (resultCode == RESULT_OK) {
82
- val tokenId = data?.getStringExtra(TapAndPay.EXTRA_ISSUER_TOKEN_ID)
83
- sendEvent(
84
- context,
85
- OnCardActivatedEvent.NAME,
86
- OnCardActivatedEvent("activated", tokenId).toMap()
87
- )
88
- localPromise?.resolve(TokenizationStatus.SUCCESS.code)
89
- } else if (resultCode == RESULT_CANCELED) {
90
- sendEvent(
91
- context,
92
- OnCardActivatedEvent.NAME,
93
- OnCardActivatedEvent("canceled", null).toMap()
94
- )
95
- localPromise?.resolve(TokenizationStatus.CANCELED.code)
96
- } else {
97
- localPromise?.resolve(TokenizationStatus.ERROR.code)
100
+ when (requestCode) {
101
+ REQUEST_CREATE_WALLET -> {
102
+ pendingCreateWalletPromise?.resolve(resultCode == RESULT_OK)
103
+ pendingCreateWalletPromise = null
98
104
  }
105
+ REQUEST_CODE_RESUME_TOKENIZE -> handleResumeTokenizeResult(resultCode, data)
106
+ REQUEST_CODE_PUSH_TOKENIZE -> handlePushTokenizeResult(resultCode, data)
99
107
  }
100
108
  }
101
109
 
102
110
  override fun onNewIntent(intent: Intent) {}
103
111
  }
104
112
 
113
+ private fun takePendingTokenizePromise(): Promise? =
114
+ pendingPushTokenizePromise.also { pendingPushTokenizePromise = null }
115
+
116
+ private fun sendCardActivatedEvent(status: String, tokenId: String?) {
117
+ sendEvent(reactApplicationContext, OnCardActivatedEvent.NAME, OnCardActivatedEvent(status, tokenId).toMap())
118
+ }
119
+
120
+ private fun handleResumeTokenizeResult(resultCode: Int, data: Intent?) {
121
+ val promise = takePendingTokenizePromise()
122
+ when (resultCode) {
123
+ RESULT_OK -> {
124
+ sendCardActivatedEvent("activated", data?.getStringExtra(TapAndPay.EXTRA_ISSUER_TOKEN_ID))
125
+ promise?.resolve(TokenizationStatus.SUCCESS.code)
126
+ }
127
+ RESULT_CANCELED -> {
128
+ sendCardActivatedEvent("canceled", null)
129
+ promise?.resolve(TokenizationStatus.CANCELED.code)
130
+ }
131
+ else -> promise?.resolve(TokenizationStatus.ERROR.code)
132
+ }
133
+ }
134
+
135
+ private fun handlePushTokenizeResult(resultCode: Int, data: Intent?) {
136
+ val promise = takePendingTokenizePromise()
137
+ if (resultCode == RESULT_CANCELED) {
138
+ sendCardActivatedEvent("canceled", null)
139
+ promise?.resolve(TokenizationStatus.CANCELED.code)
140
+ return
141
+ }
142
+
143
+ val result = data?.let {
144
+ IntentCompat.getParcelableExtra(it, TapAndPay.EXTRA_PUSH_TOKENIZE_RESULT, PushTokenizeResult::class.java)
145
+ }
146
+
147
+ if (result == null) {
148
+ handlePushTokenizeResultExtras(resultCode, data, promise)
149
+ return
150
+ }
151
+
152
+ val successfulOutcome = result.tokenizationOutcomes.firstOrNull { it.tokenResult }
153
+ if (result.cardResult || successfulOutcome != null) {
154
+ sendCardActivatedEvent("activated", successfulOutcome?.issuerTokenId)
155
+ promise?.resolve(TokenizationStatus.SUCCESS.code)
156
+ } else {
157
+ promise?.reject(E_OPERATION_FAILED, "Card not saved. Status: ${result.cardStatus}")
158
+ }
159
+ }
160
+
161
+ // Google documents the result both as PushTokenizeResult and as separate extras, so read the extras when the object is missing
162
+ private fun handlePushTokenizeResultExtras(resultCode: Int, data: Intent?, promise: Promise?) {
163
+ val hasTokenResult = data?.hasExtra(TapAndPay.EXTRA_TOKEN_RESULT) == true
164
+ val hasCardResult = data?.hasExtra(TapAndPay.EXTRA_CARD_RESULT) == true
165
+
166
+ if (!hasTokenResult && !hasCardResult) {
167
+ if (resultCode == RESULT_OK) {
168
+ sendCardActivatedEvent("activated", data?.getStringExtra(TapAndPay.EXTRA_ISSUER_TOKEN_ID))
169
+ promise?.resolve(TokenizationStatus.SUCCESS.code)
170
+ } else {
171
+ promise?.resolve(TokenizationStatus.ERROR.code)
172
+ }
173
+ return
174
+ }
175
+
176
+ val tokenResult = data?.getBooleanExtra(TapAndPay.EXTRA_TOKEN_RESULT, false) == true
177
+ val cardResult = data?.getBooleanExtra(TapAndPay.EXTRA_CARD_RESULT, false) == true
178
+ if (tokenResult || cardResult) {
179
+ val tokenId = if (tokenResult) data?.getStringExtra(TapAndPay.EXTRA_ISSUER_TOKEN_ID) else null
180
+ sendCardActivatedEvent("activated", tokenId)
181
+ promise?.resolve(TokenizationStatus.SUCCESS.code)
182
+ } else {
183
+ promise?.reject(E_OPERATION_FAILED, "Card not saved")
184
+ }
185
+ }
186
+
105
187
  @ReactMethod
106
188
  override fun ensureGoogleWalletInitialized(promise: Promise) {
107
189
  val localPromise = PromiseImpl({ _ ->
@@ -147,7 +229,7 @@ class WalletModule internal constructor(context: ReactApplicationContext) :
147
229
 
148
230
  @ReactMethod
149
231
  override fun getCardStatusBySuffix(last4Digits: String, promise: Promise) {
150
- tapAndPayClient.listTokens()
232
+ tapAndPayClient.listTokens(ListTokensRequest.Builder().build())
151
233
  .addOnCompleteListener { task ->
152
234
  if (!task.isSuccessful || task.result == null) {
153
235
  promise.resolve(CardStatus.NOT_FOUND_IN_WALLET.code)
@@ -166,7 +248,12 @@ class WalletModule internal constructor(context: ReactApplicationContext) :
166
248
 
167
249
  @ReactMethod
168
250
  override fun getCardStatusByIdentifier(identifier: String, tsp: String, promise: Promise) {
169
- tapAndPayClient.getTokenStatus(getTokenServiceProvider(tsp), identifier)
251
+ tapAndPayClient.getTokenStatus(
252
+ GetTokenStatusRequest.Builder()
253
+ .setTokenServiceProvider(getTokenServiceProvider(tsp))
254
+ .setIssuerTokenId(identifier)
255
+ .build()
256
+ )
170
257
  .addOnCompleteListener { task ->
171
258
  if (!task.isSuccessful || task.result == null) {
172
259
  promise.resolve(CardStatus.NOT_FOUND_IN_WALLET.code)
@@ -183,6 +270,25 @@ class WalletModule internal constructor(context: ReactApplicationContext) :
183
270
  }
184
271
  }
185
272
 
273
+ @ReactMethod
274
+ override fun hasEligibleTokenizationTarget(last4Digits: String, network: String, issuerName: String, promise: Promise) {
275
+ try {
276
+ val request = HasEligibleTokenizationTargetRequest.Builder()
277
+ .setIdentifier(last4Digits)
278
+ .setNetwork(getCardNetwork(network))
279
+ .setTokenServiceProvider(getTokenServiceProvider(network))
280
+ .setIssuerName(issuerName)
281
+ .build()
282
+ tapAndPayClient.hasEligibleTokenizationTarget(request)
283
+ .addOnSuccessListener { promise.resolve(it) }
284
+ .addOnFailureListener { e ->
285
+ promise.reject(E_OPERATION_FAILED, "hasEligibleTokenizationTarget: ${e.localizedMessage}")
286
+ }
287
+ } catch (e: InvalidNetworkError) {
288
+ promise.reject(E_INVALID_DATA, e.message)
289
+ }
290
+ }
291
+
186
292
  @ReactMethod
187
293
  override fun addCardToGoogleWallet(
188
294
  data: ReadableMap, promise: Promise
@@ -197,6 +303,11 @@ class WalletModule internal constructor(context: ReactApplicationContext) :
197
303
  val displayName = getDisplayName(data, cardData.network)
198
304
  pendingPushTokenizePromise = promise
199
305
 
306
+ val pushTokenizeExtraOptions = PushTokenizeExtraOptions.newBuilder()
307
+ .setIsBounceProvisioned(cardData.isBounceProvisioned)
308
+ .setEnrollForVirtualCards(cardData.isVirtualCard)
309
+ .build()
310
+
200
311
  val pushTokenizeRequest = PushTokenizeRequest.Builder()
201
312
  .setOpaquePaymentCard(cardData.opaquePaymentCard.toByteArray(Charset.forName("UTF-8")))
202
313
  .setNetwork(cardNetwork)
@@ -204,17 +315,130 @@ class WalletModule internal constructor(context: ReactApplicationContext) :
204
315
  .setDisplayName(displayName)
205
316
  .setLastDigits(cardData.lastDigits)
206
317
  .setUserAddress(cardData.userAddress)
318
+ .setPaymentCredentialsGenerator(createPaymentCredentialsGenerator(cardData))
319
+ .setPushTokenizeExtraOptions(pushTokenizeExtraOptions)
207
320
  .build()
208
321
 
209
- tapAndPayClient.pushTokenize(
210
- activity, pushTokenizeRequest, REQUEST_CODE_PUSH_TOKENIZE
211
- )
322
+ tapAndPayClient.pushTokenize(pushTokenizeRequest)
323
+ .addOnSuccessListener { pendingIntent ->
324
+ try {
325
+ activity.startIntentSenderForResult(
326
+ pendingIntent.intentSender,
327
+ REQUEST_CODE_PUSH_TOKENIZE,
328
+ null, 0, 0, 0
329
+ )
330
+ } catch (e: Exception) {
331
+ pendingPushTokenizePromise = null
332
+ promise.reject(E_OPERATION_FAILED, "Failed to launch Google Pay: ${e.message}")
333
+ }
334
+ }
335
+ .addOnFailureListener { e ->
336
+ pendingPushTokenizePromise = null
337
+ promise.reject(E_OPERATION_FAILED, "Google Pay API Error: ${e.message}")
338
+ }
212
339
  } catch (e: java.lang.Exception) {
213
340
  pendingPushTokenizePromise = null
214
341
  promise.reject(e)
215
342
  }
216
343
  }
217
344
 
345
+ // Google Wallet only understands GeneratePaymentCredentialsException; UNKNOWN_ERROR covers backend failures and timeouts
346
+ private fun paymentCredentialsError() =
347
+ GeneratePaymentCredentialsException(GeneratePaymentCredentialsException.UNKNOWN_ERROR)
348
+
349
+ private fun createPaymentCredentialsGenerator(
350
+ cardData: CardData
351
+ ): PaymentCredentialsGenerator {
352
+ return object : PaymentCredentialsGenerator {
353
+ override fun generate(request: GeneratePaymentCredentialsRequest): Future<GeneratePaymentCredentialsResponse> {
354
+ if (!request.googleOpaquePaymentCardRequested) {
355
+ val response = GeneratePaymentCredentialsResponse.Builder()
356
+ .setOpaquePaymentCard(cardData.opaquePaymentCard.toByteArray(Charsets.UTF_8))
357
+ .build()
358
+
359
+ return CompletableFuture.completedFuture(response)
360
+ }
361
+
362
+ val future = CompletableFuture<GeneratePaymentCredentialsResponse>()
363
+ val credentials = CompletableDeferred<GeneratePaymentCredentialsResponse>()
364
+ val requestId = UUID.randomUUID().toString()
365
+ pendingPaymentCredentials[requestId] = credentials
366
+ moduleScope.launch(start = CoroutineStart.UNDISPATCHED) {
367
+ // null on timeout, on reject, or when invalidate() cancels the scope
368
+ val response = runCatching {
369
+ withTimeoutOrNull(PAYMENT_CREDENTIALS_TIMEOUT_MS) { credentials.await() }
370
+ }.getOrNull()
371
+ pendingPaymentCredentials.remove(requestId)
372
+ if (response != null) {
373
+ future.complete(response)
374
+ } else {
375
+ future.completeExceptionally(paymentCredentialsError())
376
+ }
377
+ }
378
+
379
+ val params = Arguments.createMap().apply {
380
+ putString("requestId", requestId)
381
+ putString("serverSessionId", request.serverSessionId)
382
+ putString("walletId", request.walletId)
383
+ putString("tokenRequestorId", request.tokenRequestorId)
384
+ putString("opaquePaymentCard", cardData.opaquePaymentCard)
385
+ }
386
+
387
+ // send event to the RN so the Google OPC can be generated on the backend
388
+ sendEvent(reactApplicationContext, "onPaymentCredentialsRequest", params)
389
+ return future
390
+ }
391
+
392
+ // This switch enables the UAPP flow
393
+ override fun getGoogleOpaquePaymentCardSupported(): Boolean {
394
+ return true
395
+ }
396
+ }
397
+ }
398
+
399
+ @ReactMethod
400
+ override fun AndroidProvidePaymentCredentials(requestId: String, responseData: ReadableMap, promise: Promise) {
401
+ val credentials = pendingPaymentCredentials.remove(requestId)
402
+ if (credentials == null) {
403
+ promise.reject(E_OPERATION_FAILED, "Request ID not found or timed out")
404
+ return
405
+ }
406
+
407
+ try {
408
+ val tspOpc = responseData.getString("opaquePaymentCard")
409
+ val googleOpc = responseData.getString("googleOpaquePaymentCard")
410
+
411
+ if (tspOpc == null) {
412
+ throw Exception("opaquePaymentCard is required")
413
+ }
414
+ if (googleOpc == null) {
415
+ throw Exception("googleOpaquePaymentCard is required")
416
+ }
417
+ val response = GeneratePaymentCredentialsResponse.Builder()
418
+ .setGoogleOpaquePaymentCard(googleOpc.toByteArray(Charsets.UTF_8))
419
+ .setOpaquePaymentCard(tspOpc.toByteArray(Charsets.UTF_8))
420
+ .build()
421
+
422
+ credentials.complete(response)
423
+ promise.resolve(true)
424
+
425
+ } catch (e: Exception) {
426
+ credentials.completeExceptionally(paymentCredentialsError())
427
+ promise.reject(E_OPERATION_FAILED, e.message)
428
+ }
429
+ }
430
+
431
+ @ReactMethod
432
+ override fun AndroidRejectPaymentCredentials(requestId: String, errorMessage: String, promise: Promise) {
433
+ val credentials = pendingPaymentCredentials.remove(requestId)
434
+ if (credentials == null) {
435
+ promise.reject(E_OPERATION_FAILED, "Request ID not found or timed out")
436
+ return
437
+ }
438
+ credentials.completeExceptionally(paymentCredentialsError())
439
+ promise.resolve(true)
440
+ }
441
+
218
442
  @ReactMethod
219
443
  override fun resumeAddCardToGoogleWallet(data: ReadableMap, promise: Promise) {
220
444
  if (pendingPushTokenizePromise != null) {
@@ -232,14 +456,13 @@ class WalletModule internal constructor(context: ReactApplicationContext) :
232
456
  val displayName = getDisplayName(data, network)
233
457
  pendingPushTokenizePromise = promise
234
458
 
235
- tapAndPayClient.tokenize(
236
- activity,
237
- tokenReferenceID,
238
- tokenServiceProvider,
239
- displayName,
240
- cardNetwork,
241
- REQUEST_CODE_PUSH_TOKENIZE
242
- )
459
+ val tokenizeRequest = TokenizeRequest.Builder()
460
+ .setIssuerTokenId(tokenReferenceID)
461
+ .setTokenServiceProvider(tokenServiceProvider)
462
+ .setCardDisplayName(displayName)
463
+ .setCardNetwork(cardNetwork)
464
+ .build()
465
+ tapAndPayClient.tokenize(activity, tokenizeRequest, REQUEST_CODE_RESUME_TOKENIZE)
243
466
  } catch (e: java.lang.Exception) {
244
467
  pendingPushTokenizePromise = null
245
468
  promise.reject(e)
@@ -248,13 +471,13 @@ class WalletModule internal constructor(context: ReactApplicationContext) :
248
471
 
249
472
  @ReactMethod
250
473
  override fun listTokens(promise: Promise) {
251
- tapAndPayClient.listTokens()
474
+ tapAndPayClient.listTokens(ListTokensRequest.Builder().build())
252
475
  .addOnCompleteListener { task ->
253
476
  if (!task.isSuccessful || task.result == null) {
254
477
  promise.resolve(Arguments.createArray())
255
478
  return@addOnCompleteListener
256
479
  }
257
-
480
+
258
481
  val tokensArray = Arguments.createArray()
259
482
  task.result.forEach { tokenInfo ->
260
483
  val tokenData = Arguments.createMap().apply {
@@ -264,7 +487,7 @@ class WalletModule internal constructor(context: ReactApplicationContext) :
264
487
  }
265
488
  tokensArray.pushMap(tokenData)
266
489
  }
267
-
490
+
268
491
  promise.resolve(tokensArray)
269
492
  }
270
493
  .addOnFailureListener { e ->
@@ -341,13 +564,13 @@ class WalletModule internal constructor(context: ReactApplicationContext) :
341
564
  data.getString("cardHolderName")?.let { name ->
342
565
  if (name.isNotEmpty()) return name
343
566
  }
344
-
567
+
345
568
  data.getString("lastDigits")?.let { digits ->
346
569
  if (digits.isNotEmpty()) {
347
570
  return "${network.uppercase(Locale.getDefault())} Card *$digits"
348
571
  }
349
572
  }
350
-
573
+
351
574
  return "${network.uppercase(Locale.getDefault())} Card"
352
575
  }
353
576
 
@@ -5,8 +5,10 @@ import com.google.android.gms.tapandpay.issuer.UserAddress
5
5
  data class CardData(
6
6
  val platform: String = "android",
7
7
  val network: String,
8
- val opaquePaymentCard: String,
8
+ val opaquePaymentCard: String, // TSP OPC
9
9
  val cardHolderName: String,
10
10
  val lastDigits: String,
11
11
  val userAddress: UserAddress,
12
+ val isVirtualCard: Boolean = false,
13
+ val isBounceProvisioned: Boolean = false,
12
14
  )
@@ -57,6 +57,14 @@ public abstract class NativeWalletSpec extends ReactContextBaseJavaModule implem
57
57
  @DoNotStrip
58
58
  public abstract void addCardToGoogleWallet(ReadableMap cardData, Promise promise);
59
59
 
60
+ @ReactMethod
61
+ @DoNotStrip
62
+ public abstract void AndroidProvidePaymentCredentials(String requestId, ReadableMap responseData, Promise promise);
63
+
64
+ @ReactMethod
65
+ @DoNotStrip
66
+ public abstract void AndroidRejectPaymentCredentials(String requestId, String errorMessage, Promise promise);
67
+
60
68
  @ReactMethod
61
69
  @DoNotStrip
62
70
  public abstract void resumeAddCardToGoogleWallet(ReadableMap cardData, Promise promise);
package/ios/RNWallet.mm CHANGED
@@ -135,6 +135,36 @@ RCT_REMAP_METHOD(getCardStatusByIdentifier,
135
135
  // no-op
136
136
  }
137
137
 
138
+ - (void)hasEligibleTokenizationTarget:(NSString *)last4Digits
139
+ network:(NSString *)network
140
+ issuerName:(NSString *)issuerName
141
+ resolve:(RCTPromiseResolveBlock)resolve
142
+ reject:(RCTPromiseRejectBlock)reject
143
+ {
144
+ // no-op
145
+ }
146
+
147
+ - (void)AndroidProvidePaymentCredentials:(NSString *)requestId
148
+ responseData:
149
+ #ifdef RCT_NEW_ARCH_ENABLED
150
+ (JS::NativeWallet::AndroidPaymentCredentialsResponse &)responseData
151
+ #else
152
+ (NSDictionary *)responseData
153
+ #endif
154
+ resolve:(RCTPromiseResolveBlock)resolve
155
+ reject:(RCTPromiseRejectBlock)reject
156
+ {
157
+ // no-op
158
+ }
159
+
160
+ - (void)AndroidRejectPaymentCredentials:(NSString *)requestId
161
+ errorMessage:(NSString *)errorMessage
162
+ resolve:(RCTPromiseResolveBlock)resolve
163
+ reject:(RCTPromiseRejectBlock)reject
164
+ {
165
+ // no-op
166
+ }
167
+
138
168
  - (void)getSecureWalletInfo:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
139
169
  // no-op
140
170
  }
@@ -1 +1 @@
1
- {"version":3,"names":["_reactNative","require","PACKAGE_NAME","exports","Wallet","TurboModuleRegistry","getEnforcing","error","Error","console","warn","message","_default","default"],"sourceRoot":"../../src","sources":["NativeWallet.ts"],"mappings":";;;;;;AACA,IAAAA,YAAA,GAAAC,OAAA;AAqFA,MAAMC,YAAY,GAAAC,OAAA,CAAAD,YAAA,GAAG,gCAAgC;AACrD;AACA;AACA;AACA,IAAIE,MAAwB;AAC5B,IAAI;EACFA,MAAM,GAAGC,gCAAmB,CAACC,YAAY,CAAO,UAAU,CAAC;AAC7D,CAAC,CAAC,OAAOC,KAAK,EAAE;EACd,IAAIA,KAAK,YAAYC,KAAK,EAAE;IAC1B;IACAC,OAAO,CAACC,IAAI,CAAC,IAAIR,YAAY,mCAAmCK,KAAK,CAACI,OAAO,EAAE,CAAC;EAClF;AACF;AAAC,IAAAC,QAAA,GAAAT,OAAA,CAAAU,OAAA,GACcT,MAAM","ignoreList":[]}
1
+ {"version":3,"names":["_reactNative","require","PACKAGE_NAME","exports","Wallet","TurboModuleRegistry","getEnforcing","error","Error","console","warn","message","_default","default"],"sourceRoot":"../../src","sources":["NativeWallet.ts"],"mappings":";;;;;;AACA,IAAAA,YAAA,GAAAC,OAAA;AAuGA,MAAMC,YAAY,GAAAC,OAAA,CAAAD,YAAA,GAAG,gCAAgC;AACrD;AACA;AACA;AACA,IAAIE,MAAwB;AAC5B,IAAI;EACFA,MAAM,GAAGC,gCAAmB,CAACC,YAAY,CAAO,UAAU,CAAC;AAC7D,CAAC,CAAC,OAAOC,KAAK,EAAE;EACd,IAAIA,KAAK,YAAYC,KAAK,EAAE;IAC1B;IACAC,OAAO,CAACC,IAAI,CAAC,IAAIR,YAAY,mCAAmCK,KAAK,CAACI,OAAO,EAAE,CAAC;EAClF;AACF;AAAC,IAAAC,QAAA,GAAAT,OAAA,CAAAU,OAAA,GACcT,MAAM","ignoreList":[]}
@@ -16,6 +16,7 @@ exports.checkWalletAvailability = checkWalletAvailability;
16
16
  exports.getCardStatusByIdentifier = getCardStatusByIdentifier;
17
17
  exports.getCardStatusBySuffix = getCardStatusBySuffix;
18
18
  exports.getSecureWalletInfo = getSecureWalletInfo;
19
+ exports.hasEligibleTokenizationTarget = hasEligibleTokenizationTarget;
19
20
  exports.listTokens = listTokens;
20
21
  exports.removeListener = removeListener;
21
22
  exports.resumeAddCardToGoogleWallet = resumeAddCardToGoogleWallet;
@@ -25,12 +26,31 @@ var _utils = require("./utils");
25
26
  var _AddToWalletButton = _interopRequireDefault(require("./AddToWalletButton"));
26
27
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
27
28
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
29
+ /* eslint-disable no-console */
28
30
  /* eslint-disable @lwc/lwc/no-async-await */
29
31
 
30
32
  function getModuleLinkingRejection() {
31
33
  return Promise.reject(new Error(`Failed to load Wallet module, make sure to link ${_NativeWallet.PACKAGE_NAME} correctly`));
32
34
  }
33
35
  let eventEmitter;
36
+ let paymentCredentialsHandler = null;
37
+ if (_reactNative.Platform.OS === 'android' && _NativeWallet.default) {
38
+ eventEmitter ??= new _reactNative.NativeEventEmitter(_NativeWallet.default);
39
+ eventEmitter.addListener('onPaymentCredentialsRequest', async data => {
40
+ if (!paymentCredentialsHandler) {
41
+ console.warn(`[${_NativeWallet.PACKAGE_NAME}] Received payment credentials request but no handler is set`);
42
+ await (_NativeWallet.default === null || _NativeWallet.default === void 0 ? void 0 : _NativeWallet.default.AndroidRejectPaymentCredentials(data.requestId, 'No payment credentials handler is set').catch(() => undefined));
43
+ return;
44
+ }
45
+ try {
46
+ const responseData = await paymentCredentialsHandler(data);
47
+ await (_NativeWallet.default === null || _NativeWallet.default === void 0 ? void 0 : _NativeWallet.default.AndroidProvidePaymentCredentials(data.requestId, responseData));
48
+ } catch (error) {
49
+ console.error(`[${_NativeWallet.PACKAGE_NAME}] Error handling payment credentials request:`, error);
50
+ await (_NativeWallet.default === null || _NativeWallet.default === void 0 ? void 0 : _NativeWallet.default.AndroidRejectPaymentCredentials(data.requestId, error instanceof Error ? error.message : String(error)).catch(() => undefined));
51
+ }
52
+ });
53
+ }
34
54
  function addListener(event, callback) {
35
55
  if (!_NativeWallet.default) {
36
56
  // eslint-disable-next-line no-console
@@ -85,7 +105,25 @@ async function getCardStatusByIdentifier(identifier, tsp) {
85
105
  const tokenState = await _NativeWallet.default.getCardStatusByIdentifier(identifier, tsp.toUpperCase());
86
106
  return (0, _utils.getCardState)(tokenState);
87
107
  }
88
- async function addCardToGoogleWallet(cardData) {
108
+
109
+ /**
110
+ * Checks whether the card can still be added to a Google Wallet target: the phone or a paired wearable.
111
+ * Use it to decide whether to show the "Add to Google Wallet" button when wearables are supported.
112
+ * @param last4Digits - The last 4 digits of the card number (FPAN, not the token)
113
+ * @param network - The card network, e.g. `VISA`, `MASTERCARD`
114
+ * @param issuerName - The issuer name used for matching, as in the token metadata (not the card display name)
115
+ * @returns `true` if at least one target can still receive the card
116
+ */
117
+ async function hasEligibleTokenizationTarget(last4Digits, network, issuerName) {
118
+ if (_reactNative.Platform.OS === 'ios') {
119
+ throw new Error('hasEligibleTokenizationTarget is not available on iOS');
120
+ }
121
+ if (!_NativeWallet.default) {
122
+ return getModuleLinkingRejection();
123
+ }
124
+ return _NativeWallet.default.hasEligibleTokenizationTarget(last4Digits, network.toUpperCase(), issuerName);
125
+ }
126
+ async function addCardToGoogleWallet(cardData, handlePaymentCredentialsGeneration) {
89
127
  if (_reactNative.Platform.OS === 'ios') {
90
128
  throw new Error('addCardToGoogleWallet is not available on iOS');
91
129
  }
@@ -96,8 +134,13 @@ async function addCardToGoogleWallet(cardData) {
96
134
  if (!isWalletInitialized) {
97
135
  throw new Error('Wallet could not be initialized');
98
136
  }
99
- const tokenizationStatus = await _NativeWallet.default.addCardToGoogleWallet(cardData);
100
- return (0, _utils.getTokenizationStatus)(tokenizationStatus);
137
+ paymentCredentialsHandler = handlePaymentCredentialsGeneration;
138
+ try {
139
+ const tokenizationStatus = await _NativeWallet.default.addCardToGoogleWallet(cardData);
140
+ return (0, _utils.getTokenizationStatus)(tokenizationStatus);
141
+ } finally {
142
+ paymentCredentialsHandler = null;
143
+ }
101
144
  }
102
145
  async function resumeAddCardToGoogleWallet(cardData) {
103
146
  if (_reactNative.Platform.OS === 'ios') {
@@ -1 +1 @@
1
- {"version":3,"names":["_reactNative","require","_NativeWallet","_interopRequireWildcard","_utils","_AddToWalletButton","_interopRequireDefault","e","__esModule","default","t","WeakMap","r","n","o","i","f","__proto__","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","getModuleLinkingRejection","Promise","reject","Error","PACKAGE_NAME","eventEmitter","addListener","event","callback","Wallet","console","warn","remove","undefined","NativeEventEmitter","removeListener","subscription","checkWalletAvailability","getSecureWalletInfo","Platform","OS","isWalletInitialized","ensureGoogleWalletInitialized","getCardStatusBySuffix","last4Digits","cardState","getCardState","getCardStatusByIdentifier","identifier","tsp","tokenState","toUpperCase","addCardToGoogleWallet","cardData","tokenizationStatus","getTokenizationStatus","resumeAddCardToGoogleWallet","listTokens","resolve","addCardToAppleWallet","issuerEncryptPayloadCallback","wallet","passData","IOSPresentAddPaymentPassView","status","addPaymentPassToWallet","paymentPassData","responseData","nonce","nonceSignature","certificates","response","IOSHandleAddPaymentPassResponse"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;;;;;;;;;;;;;;;;;;;;AACA,IAAAA,YAAA,GAAAC,OAAA;AAEA,IAAAC,aAAA,GAAAC,uBAAA,CAAAF,OAAA;AAaA,IAAAG,MAAA,GAAAH,OAAA;AACA,IAAAI,kBAAA,GAAAC,sBAAA,CAAAL,OAAA;AAAoD,SAAAK,uBAAAC,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAAA,SAAAJ,wBAAAI,CAAA,EAAAG,CAAA,6BAAAC,OAAA,MAAAC,CAAA,OAAAD,OAAA,IAAAE,CAAA,OAAAF,OAAA,YAAAR,uBAAA,YAAAA,CAAAI,CAAA,EAAAG,CAAA,SAAAA,CAAA,IAAAH,CAAA,IAAAA,CAAA,CAAAC,UAAA,SAAAD,CAAA,MAAAO,CAAA,EAAAC,CAAA,EAAAC,CAAA,KAAAC,SAAA,QAAAR,OAAA,EAAAF,CAAA,iBAAAA,CAAA,uBAAAA,CAAA,yBAAAA,CAAA,SAAAS,CAAA,MAAAF,CAAA,GAAAJ,CAAA,GAAAG,CAAA,GAAAD,CAAA,QAAAE,CAAA,CAAAI,GAAA,CAAAX,CAAA,UAAAO,CAAA,CAAAK,GAAA,CAAAZ,CAAA,GAAAO,CAAA,CAAAM,GAAA,CAAAb,CAAA,EAAAS,CAAA,gBAAAN,CAAA,IAAAH,CAAA,gBAAAG,CAAA,OAAAW,cAAA,CAAAC,IAAA,CAAAf,CAAA,EAAAG,CAAA,OAAAK,CAAA,IAAAD,CAAA,GAAAS,MAAA,CAAAC,cAAA,KAAAD,MAAA,CAAAE,wBAAA,CAAAlB,CAAA,EAAAG,CAAA,OAAAK,CAAA,CAAAI,GAAA,IAAAJ,CAAA,CAAAK,GAAA,IAAAN,CAAA,CAAAE,CAAA,EAAAN,CAAA,EAAAK,CAAA,IAAAC,CAAA,CAAAN,CAAA,IAAAH,CAAA,CAAAG,CAAA,WAAAM,CAAA,KAAAT,CAAA,EAAAG,CAAA;AAjBpD;;AAmBA,SAASgB,yBAAyBA,CAAA,EAAG;EACnC,OAAOC,OAAO,CAACC,MAAM,CAAC,IAAIC,KAAK,CAAC,mDAAmDC,0BAAY,YAAY,CAAC,CAAC;AAC/G;AAEA,IAAIC,YAA4C;AAEhD,SAASC,WAAWA,CAACC,KAAa,EAAEC,QAAgD,EAAuB;EACzG,IAAI,CAACC,qBAAM,EAAE;IACX;IACAC,OAAO,CAACC,IAAI,CAAC,IAAIP,0BAAY,0DAA0D,CAAC;IACxF,OAAO;MAACQ,MAAM,EAAEA,CAAA,KAAMC;IAAS,CAAC;EAClC;EACAR,YAAY,KAAK,IAAIS,+BAAkB,CAACL,qBAAM,CAAC;EAC/C,OAAOJ,YAAY,CAACC,WAAW,CAACC,KAAK,EAAEC,QAAQ,CAAC;AAClD;AAEA,SAASO,cAAcA,CAACC,YAAiC,EAAQ;EAC/DA,YAAY,CAACJ,MAAM,CAAC,CAAC;AACvB;AAEA,SAASK,uBAAuBA,CAAA,EAAqB;EACnD,IAAI,CAACR,qBAAM,EAAE;IACX,OAAOT,yBAAyB,CAAC,CAAC;EACpC;EACA,OAAOS,qBAAM,CAACQ,uBAAuB,CAAC,CAAC;AACzC;AAEA,eAAeC,mBAAmBA,CAAA,EAA+B;EAC/D,IAAIC,qBAAQ,CAACC,EAAE,KAAK,KAAK,EAAE;IACzB,MAAM,IAAIjB,KAAK,CAAC,6CAA6C,CAAC;EAChE;EAEA,IAAI,CAACM,qBAAM,EAAE;IACX,OAAOT,yBAAyB,CAAC,CAAC;EACpC;EACA,MAAMqB,mBAAmB,GAAG,MAAMZ,qBAAM,CAACa,6BAA6B,CAAC,CAAC;EACxE,IAAI,CAACD,mBAAmB,EAAE;IACxB,MAAM,IAAIlB,KAAK,CAAC,iCAAiC,CAAC;EACpD;EAEA,OAAOM,qBAAM,CAACS,mBAAmB,CAAC,CAAC;AACrC;AAEA,eAAeK,qBAAqBA,CAACC,WAAmB,EAAuB;EAC7E,IAAI,CAACf,qBAAM,EAAE;IACX,OAAOT,yBAAyB,CAAC,CAAC;EACpC;EAEA,MAAMyB,SAAS,GAAG,MAAMhB,qBAAM,CAACc,qBAAqB,CAACC,WAAW,CAAC;EACjE,OAAO,IAAAE,mBAAY,EAACD,SAAS,CAAC;AAChC;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,eAAeE,yBAAyBA,CAACC,UAAkB,EAAEC,GAAW,EAAuB;EAC7F,IAAI,CAACpB,qBAAM,EAAE;IACX,OAAOT,yBAAyB,CAAC,CAAC;EACpC;EAEA,MAAM8B,UAAU,GAAG,MAAMrB,qBAAM,CAACkB,yBAAyB,CAACC,UAAU,EAAEC,GAAG,CAACE,WAAW,CAAC,CAAC,CAAC;EACxF,OAAO,IAAAL,mBAAY,EAACI,UAAU,CAAC;AACjC;AAEA,eAAeE,qBAAqBA,CAACC,QAAyB,EAA+B;EAC3F,IAAId,qBAAQ,CAACC,EAAE,KAAK,KAAK,EAAE;IACzB,MAAM,IAAIjB,KAAK,CAAC,+CAA+C,CAAC;EAClE;EAEA,IAAI,CAACM,qBAAM,EAAE;IACX,OAAOT,yBAAyB,CAAC,CAAC;EACpC;EACA,MAAMqB,mBAAmB,GAAG,MAAMZ,qBAAM,CAACa,6BAA6B,CAAC,CAAC;EACxE,IAAI,CAACD,mBAAmB,EAAE;IACxB,MAAM,IAAIlB,KAAK,CAAC,iCAAiC,CAAC;EACpD;EACA,MAAM+B,kBAAkB,GAAG,MAAMzB,qBAAM,CAACuB,qBAAqB,CAACC,QAAQ,CAAC;EACvE,OAAO,IAAAE,4BAAqB,EAACD,kBAAkB,CAAC;AAClD;AAEA,eAAeE,2BAA2BA,CAACH,QAA+B,EAA+B;EACvG,IAAId,qBAAQ,CAACC,EAAE,KAAK,KAAK,EAAE;IACzB,MAAM,IAAIjB,KAAK,CAAC,qDAAqD,CAAC;EACxE;EAEA,IAAI,CAACM,qBAAM,EAAE;IACX,OAAOT,yBAAyB,CAAC,CAAC;EACpC;EACA,MAAMqB,mBAAmB,GAAG,MAAMZ,qBAAM,CAACa,6BAA6B,CAAC,CAAC;EACxE,IAAI,CAACD,mBAAmB,EAAE;IACxB,MAAM,IAAIlB,KAAK,CAAC,iCAAiC,CAAC;EACpD;EACA,MAAM+B,kBAAkB,GAAG,MAAMzB,qBAAM,CAAC2B,2BAA2B,CAACH,QAAQ,CAAC;EAC7E,OAAO,IAAAE,4BAAqB,EAACD,kBAAkB,CAAC;AAClD;AAEA,eAAeG,UAAUA,CAAA,EAAyB;EAChD,IAAIlB,qBAAQ,CAACC,EAAE,KAAK,KAAK,EAAE;IACzB,OAAOnB,OAAO,CAACqC,OAAO,CAAC,EAAE,CAAC;EAC5B;EAEA,IAAI,CAAC7B,qBAAM,EAAE;IACX,OAAOT,yBAAyB,CAAC,CAAC;EACpC;EACA,MAAMqB,mBAAmB,GAAG,MAAMZ,qBAAM,CAACa,6BAA6B,CAAC,CAAC;EACxE,IAAI,CAACD,mBAAmB,EAAE;IACxB,MAAM,IAAIlB,KAAK,CAAC,iCAAiC,CAAC;EACpD;EACA,OAAOM,qBAAM,CAAC4B,UAAU,CAAC,CAAC;AAC5B;AAEA,eAAeE,oBAAoBA,CACjCN,QAAqB,EACrBO,4BAA0H,EAC7F;EAC7B,IAAIrB,qBAAQ,CAACC,EAAE,KAAK,SAAS,EAAE;IAC7B,MAAM,IAAIjB,KAAK,CAAC,kDAAkD,CAAC;EACrE;EAEA,IAAI,CAACM,qBAAM,EAAE;IACX,OAAOT,yBAAyB,CAAC,CAAC;EACpC;EACA,MAAMyC,MAAM,GAAGhC,qBAAM;EAErB,MAAMiC,QAAQ,GAAG,MAAMD,MAAM,CAACE,4BAA4B,CAACV,QAAQ,CAAC;EAEpE,IAAI,CAACS,QAAQ,IAAIA,QAAQ,CAACE,MAAM,KAAK,CAAC,EAAE;IACtC,OAAO,IAAAT,4BAAqB,EAAC,CAAAO,QAAQ,aAARA,QAAQ,uBAARA,QAAQ,CAAEE,MAAM,KAAI,CAAC,CAAC,CAAC;EACtD;EAEA,eAAeC,sBAAsBA,CAACC,eAAsC,EAAmB;IAC7F,MAAMC,YAAY,GAAG,MAAMP,4BAA4B,CAACM,eAAe,CAACE,KAAK,EAAEF,eAAe,CAACG,cAAc,EAAEH,eAAe,CAACI,YAAY,CAAC;IAC5I,MAAMC,QAAQ,GAAG,MAAMV,MAAM,CAACW,+BAA+B,CAACL,YAAY,CAAC;IAC3E;IACA;IACA,IAAII,QAAQ,EAAE;MACZ,OAAON,sBAAsB,CAACM,QAAQ,CAAC;IACzC;IACA,OAAO,CAAC;EACV;EACA,MAAMP,MAAM,GAAG,MAAMC,sBAAsB,CAACH,QAAQ,CAAC;EACrD,OAAO,IAAAP,4BAAqB,EAACS,MAAM,CAAC;AACtC","ignoreList":[]}
1
+ {"version":3,"names":["_reactNative","require","_NativeWallet","_interopRequireWildcard","_utils","_AddToWalletButton","_interopRequireDefault","e","__esModule","default","t","WeakMap","r","n","o","i","f","__proto__","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","getModuleLinkingRejection","Promise","reject","Error","PACKAGE_NAME","eventEmitter","paymentCredentialsHandler","Platform","OS","Wallet","NativeEventEmitter","addListener","data","console","warn","AndroidRejectPaymentCredentials","requestId","catch","undefined","responseData","AndroidProvidePaymentCredentials","error","message","String","event","callback","remove","removeListener","subscription","checkWalletAvailability","getSecureWalletInfo","isWalletInitialized","ensureGoogleWalletInitialized","getCardStatusBySuffix","last4Digits","cardState","getCardState","getCardStatusByIdentifier","identifier","tsp","tokenState","toUpperCase","hasEligibleTokenizationTarget","network","issuerName","addCardToGoogleWallet","cardData","handlePaymentCredentialsGeneration","tokenizationStatus","getTokenizationStatus","resumeAddCardToGoogleWallet","listTokens","resolve","addCardToAppleWallet","issuerEncryptPayloadCallback","wallet","passData","IOSPresentAddPaymentPassView","status","addPaymentPassToWallet","paymentPassData","nonce","nonceSignature","certificates","response","IOSHandleAddPaymentPassResponse"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"names":["TurboModuleRegistry","PACKAGE_NAME","Wallet","getEnforcing","error","Error","console","warn","message"],"sourceRoot":"../../src","sources":["NativeWallet.ts"],"mappings":"AACA,SAAQA,mBAAmB,QAAO,cAAc;AAqFhD,MAAMC,YAAY,GAAG,gCAAgC;AACrD;AACA;AACA;AACA,IAAIC,MAAwB;AAC5B,IAAI;EACFA,MAAM,GAAGF,mBAAmB,CAACG,YAAY,CAAO,UAAU,CAAC;AAC7D,CAAC,CAAC,OAAOC,KAAK,EAAE;EACd,IAAIA,KAAK,YAAYC,KAAK,EAAE;IAC1B;IACAC,OAAO,CAACC,IAAI,CAAC,IAAIN,YAAY,mCAAmCG,KAAK,CAACI,OAAO,EAAE,CAAC;EAClF;AACF;AACA,eAAeN,MAAM;AACrB,SAAQD,YAAY","ignoreList":[]}
1
+ {"version":3,"names":["TurboModuleRegistry","PACKAGE_NAME","Wallet","getEnforcing","error","Error","console","warn","message"],"sourceRoot":"../../src","sources":["NativeWallet.ts"],"mappings":"AACA,SAAQA,mBAAmB,QAAO,cAAc;AAuGhD,MAAMC,YAAY,GAAG,gCAAgC;AACrD;AACA;AACA;AACA,IAAIC,MAAwB;AAC5B,IAAI;EACFA,MAAM,GAAGF,mBAAmB,CAACG,YAAY,CAAO,UAAU,CAAC;AAC7D,CAAC,CAAC,OAAOC,KAAK,EAAE;EACd,IAAIA,KAAK,YAAYC,KAAK,EAAE;IAC1B;IACAC,OAAO,CAACC,IAAI,CAAC,IAAIN,YAAY,mCAAmCG,KAAK,CAACI,OAAO,EAAE,CAAC;EAClF;AACF;AACA,eAAeN,MAAM;AACrB,SAAQD,YAAY","ignoreList":[]}
@@ -1,3 +1,4 @@
1
+ /* eslint-disable no-console */
1
2
  /* eslint-disable @lwc/lwc/no-async-await */
2
3
  import { NativeEventEmitter, Platform } from 'react-native';
3
4
  import Wallet, { PACKAGE_NAME } from './NativeWallet';
@@ -7,6 +8,24 @@ function getModuleLinkingRejection() {
7
8
  return Promise.reject(new Error(`Failed to load Wallet module, make sure to link ${PACKAGE_NAME} correctly`));
8
9
  }
9
10
  let eventEmitter;
11
+ let paymentCredentialsHandler = null;
12
+ if (Platform.OS === 'android' && Wallet) {
13
+ eventEmitter ??= new NativeEventEmitter(Wallet);
14
+ eventEmitter.addListener('onPaymentCredentialsRequest', async data => {
15
+ if (!paymentCredentialsHandler) {
16
+ console.warn(`[${PACKAGE_NAME}] Received payment credentials request but no handler is set`);
17
+ await (Wallet === null || Wallet === void 0 ? void 0 : Wallet.AndroidRejectPaymentCredentials(data.requestId, 'No payment credentials handler is set').catch(() => undefined));
18
+ return;
19
+ }
20
+ try {
21
+ const responseData = await paymentCredentialsHandler(data);
22
+ await (Wallet === null || Wallet === void 0 ? void 0 : Wallet.AndroidProvidePaymentCredentials(data.requestId, responseData));
23
+ } catch (error) {
24
+ console.error(`[${PACKAGE_NAME}] Error handling payment credentials request:`, error);
25
+ await (Wallet === null || Wallet === void 0 ? void 0 : Wallet.AndroidRejectPaymentCredentials(data.requestId, error instanceof Error ? error.message : String(error)).catch(() => undefined));
26
+ }
27
+ });
28
+ }
10
29
  function addListener(event, callback) {
11
30
  if (!Wallet) {
12
31
  // eslint-disable-next-line no-console
@@ -61,7 +80,25 @@ async function getCardStatusByIdentifier(identifier, tsp) {
61
80
  const tokenState = await Wallet.getCardStatusByIdentifier(identifier, tsp.toUpperCase());
62
81
  return getCardState(tokenState);
63
82
  }
64
- async function addCardToGoogleWallet(cardData) {
83
+
84
+ /**
85
+ * Checks whether the card can still be added to a Google Wallet target: the phone or a paired wearable.
86
+ * Use it to decide whether to show the "Add to Google Wallet" button when wearables are supported.
87
+ * @param last4Digits - The last 4 digits of the card number (FPAN, not the token)
88
+ * @param network - The card network, e.g. `VISA`, `MASTERCARD`
89
+ * @param issuerName - The issuer name used for matching, as in the token metadata (not the card display name)
90
+ * @returns `true` if at least one target can still receive the card
91
+ */
92
+ async function hasEligibleTokenizationTarget(last4Digits, network, issuerName) {
93
+ if (Platform.OS === 'ios') {
94
+ throw new Error('hasEligibleTokenizationTarget is not available on iOS');
95
+ }
96
+ if (!Wallet) {
97
+ return getModuleLinkingRejection();
98
+ }
99
+ return Wallet.hasEligibleTokenizationTarget(last4Digits, network.toUpperCase(), issuerName);
100
+ }
101
+ async function addCardToGoogleWallet(cardData, handlePaymentCredentialsGeneration) {
65
102
  if (Platform.OS === 'ios') {
66
103
  throw new Error('addCardToGoogleWallet is not available on iOS');
67
104
  }
@@ -72,8 +109,13 @@ async function addCardToGoogleWallet(cardData) {
72
109
  if (!isWalletInitialized) {
73
110
  throw new Error('Wallet could not be initialized');
74
111
  }
75
- const tokenizationStatus = await Wallet.addCardToGoogleWallet(cardData);
76
- return getTokenizationStatus(tokenizationStatus);
112
+ paymentCredentialsHandler = handlePaymentCredentialsGeneration;
113
+ try {
114
+ const tokenizationStatus = await Wallet.addCardToGoogleWallet(cardData);
115
+ return getTokenizationStatus(tokenizationStatus);
116
+ } finally {
117
+ paymentCredentialsHandler = null;
118
+ }
77
119
  }
78
120
  async function resumeAddCardToGoogleWallet(cardData) {
79
121
  if (Platform.OS === 'ios') {
@@ -127,5 +169,5 @@ async function addCardToAppleWallet(cardData, issuerEncryptPayloadCallback) {
127
169
  const status = await addPaymentPassToWallet(passData);
128
170
  return getTokenizationStatus(status);
129
171
  }
130
- export { AddToWalletButton, checkWalletAvailability, getSecureWalletInfo, getCardStatusBySuffix, getCardStatusByIdentifier, addCardToGoogleWallet, resumeAddCardToGoogleWallet, listTokens, addCardToAppleWallet, addListener, removeListener };
172
+ export { AddToWalletButton, checkWalletAvailability, getSecureWalletInfo, getCardStatusBySuffix, getCardStatusByIdentifier, hasEligibleTokenizationTarget, addCardToGoogleWallet, resumeAddCardToGoogleWallet, listTokens, addCardToAppleWallet, addListener, removeListener };
131
173
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["NativeEventEmitter","Platform","Wallet","PACKAGE_NAME","getCardState","getTokenizationStatus","AddToWalletButton","getModuleLinkingRejection","Promise","reject","Error","eventEmitter","addListener","event","callback","console","warn","remove","undefined","removeListener","subscription","checkWalletAvailability","getSecureWalletInfo","OS","isWalletInitialized","ensureGoogleWalletInitialized","getCardStatusBySuffix","last4Digits","cardState","getCardStatusByIdentifier","identifier","tsp","tokenState","toUpperCase","addCardToGoogleWallet","cardData","tokenizationStatus","resumeAddCardToGoogleWallet","listTokens","resolve","addCardToAppleWallet","issuerEncryptPayloadCallback","wallet","passData","IOSPresentAddPaymentPassView","status","addPaymentPassToWallet","paymentPassData","responseData","nonce","nonceSignature","certificates","response","IOSHandleAddPaymentPassResponse"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["NativeEventEmitter","Platform","Wallet","PACKAGE_NAME","getCardState","getTokenizationStatus","AddToWalletButton","getModuleLinkingRejection","Promise","reject","Error","eventEmitter","paymentCredentialsHandler","OS","addListener","data","console","warn","AndroidRejectPaymentCredentials","requestId","catch","undefined","responseData","AndroidProvidePaymentCredentials","error","message","String","event","callback","remove","removeListener","subscription","checkWalletAvailability","getSecureWalletInfo","isWalletInitialized","ensureGoogleWalletInitialized","getCardStatusBySuffix","last4Digits","cardState","getCardStatusByIdentifier","identifier","tsp","tokenState","toUpperCase","hasEligibleTokenizationTarget","network","issuerName","addCardToGoogleWallet","cardData","handlePaymentCredentialsGeneration","tokenizationStatus","resumeAddCardToGoogleWallet","listTokens","resolve","addCardToAppleWallet","issuerEncryptPayloadCallback","wallet","passData","IOSPresentAddPaymentPassView","status","addPaymentPassToWallet","paymentPassData","nonce","nonceSignature","certificates","response","IOSHandleAddPaymentPassResponse"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
@@ -21,6 +21,8 @@ type AndroidCardData = {
21
21
  cardHolderName: string;
22
22
  lastDigits: string;
23
23
  userAddress: UserAddress;
24
+ isVirtualCard?: boolean;
25
+ isBounceProvisioned?: boolean;
24
26
  };
25
27
  type AndroidResumeCardData = {
26
28
  network: string;
@@ -35,9 +37,16 @@ type IOSCardData = {
35
37
  cardDescription: string;
36
38
  };
37
39
  type onCardActivatedPayload = {
38
- tokenId: string;
40
+ tokenId?: string | null;
39
41
  status: 'activated' | 'canceled';
40
42
  };
43
+ type onPaymentCredentialsRequestPayload = {
44
+ requestId: string;
45
+ serverSessionId: string;
46
+ walletId: string;
47
+ tokenRequestorId: string | null;
48
+ opaquePaymentCard: string;
49
+ };
41
50
  type IOSAddPaymentPassData = {
42
51
  status: number;
43
52
  nonce: string;
@@ -55,13 +64,20 @@ type TokenInfo = {
55
64
  lastDigits: string;
56
65
  tokenState: number;
57
66
  };
67
+ type AndroidPaymentCredentialsResponse = {
68
+ opaquePaymentCard: string;
69
+ googleOpaquePaymentCard: string;
70
+ };
58
71
  export interface Spec extends TurboModule {
59
72
  checkWalletAvailability(): Promise<boolean>;
60
73
  ensureGoogleWalletInitialized(): Promise<boolean>;
61
74
  getSecureWalletInfo(): Promise<AndroidWalletData>;
62
75
  getCardStatusBySuffix(last4Digits: string): Promise<number>;
63
76
  getCardStatusByIdentifier(identifier: string, tsp: string): Promise<number>;
77
+ hasEligibleTokenizationTarget(last4Digits: string, network: string, issuerName: string): Promise<boolean>;
64
78
  addCardToGoogleWallet(cardData: AndroidCardData): Promise<number>;
79
+ AndroidProvidePaymentCredentials(requestId: string, responseData: AndroidPaymentCredentialsResponse): Promise<boolean>;
80
+ AndroidRejectPaymentCredentials(requestId: string, errorMessage: string): Promise<boolean>;
65
81
  resumeAddCardToGoogleWallet(cardData: AndroidResumeCardData): Promise<number>;
66
82
  listTokens(): Promise<TokenInfo[]>;
67
83
  IOSPresentAddPaymentPassView(cardData: IOSCardData): Promise<IOSAddPaymentPassData>;
@@ -73,5 +89,5 @@ declare const PACKAGE_NAME = "@expensify/react-native-wallet";
73
89
  declare let Wallet: Spec | undefined;
74
90
  export default Wallet;
75
91
  export { PACKAGE_NAME };
76
- export type { AndroidCardData, AndroidResumeCardData, IOSCardData, AndroidWalletData, CardStatus, UserAddress, onCardActivatedPayload, Platform, IOSAddPaymentPassData, IOSEncryptPayload, TokenizationStatus, TokenInfo, };
92
+ export type { AndroidCardData, AndroidResumeCardData, IOSCardData, AndroidWalletData, CardStatus, UserAddress, onCardActivatedPayload, onPaymentCredentialsRequestPayload, Platform, IOSAddPaymentPassData, IOSEncryptPayload, TokenizationStatus, TokenInfo, AndroidPaymentCredentialsResponse, };
77
93
  //# sourceMappingURL=NativeWallet.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"NativeWallet.d.ts","sourceRoot":"","sources":["../../../src/NativeWallet.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"NativeWallet.d.ts","sourceRoot":"","sources":["../../../src/NativeWallet.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import type { EmitterSubscription } from 'react-native';
2
- import type { TokenizationStatus, AndroidCardData, AndroidResumeCardData, CardStatus, IOSCardData, IOSEncryptPayload, AndroidWalletData, onCardActivatedPayload, IOSAddPaymentPassData, TokenInfo } from './NativeWallet';
2
+ import type { TokenizationStatus, AndroidCardData, AndroidResumeCardData, CardStatus, IOSCardData, IOSEncryptPayload, AndroidWalletData, onCardActivatedPayload, onPaymentCredentialsRequestPayload, IOSAddPaymentPassData, TokenInfo, AndroidPaymentCredentialsResponse } from './NativeWallet';
3
3
  import AddToWalletButton from './AddToWalletButton';
4
4
  declare function addListener(event: string, callback: (data: onCardActivatedPayload) => void): EmitterSubscription;
5
5
  declare function removeListener(subscription: EmitterSubscription): void;
@@ -13,10 +13,19 @@ declare function getCardStatusBySuffix(last4Digits: string): Promise<CardStatus>
13
13
  * @returns CardStatus - The card status
14
14
  */
15
15
  declare function getCardStatusByIdentifier(identifier: string, tsp: string): Promise<CardStatus>;
16
- declare function addCardToGoogleWallet(cardData: AndroidCardData): Promise<TokenizationStatus>;
16
+ /**
17
+ * Checks whether the card can still be added to a Google Wallet target: the phone or a paired wearable.
18
+ * Use it to decide whether to show the "Add to Google Wallet" button when wearables are supported.
19
+ * @param last4Digits - The last 4 digits of the card number (FPAN, not the token)
20
+ * @param network - The card network, e.g. `VISA`, `MASTERCARD`
21
+ * @param issuerName - The issuer name used for matching, as in the token metadata (not the card display name)
22
+ * @returns `true` if at least one target can still receive the card
23
+ */
24
+ declare function hasEligibleTokenizationTarget(last4Digits: string, network: string, issuerName: string): Promise<boolean>;
25
+ declare function addCardToGoogleWallet(cardData: AndroidCardData, handlePaymentCredentialsGeneration: (data: onPaymentCredentialsRequestPayload) => Promise<AndroidPaymentCredentialsResponse>): Promise<TokenizationStatus>;
17
26
  declare function resumeAddCardToGoogleWallet(cardData: AndroidResumeCardData): Promise<TokenizationStatus>;
18
27
  declare function listTokens(): Promise<TokenInfo[]>;
19
28
  declare function addCardToAppleWallet(cardData: IOSCardData, issuerEncryptPayloadCallback: (nonce: string, nonceSignature: string, certificate: string[]) => Promise<IOSEncryptPayload>): Promise<TokenizationStatus>;
20
- export type { AndroidCardData, AndroidWalletData, CardStatus, IOSEncryptPayload, IOSCardData, IOSAddPaymentPassData, onCardActivatedPayload, TokenizationStatus, TokenInfo };
21
- export { AddToWalletButton, checkWalletAvailability, getSecureWalletInfo, getCardStatusBySuffix, getCardStatusByIdentifier, addCardToGoogleWallet, resumeAddCardToGoogleWallet, listTokens, addCardToAppleWallet, addListener, removeListener, };
29
+ export type { AndroidCardData, AndroidWalletData, CardStatus, IOSEncryptPayload, IOSCardData, IOSAddPaymentPassData, onCardActivatedPayload, onPaymentCredentialsRequestPayload, TokenizationStatus, TokenInfo, AndroidPaymentCredentialsResponse, };
30
+ export { AddToWalletButton, checkWalletAvailability, getSecureWalletInfo, getCardStatusBySuffix, getCardStatusByIdentifier, hasEligibleTokenizationTarget, addCardToGoogleWallet, resumeAddCardToGoogleWallet, listTokens, addCardToAppleWallet, addListener, removeListener, };
22
31
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,cAAc,CAAC;AAEtD,OAAO,KAAK,EACV,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACrB,UAAU,EACV,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EACjB,sBAAsB,EACtB,qBAAqB,EACrB,SAAS,EACV,MAAM,gBAAgB,CAAC;AAExB,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AAQpD,iBAAS,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,sBAAsB,KAAK,IAAI,GAAG,mBAAmB,CAQzG;AAED,iBAAS,cAAc,CAAC,YAAY,EAAE,mBAAmB,GAAG,IAAI,CAE/D;AAED,iBAAS,uBAAuB,IAAI,OAAO,CAAC,OAAO,CAAC,CAKnD;AAED,iBAAe,mBAAmB,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAc/D;AAED,iBAAe,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAO7E;AAED;;;;;GAKG;AACH,iBAAe,yBAAyB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAO7F;AAED,iBAAe,qBAAqB,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAc3F;AAED,iBAAe,2BAA2B,CAAC,QAAQ,EAAE,qBAAqB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAcvG;AAED,iBAAe,UAAU,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAahD;AAED,iBAAe,oBAAoB,CACjC,QAAQ,EAAE,WAAW,EACrB,4BAA4B,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,iBAAiB,CAAC,GACzH,OAAO,CAAC,kBAAkB,CAAC,CA4B7B;AAED,YAAY,EAAC,eAAe,EAAE,iBAAiB,EAAE,UAAU,EAAE,iBAAiB,EAAE,WAAW,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,SAAS,EAAC,CAAC;AAC3K,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,mBAAmB,EACnB,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,2BAA2B,EAC3B,UAAU,EACV,oBAAoB,EACpB,WAAW,EACX,cAAc,GACf,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,cAAc,CAAC;AAEtD,OAAO,KAAK,EACV,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACrB,UAAU,EACV,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EACjB,sBAAsB,EACtB,kCAAkC,EAClC,qBAAqB,EACrB,SAAS,EACT,iCAAiC,EAClC,MAAM,gBAAgB,CAAC;AAExB,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AA2BpD,iBAAS,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,sBAAsB,KAAK,IAAI,GAAG,mBAAmB,CAQzG;AAED,iBAAS,cAAc,CAAC,YAAY,EAAE,mBAAmB,GAAG,IAAI,CAE/D;AAED,iBAAS,uBAAuB,IAAI,OAAO,CAAC,OAAO,CAAC,CAKnD;AAED,iBAAe,mBAAmB,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAc/D;AAED,iBAAe,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAO7E;AAED;;;;;GAKG;AACH,iBAAe,yBAAyB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAO7F;AAED;;;;;;;GAOG;AACH,iBAAe,6BAA6B,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAUvH;AAED,iBAAe,qBAAqB,CAClC,QAAQ,EAAE,eAAe,EACzB,kCAAkC,EAAE,CAAC,IAAI,EAAE,kCAAkC,KAAK,OAAO,CAAC,iCAAiC,CAAC,GAC3H,OAAO,CAAC,kBAAkB,CAAC,CAoB7B;AAED,iBAAe,2BAA2B,CAAC,QAAQ,EAAE,qBAAqB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAcvG;AAED,iBAAe,UAAU,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAahD;AAED,iBAAe,oBAAoB,CACjC,QAAQ,EAAE,WAAW,EACrB,4BAA4B,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,iBAAiB,CAAC,GACzH,OAAO,CAAC,kBAAkB,CAAC,CA4B7B;AAED,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,UAAU,EACV,iBAAiB,EACjB,WAAW,EACX,qBAAqB,EACrB,sBAAsB,EACtB,kCAAkC,EAClC,kBAAkB,EAClB,SAAS,EACT,iCAAiC,GAClC,CAAC;AACF,OAAO,EACL,iBAAiB,EACjB,uBAAuB,EACvB,mBAAmB,EACnB,qBAAqB,EACrB,yBAAyB,EACzB,6BAA6B,EAC7B,qBAAqB,EACrB,2BAA2B,EAC3B,UAAU,EACV,oBAAoB,EACpB,WAAW,EACX,cAAc,GACf,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expensify/react-native-wallet",
3
- "version": "0.1.41",
3
+ "version": "0.2.1",
4
4
  "description": "A React Native module designed for seamless integration of Card Push Provisioning into Apple Wallet and Google Wallet, enabling easy and secure addition of payment cards directly from your application.",
5
5
  "source": "./src/index.tsx",
6
6
  "main": "lib/commonjs/index",
@@ -66,7 +66,7 @@
66
66
  "devEngines": {
67
67
  "runtime": {
68
68
  "name": "node",
69
- "version": ">=24.19.0",
69
+ "version": ">=24.22.1",
70
70
  "onFail": "error"
71
71
  },
72
72
  "packageManager": {
@@ -27,6 +27,8 @@ type AndroidCardData = {
27
27
  cardHolderName: string;
28
28
  lastDigits: string;
29
29
  userAddress: UserAddress;
30
+ isVirtualCard?: boolean;
31
+ isBounceProvisioned?: boolean;
30
32
  };
31
33
 
32
34
  type AndroidResumeCardData = {
@@ -44,10 +46,18 @@ type IOSCardData = {
44
46
  };
45
47
 
46
48
  type onCardActivatedPayload = {
47
- tokenId: string;
49
+ tokenId?: string | null;
48
50
  status: 'activated' | 'canceled';
49
51
  };
50
52
 
53
+ type onPaymentCredentialsRequestPayload = {
54
+ requestId: string;
55
+ serverSessionId: string;
56
+ walletId: string;
57
+ tokenRequestorId: string | null;
58
+ opaquePaymentCard: string;
59
+ };
60
+
51
61
  type IOSAddPaymentPassData = {
52
62
  status: number;
53
63
  nonce: string;
@@ -69,13 +79,21 @@ type TokenInfo = {
69
79
  tokenState: number;
70
80
  };
71
81
 
82
+ type AndroidPaymentCredentialsResponse = {
83
+ opaquePaymentCard: string;
84
+ googleOpaquePaymentCard: string;
85
+ };
86
+
72
87
  export interface Spec extends TurboModule {
73
88
  checkWalletAvailability(): Promise<boolean>;
74
89
  ensureGoogleWalletInitialized(): Promise<boolean>;
75
90
  getSecureWalletInfo(): Promise<AndroidWalletData>;
76
91
  getCardStatusBySuffix(last4Digits: string): Promise<number>;
77
92
  getCardStatusByIdentifier(identifier: string, tsp: string): Promise<number>;
93
+ hasEligibleTokenizationTarget(last4Digits: string, network: string, issuerName: string): Promise<boolean>;
78
94
  addCardToGoogleWallet(cardData: AndroidCardData): Promise<number>;
95
+ AndroidProvidePaymentCredentials(requestId: string, responseData: AndroidPaymentCredentialsResponse): Promise<boolean>;
96
+ AndroidRejectPaymentCredentials(requestId: string, errorMessage: string): Promise<boolean>;
79
97
  resumeAddCardToGoogleWallet(cardData: AndroidResumeCardData): Promise<number>;
80
98
  listTokens(): Promise<TokenInfo[]>;
81
99
  IOSPresentAddPaymentPassView(cardData: IOSCardData): Promise<IOSAddPaymentPassData>;
@@ -107,9 +125,11 @@ export type {
107
125
  CardStatus,
108
126
  UserAddress,
109
127
  onCardActivatedPayload,
128
+ onPaymentCredentialsRequestPayload,
110
129
  Platform,
111
130
  IOSAddPaymentPassData,
112
131
  IOSEncryptPayload,
113
132
  TokenizationStatus,
114
133
  TokenInfo,
134
+ AndroidPaymentCredentialsResponse,
115
135
  };
package/src/index.tsx CHANGED
@@ -1,3 +1,4 @@
1
+ /* eslint-disable no-console */
1
2
  /* eslint-disable @lwc/lwc/no-async-await */
2
3
  import {NativeEventEmitter, Platform} from 'react-native';
3
4
  import type {EmitterSubscription} from 'react-native';
@@ -11,8 +12,10 @@ import type {
11
12
  IOSEncryptPayload,
12
13
  AndroidWalletData,
13
14
  onCardActivatedPayload,
15
+ onPaymentCredentialsRequestPayload,
14
16
  IOSAddPaymentPassData,
15
17
  TokenInfo,
18
+ AndroidPaymentCredentialsResponse,
16
19
  } from './NativeWallet';
17
20
  import {getCardState, getTokenizationStatus} from './utils';
18
21
  import AddToWalletButton from './AddToWalletButton';
@@ -22,6 +25,25 @@ function getModuleLinkingRejection() {
22
25
  }
23
26
 
24
27
  let eventEmitter: NativeEventEmitter | undefined;
28
+ let paymentCredentialsHandler: ((data: onPaymentCredentialsRequestPayload) => Promise<AndroidPaymentCredentialsResponse>) | null = null;
29
+
30
+ if (Platform.OS === 'android' && Wallet) {
31
+ eventEmitter ??= new NativeEventEmitter(Wallet);
32
+ eventEmitter.addListener('onPaymentCredentialsRequest', async (data: onPaymentCredentialsRequestPayload) => {
33
+ if (!paymentCredentialsHandler) {
34
+ console.warn(`[${PACKAGE_NAME}] Received payment credentials request but no handler is set`);
35
+ await Wallet?.AndroidRejectPaymentCredentials(data.requestId, 'No payment credentials handler is set').catch(() => undefined);
36
+ return;
37
+ }
38
+ try {
39
+ const responseData = await paymentCredentialsHandler(data);
40
+ await Wallet?.AndroidProvidePaymentCredentials(data.requestId, responseData);
41
+ } catch (error) {
42
+ console.error(`[${PACKAGE_NAME}] Error handling payment credentials request:`, error);
43
+ await Wallet?.AndroidRejectPaymentCredentials(data.requestId, error instanceof Error ? error.message : String(error)).catch(() => undefined);
44
+ }
45
+ });
46
+ }
25
47
 
26
48
  function addListener(event: string, callback: (data: onCardActivatedPayload) => void): EmitterSubscription {
27
49
  if (!Wallet) {
@@ -84,7 +106,30 @@ async function getCardStatusByIdentifier(identifier: string, tsp: string): Promi
84
106
  return getCardState(tokenState);
85
107
  }
86
108
 
87
- async function addCardToGoogleWallet(cardData: AndroidCardData): Promise<TokenizationStatus> {
109
+ /**
110
+ * Checks whether the card can still be added to a Google Wallet target: the phone or a paired wearable.
111
+ * Use it to decide whether to show the "Add to Google Wallet" button when wearables are supported.
112
+ * @param last4Digits - The last 4 digits of the card number (FPAN, not the token)
113
+ * @param network - The card network, e.g. `VISA`, `MASTERCARD`
114
+ * @param issuerName - The issuer name used for matching, as in the token metadata (not the card display name)
115
+ * @returns `true` if at least one target can still receive the card
116
+ */
117
+ async function hasEligibleTokenizationTarget(last4Digits: string, network: string, issuerName: string): Promise<boolean> {
118
+ if (Platform.OS === 'ios') {
119
+ throw new Error('hasEligibleTokenizationTarget is not available on iOS');
120
+ }
121
+
122
+ if (!Wallet) {
123
+ return getModuleLinkingRejection();
124
+ }
125
+
126
+ return Wallet.hasEligibleTokenizationTarget(last4Digits, network.toUpperCase(), issuerName);
127
+ }
128
+
129
+ async function addCardToGoogleWallet(
130
+ cardData: AndroidCardData,
131
+ handlePaymentCredentialsGeneration: (data: onPaymentCredentialsRequestPayload) => Promise<AndroidPaymentCredentialsResponse>,
132
+ ): Promise<TokenizationStatus> {
88
133
  if (Platform.OS === 'ios') {
89
134
  throw new Error('addCardToGoogleWallet is not available on iOS');
90
135
  }
@@ -96,8 +141,14 @@ async function addCardToGoogleWallet(cardData: AndroidCardData): Promise<Tokeniz
96
141
  if (!isWalletInitialized) {
97
142
  throw new Error('Wallet could not be initialized');
98
143
  }
99
- const tokenizationStatus = await Wallet.addCardToGoogleWallet(cardData);
100
- return getTokenizationStatus(tokenizationStatus);
144
+
145
+ paymentCredentialsHandler = handlePaymentCredentialsGeneration;
146
+ try {
147
+ const tokenizationStatus = await Wallet.addCardToGoogleWallet(cardData);
148
+ return getTokenizationStatus(tokenizationStatus);
149
+ } finally {
150
+ paymentCredentialsHandler = null;
151
+ }
101
152
  }
102
153
 
103
154
  async function resumeAddCardToGoogleWallet(cardData: AndroidResumeCardData): Promise<TokenizationStatus> {
@@ -164,13 +215,26 @@ async function addCardToAppleWallet(
164
215
  return getTokenizationStatus(status);
165
216
  }
166
217
 
167
- export type {AndroidCardData, AndroidWalletData, CardStatus, IOSEncryptPayload, IOSCardData, IOSAddPaymentPassData, onCardActivatedPayload, TokenizationStatus, TokenInfo};
218
+ export type {
219
+ AndroidCardData,
220
+ AndroidWalletData,
221
+ CardStatus,
222
+ IOSEncryptPayload,
223
+ IOSCardData,
224
+ IOSAddPaymentPassData,
225
+ onCardActivatedPayload,
226
+ onPaymentCredentialsRequestPayload,
227
+ TokenizationStatus,
228
+ TokenInfo,
229
+ AndroidPaymentCredentialsResponse,
230
+ };
168
231
  export {
169
232
  AddToWalletButton,
170
233
  checkWalletAvailability,
171
234
  getSecureWalletInfo,
172
235
  getCardStatusBySuffix,
173
236
  getCardStatusByIdentifier,
237
+ hasEligibleTokenizationTarget,
174
238
  addCardToGoogleWallet,
175
239
  resumeAddCardToGoogleWallet,
176
240
  listTokens,