@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 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. Send an email to apple-pay-provisioning@apple.com with your app name, Team ID, and Adam ID.
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
@@ -0,0 +1,2 @@
1
+ // This file configures the entry file for your plugin.
2
+ module.exports = require('./plugins/build');
@@ -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 _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
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 Andorid');
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","_getRequireWildcardCache","WeakMap","r","t","has","get","n","__proto__","a","Object","defineProperty","getOwnPropertyDescriptor","u","hasOwnProperty","call","i","set","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":[]}
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":[]}
@@ -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 Andorid');
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.15",
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 '/example/**/*' --ignore-pattern '/WebExample/**/*'",
36
- "lint:example": "eslint example --ext .js,.ts,.tsx",
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": "^2.0.24",
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
+ }
@@ -25,7 +25,7 @@ Pod::Spec.new do |s|
25
25
  s.source = { :git => "https://github.com/Expensify/react-native-wallet.git", :tag => "#{s.version}" }
26
26
 
27
27
  s.source_files = "ios/**/*.{h,m,mm,cpp,swift}"
28
-
28
+
29
29
  s.dependency "React-Core"
30
30
 
31
31
  install_modules_dependencies(s);
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 Andorid');
133
+ throw new Error('addCardToAppleWallet is not available on Android');
134
134
  }
135
135
 
136
136
  const passData = await Wallet?.IOSPresentAddPaymentPassView(cardData);