@expensify/react-native-wallet 0.1.15 → 0.1.18
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 +93 -15
- package/app.plugin.js +2 -0
- package/lib/commonjs/index.js +2 -3
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/index.js +1 -1
- package/package.json +14 -10
- package/plugins/build/index.d.ts +16 -0
- package/plugins/build/index.js +127 -0
- package/plugins/src/index.ts +169 -0
- package/plugins/tsconfig.json +18 -0
- package/react-native-wallet.podspec +1 -1
- package/src/index.tsx +1 -1
package/README.md
CHANGED
|
@@ -5,10 +5,11 @@
|
|
|
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
|
+
- 🎉 Expo support (expo-plugin)
|
|
8
9
|
|
|
9
10
|
## Getting started
|
|
10
11
|
|
|
11
|
-
Using the `react-native-wallet` Push Provisioning features requires proper configuration and access from both Google and Apple.
|
|
12
|
+
Using the `react-native-wallet` Push Provisioning features requires proper configuration and access from both Google and Apple.
|
|
12
13
|
Please follow the instructions below before installing the library:
|
|
13
14
|
|
|
14
15
|
### Android
|
|
@@ -20,10 +21,10 @@ To be able to interact with the Google Wallet on the Android please make sure to
|
|
|
20
21
|
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.
|
|
21
22
|
|
|
22
23
|
2. Once getting an approval from the Google team
|
|
23
|
-
1. Download the [TapAndPay SDK](https://developers.google.com/pay/issuers/apis/push-provisioning/android/releases).
|
|
24
|
-
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).
|
|
24
|
+
1. Download the [TapAndPay SDK](https://developers.google.com/pay/issuers/apis/push-provisioning/android/releases).
|
|
25
|
+
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).
|
|
25
26
|
3. Add `/android/libs` to `.gitignore`.
|
|
26
|
-
|
|
27
|
+
|
|
27
28
|
3. Then connect the SDK to your project in `build.gradle`, for example like in [example/android/build.gradle](https://github.com/Expensify/react-native-wallet/blob/main/example/android/build.gradle):
|
|
28
29
|
|
|
29
30
|
```groovy
|
|
@@ -37,7 +38,7 @@ allprojects {
|
|
|
37
38
|
|
|
38
39
|
#### Step 2: Whitelist your app for SDK use.
|
|
39
40
|
|
|
40
|
-
To use the Google SDK in your app, you will need to whitelist your app details. Without it, calling some functions will result in a `Not verified` error.
|
|
41
|
+
To use the Google SDK in your app, you will need to whitelist your app details. Without it, calling some functions will result in a `Not verified` error.
|
|
41
42
|
To resolve it, please follow the instructions from [the official Google documentation](https://developers.google.com/pay/issuers/apis/push-provisioning/android/allowlist).
|
|
42
43
|
|
|
43
44
|
For your builds, you will need to prepare your app's `package name` and `fingerprint` following [these steps](https://developers.google.com/pay/issuers/apis/push-provisioning/android/allowlist#how_to_get_your_apps_fingerprint). The values should, for example, look like this:
|
|
@@ -58,7 +59,21 @@ With all the required data, submit the form and wait for Google's response. Afte
|
|
|
58
59
|
|
|
59
60
|
### Step 1: Apply for appropriate entitlements
|
|
60
61
|
|
|
61
|
-
To enable In-App Provisioning in your app, you must request activation of the appropriate Apple Pay entitlements for your developer Team ID. Enterprise Team IDs are not supported. This entitlement is not available by default in our panel; you will need to request it.
|
|
62
|
+
To enable In-App Provisioning in your app, you must request activation of the appropriate Apple Pay entitlements for your developer Team ID. Enterprise Team IDs are not supported. This entitlement is not available by default in our panel; you will need to request it.
|
|
63
|
+
|
|
64
|
+
Submit your request through the [In-App Provisioning Submission Form](https://developer.apple.com/contact/request/apple-pay-in-app-provisioning/). Only Account Holders can access this form — if you are unable to access it, coordinate with the Account Holder of your team. Alternatively, you can email `iap_entitlements@apple.com` with the following format:
|
|
65
|
+
|
|
66
|
+
**Subject:** `Apple Pay Entitlements and Allow List Request - [Issuer Name] - [Country Code]`
|
|
67
|
+
|
|
68
|
+
**Body:**
|
|
69
|
+
- Issuer Name
|
|
70
|
+
- Country [Country Code]
|
|
71
|
+
- Team ID
|
|
72
|
+
- Adam ID
|
|
73
|
+
- App Name
|
|
74
|
+
|
|
75
|
+
> [!NOTE]
|
|
76
|
+
> Only a production Team ID and Adam ID can receive the entitlement. Test Team IDs don't qualify.
|
|
62
77
|
|
|
63
78
|
Once Apple verifies your identity, you should get documentation named `Getting Started with Apple Pay In-App Provisioning, Verification & Security`. In this confidential document you will find all the relevant information about:
|
|
64
79
|
- Prerequisites for your project
|
|
@@ -72,13 +87,13 @@ Make sure to familiarize yourself with that document before deploying your app.
|
|
|
72
87
|
|
|
73
88
|
### Step 2: Activate the entitlement
|
|
74
89
|
|
|
75
|
-
After getting a positive response from Apple, open the developer portal panel and search `Certificates, Identifiers & Profiles` -> `Profiles` -> `Our distribution profile` -> `Edit` and add the `ApplePay In-App Provisioning Distribution` entitlement.
|
|
90
|
+
After getting a positive response from Apple, open the developer portal panel and search `Certificates, Identifiers & Profiles` -> `Profiles` -> `Our distribution profile` -> `Edit` and add the `ApplePay In-App Provisioning Distribution` entitlement.
|
|
76
91
|
It’s available only for the production environment so your QA must work with physical devices and cards.
|
|
77
92
|
|
|
78
93
|
|
|
79
94
|
### Step 3: Add the entitlement to your project
|
|
80
95
|
|
|
81
|
-
Add `com.apple.developer.payment-pass-provisioning` entitlement to your project. Find or create `.entitlements` file in your project and add the entitlement like below (similarly to [WalletExample.entitlements](https://github.com/Expensify/react-native-wallet/blob/main/example/ios/WalletExample/WalletExample.entitlements)):
|
|
96
|
+
Add `com.apple.developer.payment-pass-provisioning` entitlement to your project. Find or create `.entitlements` file in your project and add the entitlement like below (similarly to [WalletExample.entitlements](https://github.com/Expensify/react-native-wallet/blob/main/example/ios/WalletExample/WalletExample.entitlements)):
|
|
82
97
|
|
|
83
98
|
```xml
|
|
84
99
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
@@ -105,14 +120,44 @@ or
|
|
|
105
120
|
yarn add @expensify/react-native-wallet
|
|
106
121
|
```
|
|
107
122
|
|
|
123
|
+
### Expo plugin
|
|
124
|
+
|
|
125
|
+
To use `@expensify/react-native-wallet` with expo, you will need to use the expo-plugin.
|
|
126
|
+
|
|
127
|
+
In your `app.json` file, add the following configuration:
|
|
128
|
+
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"expo": {
|
|
132
|
+
"plugins": [
|
|
133
|
+
[
|
|
134
|
+
"@expensify/react-native-wallet",
|
|
135
|
+
{
|
|
136
|
+
enableApplePayProvisioning: true,
|
|
137
|
+
googleTapAndPaySdkPath: "./libs/tapandpay-v18.7.0.zip", // path to the Google Tap & Pay SDK zip file
|
|
138
|
+
},
|
|
139
|
+
],
|
|
140
|
+
]
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
You will need to rebuild your app after that since the lib has native files.
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
npx expo prebuild --clean
|
|
149
|
+
npx expo run:ios
|
|
150
|
+
npx expo run:android
|
|
151
|
+
```
|
|
152
|
+
|
|
108
153
|
|
|
109
154
|
|
|
110
|
-
## Required data
|
|
155
|
+
## Required data
|
|
111
156
|
Here you can find data elements used in the library, essential to work with Google Wallet and Apple Wallet APIs.
|
|
112
157
|
|
|
113
158
|
### Android
|
|
114
159
|
- **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.
|
|
115
|
-
- **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.
|
|
160
|
+
- **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.
|
|
116
161
|
- **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.
|
|
117
162
|
|
|
118
163
|
### iOS
|
|
@@ -170,10 +215,10 @@ The library offers seven functions for seamless integration and use of the Apple
|
|
|
170
215
|
### `AddToWalletButton`
|
|
171
216
|
|
|
172
217
|
A ready-to-use component that simplifies the addition of payment cards to Google Wallet and Apple Wallet. The button automatically adapts its appearance according to the platform and language specified.
|
|
173
|
-
It uses official assets provided by [Google](https://developers.google.com/wallet/generic/resources/brand-guidelines) and [Apple](https://developer.apple.com/wallet/add-to-apple-wallet-guidelines/) in their Wallet-related branding guidelines.
|
|
218
|
+
It uses official assets provided by [Google](https://developers.google.com/wallet/generic/resources/brand-guidelines) and [Apple](https://developer.apple.com/wallet/add-to-apple-wallet-guidelines/) in their Wallet-related branding guidelines.
|
|
174
219
|
|
|
175
220
|
> [!IMPORTANT]
|
|
176
|
-
> Please bear in mind the brand rules provided by [Google](https://developers.google.com/wallet/generic/resources/brand-guidelines) and [Apple](https://developer.apple.com/wallet/add-to-apple-wallet-guidelines/) when adding this component to your application.
|
|
221
|
+
> Please bear in mind the brand rules provided by [Google](https://developers.google.com/wallet/generic/resources/brand-guidelines) and [Apple](https://developer.apple.com/wallet/add-to-apple-wallet-guidelines/) when adding this component to your application.
|
|
177
222
|
|
|
178
223
|
Adhering to these guidelines is crucial not only to comply with legal requirements but also to reassure users of the authenticity and security of your application.
|
|
179
224
|
|
|
@@ -204,6 +249,40 @@ Adhering to these guidelines is crucial not only to comply with legal requiremen
|
|
|
204
249
|
|:----:|:---------------:|
|
|
205
250
|
| <img src="./assets/buttons/android_button.svg" height="50" /> | <img src="./assets/buttons/ios_button.svg" height="50" /> |
|
|
206
251
|
|
|
252
|
+
# Hex Encoding
|
|
253
|
+
|
|
254
|
+
This library use base64 encoding to encode the data. Yours might use hex encoding.
|
|
255
|
+
|
|
256
|
+
If that is the case, you will need to convert the data in the proper format.
|
|
257
|
+
|
|
258
|
+
This is an example of how to convert data to hex format:
|
|
259
|
+
|
|
260
|
+
```ts
|
|
261
|
+
import { Buffer } from "buffer"
|
|
262
|
+
const base64ToHex = (base64: string): string => Buffer.from(base64, "base64").toString("hex")
|
|
263
|
+
|
|
264
|
+
[...]
|
|
265
|
+
|
|
266
|
+
const issuerEncryptPayloadCallback = async (
|
|
267
|
+
nonce: string,
|
|
268
|
+
nonceSignature: string,
|
|
269
|
+
certificate: string[],
|
|
270
|
+
): Promise<IOSEncryptPayload> => {
|
|
271
|
+
try {
|
|
272
|
+
const payload = {
|
|
273
|
+
encryptionDetails: {
|
|
274
|
+
nonce: base64ToHex(nonce),
|
|
275
|
+
nonceSignature: base64ToHex(nonceSignature),
|
|
276
|
+
wspCertificates: certificate,
|
|
277
|
+
},
|
|
278
|
+
serialNumber,
|
|
279
|
+
wspId: "APPLE" as const,
|
|
280
|
+
}
|
|
281
|
+
[...]
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
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
|
+
|
|
207
286
|
# Publishing your app
|
|
208
287
|
|
|
209
288
|
To successfully publish your app, you will need to navigate through a series of mandatory test cases on both platforms.
|
|
@@ -214,14 +293,14 @@ Before deploying your app to the Google Play Store, make sure you have taken car
|
|
|
214
293
|
|
|
215
294
|
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__.
|
|
216
295
|
|
|
217
|
-
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.
|
|
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.
|
|
218
297
|
|
|
219
298
|
> [!NOTE]
|
|
220
299
|
>Please make sure to hide the `Add to Google Wallet` buttons when cards are already added to the wallet.
|
|
221
300
|
|
|
222
301
|
### iOS
|
|
223
302
|
|
|
224
|
-
When implementing the In-App Push Provisioning feature in your App make sure that your app follows Apple's [branding guidelines connected to Apple Wallet](https://developer.apple.com/wallet/add-to-apple-wallet-guidelines/). Remember that you must not create your own buttons or your app could be rejected at revision. You can use the[ AddWalletButton component](#components) instead!
|
|
303
|
+
When implementing the In-App Push Provisioning feature in your App make sure that your app follows Apple's [branding guidelines connected to Apple Wallet](https://developer.apple.com/wallet/add-to-apple-wallet-guidelines/). Remember that you must not create your own buttons or your app could be rejected at revision. You can use the[ AddWalletButton component](#components) instead!
|
|
225
304
|
When the pass is already provisioned, make sure to hide this button and replace it with text like `Added to Apple Wallet`. The card is fully provisioned once it added to your main device (user's iPhone) and all linked devices (for example Apple Watch).
|
|
226
305
|
|
|
227
306
|
Next to branding guidelines, please follow the instructions and best practices from [the In-App provisioning documentation]((#ios)) provided by Apple.
|
|
@@ -246,7 +325,6 @@ Additionally, when submitting your app to the App Store, you must include:
|
|
|
246
325
|
|
|
247
326
|
`@expensify/react-native-wallet` is compatible with the five latest minor releases of React Native (≥0.76.0) and works exclusively with the new architecture.
|
|
248
327
|
|
|
249
|
-
|
|
250
328
|
# Contributing
|
|
251
329
|
|
|
252
330
|
Contributions to this library are done under [https://github.com/Expensify/App](https://github.com/Expensify/App). Please refer to that repo and all its guidelines for contributing.
|
package/app.plugin.js
ADDED
package/lib/commonjs/index.js
CHANGED
|
@@ -24,8 +24,7 @@ var _NativeWallet = _interopRequireWildcard(require("./NativeWallet"));
|
|
|
24
24
|
var _utils = require("./utils");
|
|
25
25
|
var _AddToWalletButton = _interopRequireDefault(require("./AddToWalletButton"));
|
|
26
26
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
27
|
-
function
|
|
28
|
-
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
27
|
+
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
28
|
/* eslint-disable @lwc/lwc/no-async-await */
|
|
30
29
|
|
|
31
30
|
function getModuleLinkingRejection() {
|
|
@@ -121,7 +120,7 @@ async function listTokens() {
|
|
|
121
120
|
}
|
|
122
121
|
async function addCardToAppleWallet(cardData, issuerEncryptPayloadCallback) {
|
|
123
122
|
if (_reactNative.Platform.OS === 'android') {
|
|
124
|
-
throw new Error('addCardToAppleWallet is not available on
|
|
123
|
+
throw new Error('addCardToAppleWallet is not available on Android');
|
|
125
124
|
}
|
|
126
125
|
const passData = await (_NativeWallet.default === null || _NativeWallet.default === void 0 ? void 0 : _NativeWallet.default.IOSPresentAddPaymentPassView(cardData));
|
|
127
126
|
if (!passData || passData.status !== 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_reactNative","require","_NativeWallet","_interopRequireWildcard","_utils","_AddToWalletButton","_interopRequireDefault","e","__esModule","default","
|
|
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","NativeEventEmitter","Wallet","addListener","event","callback","removeListener","subscription","remove","checkWalletAvailability","getSecureWalletInfo","Platform","OS","isWalletInitialized","ensureGoogleWalletInitialized","getCardStatusBySuffix","last4Digits","cardState","getCardState","getCardStatusByIdentifier","identifier","tsp","tokenState","toUpperCase","addCardToGoogleWallet","cardData","tokenizationStatus","getTokenizationStatus","resumeAddCardToGoogleWallet","listTokens","resolve","addCardToAppleWallet","issuerEncryptPayloadCallback","passData","IOSPresentAddPaymentPassView","status","addPaymentPassToWallet","paymentPassData","responseData","nonce","nonceSignature","certificates","response","IOSHandleAddPaymentPassResponse"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
|
@@ -96,7 +96,7 @@ async function listTokens() {
|
|
|
96
96
|
}
|
|
97
97
|
async function addCardToAppleWallet(cardData, issuerEncryptPayloadCallback) {
|
|
98
98
|
if (Platform.OS === 'android') {
|
|
99
|
-
throw new Error('addCardToAppleWallet is not available on
|
|
99
|
+
throw new Error('addCardToAppleWallet is not available on Android');
|
|
100
100
|
}
|
|
101
101
|
const passData = await (Wallet === null || Wallet === void 0 ? void 0 : Wallet.IOSPresentAddPaymentPassView(cardData));
|
|
102
102
|
if (!passData || passData.status !== 0) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@expensify/react-native-wallet",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.18",
|
|
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",
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
"ios",
|
|
16
16
|
"cpp",
|
|
17
17
|
"*.podspec",
|
|
18
|
+
"app.plugin.js",
|
|
19
|
+
"plugins",
|
|
18
20
|
"react-native.config.js",
|
|
19
21
|
"!ios/build",
|
|
20
22
|
"!android/build",
|
|
@@ -27,17 +29,21 @@
|
|
|
27
29
|
"!**/__mocks__",
|
|
28
30
|
"!**/.*"
|
|
29
31
|
],
|
|
32
|
+
"workspaces": [
|
|
33
|
+
"apps/common-app",
|
|
34
|
+
"apps/basic-example"
|
|
35
|
+
],
|
|
30
36
|
"scripts": {
|
|
31
|
-
"example": "npm run --workspace=@expensify/react-native-wallet-example",
|
|
32
37
|
"test": "jest",
|
|
33
38
|
"typecheck": "tsc --noEmit",
|
|
34
39
|
"lint": "eslint . --ext .js,.ts,.tsx",
|
|
35
|
-
"lint:root": "eslint . --ext .js,.ts,.tsx --ignore-pattern '/
|
|
36
|
-
"
|
|
37
|
-
"clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib",
|
|
40
|
+
"lint:root": "eslint . --ext .js,.ts,.tsx --ignore-pattern '/plugins/**/*' --ignore-pattern '/apps/**/*'",
|
|
41
|
+
"clean": "del-cli android/build apps/basic-example/android/build apps/basic-example/android/app/build apps/basic-example/ios/build apps/expo-example/android/build apps/expo-example/ios/build lib plugins/build",
|
|
38
42
|
"prepare": "bob build",
|
|
39
43
|
"build:watch": "nodemon --watch src --ext .ts,.tsx,.css --exec \"rm -f .build_complete && npm run prepare && npm pack && touch .build_complete\"",
|
|
40
|
-
"release": "release-it"
|
|
44
|
+
"release": "release-it",
|
|
45
|
+
"build:plugins": "cd plugins && npx tsc",
|
|
46
|
+
"postinstall": "npm run build:plugins"
|
|
41
47
|
},
|
|
42
48
|
"keywords": [
|
|
43
49
|
"react-native",
|
|
@@ -76,7 +82,7 @@
|
|
|
76
82
|
"@typescript-eslint/parser": "^6.15.0",
|
|
77
83
|
"del-cli": "^5.0.0",
|
|
78
84
|
"eslint": "^8.57.1",
|
|
79
|
-
"eslint-config-expensify": "
|
|
85
|
+
"eslint-config-expensify": "2.0.24",
|
|
80
86
|
"eslint-config-prettier": "^8.5.0",
|
|
81
87
|
"eslint-import-resolver-alias": "^1.1.2",
|
|
82
88
|
"eslint-plugin-deprecation": "^2.0.0",
|
|
@@ -88,6 +94,7 @@
|
|
|
88
94
|
"eslint-plugin-prettier": "^4.0.0",
|
|
89
95
|
"eslint-plugin-promise": "^6.1.1",
|
|
90
96
|
"eslint-plugin-tsdoc": "^0.2.17",
|
|
97
|
+
"expo-module-scripts": "^5.0.7",
|
|
91
98
|
"jest": "^29.6.3",
|
|
92
99
|
"prettier": "2.8.8",
|
|
93
100
|
"react": "19.1.0",
|
|
@@ -101,9 +108,6 @@
|
|
|
101
108
|
"react": "*",
|
|
102
109
|
"react-native": "*"
|
|
103
110
|
},
|
|
104
|
-
"workspaces": [
|
|
105
|
-
"./example"
|
|
106
|
-
],
|
|
107
111
|
"jest": {
|
|
108
112
|
"preset": "react-native",
|
|
109
113
|
"modulePathIgnorePatterns": [
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ConfigPlugin } from '@expo/config-plugins';
|
|
2
|
+
export type ReactNativeWalletConfig = {
|
|
3
|
+
/**
|
|
4
|
+
* Path to the Google TapAndPay SDK for Android
|
|
5
|
+
* This should be the path to a ZIP file containing the Google TapAndPay SDK files,
|
|
6
|
+
* or a directory containing the SDK files, or a single SDK file (.aar)
|
|
7
|
+
*/
|
|
8
|
+
googleTapAndPaySdkPath?: string;
|
|
9
|
+
/**
|
|
10
|
+
* iOS Apple Pay In-App Provisioning entitlement
|
|
11
|
+
* default true
|
|
12
|
+
*/
|
|
13
|
+
enableApplePayProvisioning?: boolean;
|
|
14
|
+
};
|
|
15
|
+
declare const _default: ConfigPlugin<ReactNativeWalletConfig>;
|
|
16
|
+
export default _default;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const node_child_process_1 = require("node:child_process");
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const config_plugins_1 = require("@expo/config-plugins");
|
|
7
|
+
const generateCode_1 = require("@expo/config-plugins/build/utils/generateCode");
|
|
8
|
+
function appendContents({ src, newSrc, tag, comment }) {
|
|
9
|
+
const header = (0, generateCode_1.createGeneratedHeaderComment)(newSrc, tag, comment);
|
|
10
|
+
if (!src.includes(header)) {
|
|
11
|
+
const sanitizedTarget = (0, generateCode_1.removeGeneratedContents)(src, tag);
|
|
12
|
+
const contentsToAdd = [header, newSrc, `${comment} @generated end ${tag}`].join('\n');
|
|
13
|
+
return {
|
|
14
|
+
contents: `${sanitizedTarget !== null && sanitizedTarget !== void 0 ? sanitizedTarget : src}\n${contentsToAdd}`,
|
|
15
|
+
didClear: !!sanitizedTarget,
|
|
16
|
+
didMerge: true,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
return { contents: src, didClear: false, didMerge: false };
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Copy Google TapAndPay SDK files to Android libs directory
|
|
23
|
+
*/
|
|
24
|
+
function copyGoogleTapAndPaySdk(projectRoot, sdkPath) {
|
|
25
|
+
const resolvedSdkPath = (0, node_path_1.resolve)(projectRoot, sdkPath);
|
|
26
|
+
const androidLibsPath = (0, node_path_1.join)(projectRoot, 'android', 'libs');
|
|
27
|
+
// Create libs directory if it doesn't exist
|
|
28
|
+
if (!(0, node_fs_1.existsSync)(androidLibsPath)) {
|
|
29
|
+
(0, node_fs_1.mkdirSync)(androidLibsPath, { recursive: true });
|
|
30
|
+
}
|
|
31
|
+
// Check if SDK path exists
|
|
32
|
+
if (!(0, node_fs_1.existsSync)(resolvedSdkPath)) {
|
|
33
|
+
throw new Error(`Google TapAndPay SDK path not found: ${resolvedSdkPath}`);
|
|
34
|
+
}
|
|
35
|
+
const fileExtension = (0, node_path_1.extname)(resolvedSdkPath).toLowerCase();
|
|
36
|
+
if (fileExtension === '.zip') {
|
|
37
|
+
// Extract ZIP file contents using system unzip command
|
|
38
|
+
try {
|
|
39
|
+
(0, node_child_process_1.execSync)(`unzip -o "${resolvedSdkPath}" -d "${androidLibsPath}"`, {
|
|
40
|
+
stdio: 'pipe',
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
throw new Error(`Failed to extract ZIP file: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else if ((0, node_fs_1.statSync)(resolvedSdkPath).isDirectory()) {
|
|
48
|
+
// Copy all files from SDK directory to libs
|
|
49
|
+
const files = (0, node_fs_1.readdirSync)(resolvedSdkPath);
|
|
50
|
+
files.forEach((file) => {
|
|
51
|
+
const srcFile = (0, node_path_1.join)(resolvedSdkPath, file);
|
|
52
|
+
const destFile = (0, node_path_1.join)(androidLibsPath, file);
|
|
53
|
+
if ((0, node_fs_1.statSync)(srcFile).isFile()) {
|
|
54
|
+
(0, node_fs_1.copyFileSync)(srcFile, destFile);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
// If it's a single file, copy it directly
|
|
60
|
+
const fileName = resolvedSdkPath.split('/').pop() || 'google-tap-and-pay.aar';
|
|
61
|
+
(0, node_fs_1.copyFileSync)(resolvedSdkPath, (0, node_path_1.join)(androidLibsPath, fileName));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Config plugin for react-native-wallet
|
|
66
|
+
* Configures native Android and iOS projects for wallet functionality
|
|
67
|
+
*/
|
|
68
|
+
const withReactNativeWallet = (config, { googleTapAndPaySdkPath, enableApplePayProvisioning = true } = {}) => {
|
|
69
|
+
// Configure iOS
|
|
70
|
+
let modifiedConfig = withReactNativeWalletIOS(config, {
|
|
71
|
+
enableApplePayProvisioning,
|
|
72
|
+
});
|
|
73
|
+
// Configure Android
|
|
74
|
+
modifiedConfig = withReactNativeWalletAndroid(modifiedConfig, {
|
|
75
|
+
googleTapAndPaySdkPath,
|
|
76
|
+
});
|
|
77
|
+
return modifiedConfig;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Configure iOS for react-native-wallet
|
|
81
|
+
*/
|
|
82
|
+
const withReactNativeWalletIOS = (config, { enableApplePayProvisioning }) => {
|
|
83
|
+
if (!enableApplePayProvisioning) {
|
|
84
|
+
return config;
|
|
85
|
+
}
|
|
86
|
+
return (0, config_plugins_1.withInfoPlist)(config, (c) => {
|
|
87
|
+
// Add Apple Pay In-App Provisioning entitlement
|
|
88
|
+
// Following the structure from the documentation
|
|
89
|
+
// eslint-disable-next-line no-param-reassign
|
|
90
|
+
c.modResults['com.apple.developer.payment-pass-provisioning'] = true;
|
|
91
|
+
return c;
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Configure Android for react-native-wallet
|
|
96
|
+
*/
|
|
97
|
+
const withReactNativeWalletAndroid = (config, { googleTapAndPaySdkPath }) => {
|
|
98
|
+
if (!googleTapAndPaySdkPath) {
|
|
99
|
+
return config;
|
|
100
|
+
}
|
|
101
|
+
return (0, config_plugins_1.withProjectBuildGradle)(config, (c) => {
|
|
102
|
+
// Copy Google TapAndPay SDK files to android/libs
|
|
103
|
+
copyGoogleTapAndPaySdk(c.modRequest.projectRoot, googleTapAndPaySdkPath);
|
|
104
|
+
if (c.modResults.language === 'groovy') {
|
|
105
|
+
// Configure gradle to use the local libs directory
|
|
106
|
+
// This follows the pattern from react-native-wallet documentation
|
|
107
|
+
const gradleMaven = `allprojects {
|
|
108
|
+
repositories {
|
|
109
|
+
google()
|
|
110
|
+
maven { url "file://\${rootDir}/libs" }
|
|
111
|
+
}
|
|
112
|
+
}`;
|
|
113
|
+
// eslint-disable-next-line no-param-reassign
|
|
114
|
+
c.modResults.contents = appendContents({
|
|
115
|
+
comment: '//',
|
|
116
|
+
newSrc: gradleMaven,
|
|
117
|
+
src: c.modResults.contents,
|
|
118
|
+
tag: 'react-native-wallet-libs-repository',
|
|
119
|
+
}).contents;
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
throw new Error('Cannot add react-native-wallet maven repository because the build.gradle is not groovy');
|
|
123
|
+
}
|
|
124
|
+
return c;
|
|
125
|
+
});
|
|
126
|
+
};
|
|
127
|
+
exports.default = (0, config_plugins_1.createRunOncePlugin)(withReactNativeWallet, 'ReactNativeWallet', '0.1.0');
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import {execSync} from 'node:child_process';
|
|
2
|
+
import {copyFileSync, existsSync, mkdirSync, readdirSync, statSync} from 'node:fs';
|
|
3
|
+
import {extname, join, resolve} from 'node:path';
|
|
4
|
+
import type {ConfigPlugin} from '@expo/config-plugins';
|
|
5
|
+
import {createRunOncePlugin, withInfoPlist, withProjectBuildGradle} from '@expo/config-plugins';
|
|
6
|
+
import {createGeneratedHeaderComment, removeGeneratedContents} from '@expo/config-plugins/build/utils/generateCode';
|
|
7
|
+
|
|
8
|
+
export type ReactNativeWalletConfig = {
|
|
9
|
+
/**
|
|
10
|
+
* Path to the Google TapAndPay SDK for Android
|
|
11
|
+
* This should be the path to a ZIP file containing the Google TapAndPay SDK files,
|
|
12
|
+
* or a directory containing the SDK files, or a single SDK file (.aar)
|
|
13
|
+
*/
|
|
14
|
+
googleTapAndPaySdkPath?: string;
|
|
15
|
+
/**
|
|
16
|
+
* iOS Apple Pay In-App Provisioning entitlement
|
|
17
|
+
* default true
|
|
18
|
+
*/
|
|
19
|
+
enableApplePayProvisioning?: boolean;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
interface AppendContentsParams {
|
|
23
|
+
src: string;
|
|
24
|
+
newSrc: string;
|
|
25
|
+
tag: string;
|
|
26
|
+
comment: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function appendContents({src, newSrc, tag, comment}: AppendContentsParams): {
|
|
30
|
+
contents: string;
|
|
31
|
+
didClear: boolean;
|
|
32
|
+
didMerge: boolean;
|
|
33
|
+
} {
|
|
34
|
+
const header = createGeneratedHeaderComment(newSrc, tag, comment);
|
|
35
|
+
if (!src.includes(header)) {
|
|
36
|
+
const sanitizedTarget = removeGeneratedContents(src, tag);
|
|
37
|
+
const contentsToAdd = [header, newSrc, `${comment} @generated end ${tag}`].join('\n');
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
contents: `${sanitizedTarget ?? src}\n${contentsToAdd}`,
|
|
41
|
+
didClear: !!sanitizedTarget,
|
|
42
|
+
didMerge: true,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return {contents: src, didClear: false, didMerge: false};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Copy Google TapAndPay SDK files to Android libs directory
|
|
50
|
+
*/
|
|
51
|
+
function copyGoogleTapAndPaySdk(projectRoot: string, sdkPath: string): void {
|
|
52
|
+
const resolvedSdkPath = resolve(projectRoot, sdkPath);
|
|
53
|
+
const androidLibsPath = join(projectRoot, 'android', 'libs');
|
|
54
|
+
|
|
55
|
+
// Create libs directory if it doesn't exist
|
|
56
|
+
if (!existsSync(androidLibsPath)) {
|
|
57
|
+
mkdirSync(androidLibsPath, {recursive: true});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Check if SDK path exists
|
|
61
|
+
if (!existsSync(resolvedSdkPath)) {
|
|
62
|
+
throw new Error(`Google TapAndPay SDK path not found: ${resolvedSdkPath}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const fileExtension = extname(resolvedSdkPath).toLowerCase();
|
|
66
|
+
|
|
67
|
+
if (fileExtension === '.zip') {
|
|
68
|
+
// Extract ZIP file contents using system unzip command
|
|
69
|
+
try {
|
|
70
|
+
execSync(`unzip -o "${resolvedSdkPath}" -d "${androidLibsPath}"`, {
|
|
71
|
+
stdio: 'pipe',
|
|
72
|
+
});
|
|
73
|
+
} catch (error) {
|
|
74
|
+
throw new Error(`Failed to extract ZIP file: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
75
|
+
}
|
|
76
|
+
} else if (statSync(resolvedSdkPath).isDirectory()) {
|
|
77
|
+
// Copy all files from SDK directory to libs
|
|
78
|
+
const files = readdirSync(resolvedSdkPath);
|
|
79
|
+
files.forEach((file) => {
|
|
80
|
+
const srcFile = join(resolvedSdkPath, file);
|
|
81
|
+
const destFile = join(androidLibsPath, file);
|
|
82
|
+
|
|
83
|
+
if (statSync(srcFile).isFile()) {
|
|
84
|
+
copyFileSync(srcFile, destFile);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
} else {
|
|
88
|
+
// If it's a single file, copy it directly
|
|
89
|
+
const fileName = resolvedSdkPath.split('/').pop() || 'google-tap-and-pay.aar';
|
|
90
|
+
copyFileSync(resolvedSdkPath, join(androidLibsPath, fileName));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Config plugin for react-native-wallet
|
|
96
|
+
* Configures native Android and iOS projects for wallet functionality
|
|
97
|
+
*/
|
|
98
|
+
const withReactNativeWallet: ConfigPlugin<ReactNativeWalletConfig> = (config, {googleTapAndPaySdkPath, enableApplePayProvisioning = true} = {}) => {
|
|
99
|
+
// Configure iOS
|
|
100
|
+
let modifiedConfig = withReactNativeWalletIOS(config, {
|
|
101
|
+
enableApplePayProvisioning,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Configure Android
|
|
105
|
+
modifiedConfig = withReactNativeWalletAndroid(modifiedConfig, {
|
|
106
|
+
googleTapAndPaySdkPath,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
return modifiedConfig;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Configure iOS for react-native-wallet
|
|
114
|
+
*/
|
|
115
|
+
const withReactNativeWalletIOS: ConfigPlugin<{
|
|
116
|
+
enableApplePayProvisioning: boolean;
|
|
117
|
+
}> = (config, {enableApplePayProvisioning}) => {
|
|
118
|
+
if (!enableApplePayProvisioning) {
|
|
119
|
+
return config;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return withInfoPlist(config, (c) => {
|
|
123
|
+
// Add Apple Pay In-App Provisioning entitlement
|
|
124
|
+
// Following the structure from the documentation
|
|
125
|
+
// eslint-disable-next-line no-param-reassign
|
|
126
|
+
c.modResults['com.apple.developer.payment-pass-provisioning'] = true;
|
|
127
|
+
|
|
128
|
+
return c;
|
|
129
|
+
});
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Configure Android for react-native-wallet
|
|
134
|
+
*/
|
|
135
|
+
const withReactNativeWalletAndroid: ConfigPlugin<{
|
|
136
|
+
googleTapAndPaySdkPath?: string;
|
|
137
|
+
}> = (config, {googleTapAndPaySdkPath}) => {
|
|
138
|
+
if (!googleTapAndPaySdkPath) {
|
|
139
|
+
return config;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return withProjectBuildGradle(config, (c) => {
|
|
143
|
+
// Copy Google TapAndPay SDK files to android/libs
|
|
144
|
+
copyGoogleTapAndPaySdk(c.modRequest.projectRoot, googleTapAndPaySdkPath);
|
|
145
|
+
|
|
146
|
+
if (c.modResults.language === 'groovy') {
|
|
147
|
+
// Configure gradle to use the local libs directory
|
|
148
|
+
// This follows the pattern from react-native-wallet documentation
|
|
149
|
+
const gradleMaven = `allprojects {
|
|
150
|
+
repositories {
|
|
151
|
+
google()
|
|
152
|
+
maven { url "file://\${rootDir}/libs" }
|
|
153
|
+
}
|
|
154
|
+
}`;
|
|
155
|
+
// eslint-disable-next-line no-param-reassign
|
|
156
|
+
c.modResults.contents = appendContents({
|
|
157
|
+
comment: '//',
|
|
158
|
+
newSrc: gradleMaven,
|
|
159
|
+
src: c.modResults.contents,
|
|
160
|
+
tag: 'react-native-wallet-libs-repository',
|
|
161
|
+
}).contents;
|
|
162
|
+
} else {
|
|
163
|
+
throw new Error('Cannot add react-native-wallet maven repository because the build.gradle is not groovy');
|
|
164
|
+
}
|
|
165
|
+
return c;
|
|
166
|
+
});
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
export default createRunOncePlugin(withReactNativeWallet, 'ReactNativeWallet', '0.1.0');
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"outDir": "build",
|
|
4
|
+
"rootDir": "src",
|
|
5
|
+
"target": "ES2019",
|
|
6
|
+
"module": "commonjs",
|
|
7
|
+
"lib": ["ES2019"],
|
|
8
|
+
"jsx": "react",
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"strict": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"skipLibCheck": true,
|
|
13
|
+
"moduleResolution": "node",
|
|
14
|
+
"resolveJsonModule": true
|
|
15
|
+
},
|
|
16
|
+
"include": ["./src"],
|
|
17
|
+
"exclude": ["**/__mocks__/*", "**/__tests__/*"]
|
|
18
|
+
}
|
package/src/index.tsx
CHANGED
|
@@ -130,7 +130,7 @@ async function addCardToAppleWallet(
|
|
|
130
130
|
issuerEncryptPayloadCallback: (nonce: string, nonceSignature: string, certificate: string[]) => Promise<IOSEncryptPayload>,
|
|
131
131
|
): Promise<TokenizationStatus> {
|
|
132
132
|
if (Platform.OS === 'android') {
|
|
133
|
-
throw new Error('addCardToAppleWallet is not available on
|
|
133
|
+
throw new Error('addCardToAppleWallet is not available on Android');
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
const passData = await Wallet?.IOSPresentAddPaymentPassView(cardData);
|