Skip to content

Commit 5b45f79

Browse files
authored
Android Pay Support (naoufal#17)
* Add Android Pay support * Update docs * Add Android Pay to lib * Update example * Update yarn.lock files * Update demo build
1 parent 56136da commit 5b45f79

File tree

24 files changed

+952
-243
lines changed

24 files changed

+952
-243
lines changed

README.md

+132-16
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,19 @@
66
[![npm](https://img.shields.io/npm/dm/react-native-payments.svg?style=flat-square)](https://www.npmjs.com/package/react-native-payments)
77
[![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)
88

9-
Accept Payments with Apple Pay using the [Payment Request API](https://paymentrequest.show).
9+
Accept Payments with Apple Pay and Android Pay using the [Payment Request API](https://paymentrequest.show).
1010

1111
__Features__
1212
- __Simple.__ No more checkout forms.
1313
- __Effective__. Faster checkouts that increase conversion.
1414
- __Future-proof__. Use a W3C Standards API, supported by companies like Google, Firefox and others.
15-
- __Cross-platform__. Share payments code between your iOS and web apps.
15+
- __Cross-platform__. Share payments code between your iOS, Android, and web apps.
1616
- __Add-ons__. Easily enable support for Stripe or Braintree via add-ons.
1717

18+
<div>
1819
<img width="280px" src="https://user-images.githubusercontent.com/1627824/27758096-9fc6bf9a-5dc1-11e7-9d8f-b2d409302fc7.gif" />
20+
<img width="280px" src="https://user-images.githubusercontent.com/1627824/30039983-d75d1b3e-91d8-11e7-9ac9-71d2ed12958c.png" />
21+
</div>
1922

2023
---
2124

@@ -50,7 +53,7 @@ $ react-native link react-native-payments
5053
```
5154

5255
## Usage
53-
- [Registering as a Merchant](#registering-as-a-merchant)
56+
- [Setting up Apple Pay/Android Pay](#setting-up-apple-payandroid-pay)
5457
- [Importing the Library](#importing-the-library)
5558
- [Initializing the Payment Request](#initializing-the-payment-request)
5659
- [Displaying the Payment Request](#displaying-the-payment-request)
@@ -61,17 +64,25 @@ $ react-native link react-native-payments
6164
- [Dismissing the Payment Request](#dismissing-the-payment-request)
6265

6366

64-
### Registering as a Merchant
65-
Before you can start accepting payments with Apple Pay, there are a few steps you'll need to go through:
67+
### Setting up Apple Pay/Android Pay
68+
Before you can start accepting payments in your App, you'll need to setup Apple Pay and/or Android Pay.
6669

70+
#### Apple Pay
6771
1. Register as an Apple Developer
6872
1. Obtain a merchant ID
69-
2. Enable Apple Pay in your app
73+
1. Enable Apple Pay in your app
7074

71-
Apple has a documentation on how to do both of these in their _[Configuring your Environment](https://developer.apple.com/library/content/ApplePay_Guide/Configuration.html)_ guide.
75+
Apple has a documentation on how to do this in their _[Configuring your Environment](https://developer.apple.com/library/content/ApplePay_Guide/Configuration.html)_ guide.
76+
77+
#### Android Pay
78+
79+
1. Add Android Pay and Google Play Services to your dependencies
80+
1. Enable Android Pay in your Manifest
81+
82+
Google has documentation on how to do this in their _[Setup Android Pay](https://developers.google.com/android-pay/setup)_ guide.
7283

7384
### Importing the Library
74-
Once Apple Pay is enabled in your app, jump into your app's entrypoint and make the `PaymentRequest` globally available to your app.
85+
Once Apple Pay/Android Pay is enabled in your app, jump into your app's entrypoint and make the `PaymentRequest` globally available to your app.
7586

7687
```es6
7788
// index.ios.js
@@ -96,6 +107,29 @@ const METHOD_DATA = [{
96107
}];
97108
```
98109

110+
<details>
111+
<summary><strong>See Android Pay Example</strong></summary>
112+
<br/>
113+
114+
```es6
115+
const METHOD_DATA = [{
116+
supportedMethods: ['android-pay'],
117+
data: {
118+
supportedNetworks: ['visa', 'mastercard', 'amex'],
119+
currencyCode: 'USD',
120+
environment: 'TEST', // defaults to production
121+
paymentMethodTokenizationParameters: {
122+
tokenizationType: 'NETWORK_TOKEN',
123+
parameters: {
124+
publicKey: 'your-pubic-key'
125+
}
126+
}
127+
}
128+
}];
129+
```
130+
131+
</details>
132+
99133
#### Payment Details
100134
Payment Details is where define transaction details like display items, a total and optionally shipping options.
101135

@@ -123,6 +157,8 @@ Once you've defined your `methodData` and `details`, you're ready to initialize
123157
const paymentRequest = new PaymentRequest(METHOD_DATA, DETAILS);
124158
```
125159

160+
🚨 _Note: On Android, display items are not displayed within the Android Pay view. Instead, the _[User Flows documentation](https://developers.google.com/android-pay/payment-flows)_ suggests showing users a confirmation view where you list the display items. When using React Native Payments, show this view after receiving the `PaymentResponse`._
161+
126162
### Displaying the Payment Request
127163
Now that you've setup your Payment Request, displaying it is as simple as calling the `show` method.
128164

@@ -131,9 +167,10 @@ paymentRequest.show();
131167
```
132168

133169
<details>
134-
<summary><strong>See Screenshot</strong></summary>
170+
<summary><strong>See Screenshots</strong></summary>
135171
<br/>
136172
<img width="250px" src="https://user-images.githubusercontent.com/1627824/27548765-be9121c0-5a4e-11e7-8e45-4b460e314e6a.png" />
173+
<img width="250px" src="https://user-images.githubusercontent.com/1627824/30039982-d565c68c-91d8-11e7-9cb9-2a0e58fffe6a.png" />
137174

138175
</details>
139176

@@ -144,6 +181,8 @@ You can abort the Payment Request at any point by calling the `abort` method.
144181
paymentRequest.abort();
145182
```
146183

184+
🚨 _Note: Not yet implemented on Android Pay_
185+
147186
### Requesting Contact Information
148187
Some apps may require contact information from a user. You can do so by providing a [`PaymentOptions`]() as a third argument when initializing a Payment Request. Using Payment Options, you can request a contact name, phone number and/or email.
149188

@@ -157,12 +196,15 @@ const OPTIONS = {
157196
```
158197

159198
<details>
160-
<summary><strong>See Screenshot</strong></summary>
199+
<summary><strong>See Screenshots</strong></summary>
161200
<br/>
162201
<img width="250px" src="https://user-images.githubusercontent.com/1627824/27549933-9be15be6-5a52-11e7-868a-abcfc8867968.png" />
202+
<img width="250px" src="https://user-images.githubusercontent.com/1627824/30039983-d75d1b3e-91d8-11e7-9ac9-71d2ed12958c.png" />
163203

164204
</details>
205+
<br/>
165206

207+
🚨 _Note: On Android, requesting a contact name will present the user with a shipping address selector. If you're not shipping anything to the user, consider capturing the contact name outside of Android Pay._
166208

167209
#### Requesting a Phone Number
168210
Set `requestPayerPhone` to `true` to request a phone number.
@@ -174,11 +216,15 @@ const OPTIONS = {
174216
```
175217

176218
<details>
177-
<summary><strong>See Screenshot</strong></summary>
219+
<summary><strong>See Screenshots</strong></summary>
178220
<br/>
179221
<img width="250px" src="https://user-images.githubusercontent.com/1627824/27549958-b6732160-5a52-11e7-8813-3beeeed03b9c.png" />
222+
<img width="250px" src="https://user-images.githubusercontent.com/1627824/30039983-d75d1b3e-91d8-11e7-9ac9-71d2ed12958c.png" />
180223

181224
</details>
225+
<br/>
226+
227+
🚨 _Note: On Android, requesting a phone number will present the user with a shipping address selector. If you're not shipping anything to the user, consider capturing the phone number outside of Android Pay._
182228

183229
#### Requesting an Email Address
184230
Set `requestPayerEmail` to `true` to request an email address.
@@ -190,9 +236,10 @@ const OPTIONS = {
190236
```
191237

192238
<details>
193-
<summary><strong>See Screenshot</strong></summary>
239+
<summary><strong>See Screenshots</strong></summary>
194240
<br/>
195241
<img width="250px" src="https://user-images.githubusercontent.com/1627824/27549968-c172ac34-5a52-11e7-973d-8d06a3beb5ce.png" />
242+
<img width="250px" src="https://user-images.githubusercontent.com/1627824/30039982-d565c68c-91d8-11e7-9cb9-2a0e58fffe6a.png" />
196243

197244
</details>
198245
<br/>
@@ -251,7 +298,7 @@ paymentRequest.addEventListener('shippingaddresschange', e => {
251298
e.updateWith(updatedDetails);
252299
});
253300

254-
paymentRequest.addEventListener('shippingaddresschange', e => {
301+
paymentRequest.addEventListener('shippingoptionchange', e => {
255302
const updatedDetails = getUpdatedDetailsForShippingOption(paymentRequest.shippingOption);
256303

257304
e.updateWith(updatedDetails);
@@ -260,6 +307,8 @@ paymentRequest.addEventListener('shippingaddresschange', e => {
260307
261308
For a deeper dive on handling shipping in Payment Request, checkout Google's _[Shipping in Payment Request](https://developers.google.com/web/fundamentals/discovery-and-monetization/payment-request/deep-dive-into-payment-request#shipping_in_payment_request_api)_.
262309
310+
🚨 _Note: On Android, there are no `shippingaddresschange` and `shippingoptionchange` events. To allow users to update their shipping address, you'll need to trigger a new `PaymentRequest`. Updating shipping options typically happens after the receiving the `PaymentResponse` and before calling its `getPaymentToken` method._
311+
263312
### Processing Payments
264313
Now that we know how to initialize, display, and dismiss a Payment Request, let's take a look at how to process payments.
265314
@@ -274,10 +323,10 @@ paymentRequest.show()
274323
});
275324
```
276325
277-
There are two ways to process Apple Pay payments -- on your server or using a payment processor.
326+
There are two ways to process Apple Pay/Android Pay payments -- on your server or using a payment processor.
278327
279328
#### Processing Payments on Your Server
280-
If you're equiped to Apple Pay payments on your server, all you have to do is send the Payment Response's `transactionIdentifier` and `paymentData` to your server.
329+
If you're equiped to process Apple Pay/Android Pay payments on your server, all you have to do is send the Payment Response data to your server.
281330
282331
```es6
283332
import { NativeModules } from 'react-native';
@@ -299,6 +348,37 @@ paymentRequest.show()
299348
});
300349
```
301350
351+
<details>
352+
<summary><strong>See Android Pay Example</strong></summary>
353+
<br/>
354+
355+
```es6
356+
paymentRequest.show()
357+
.then(paymentResponse => {
358+
const { getPaymentToken } = paymentResponse.details;
359+
360+
return getPaymentToken()
361+
.then(paymentToken => {
362+
const { ephemeralPublicKey, encryptedMessage, tag } = paymentResponse.details;
363+
364+
return fetch('...', {
365+
method: 'POST',
366+
body: {
367+
ephemeralPublicKey,
368+
encryptedMessage,
369+
tag
370+
}
371+
})
372+
.then(res => res.json())
373+
.then(successHandler)
374+
.catch(errorHandler)
375+
});
376+
});
377+
```
378+
379+
</details>
380+
<br/>
381+
302382
You can learn more about server-side decrypting of Payment Tokens on Apple's [Payment Token Format Reference](https://developer.apple.com/library/content/documentation/PassKit/Reference/PaymentTokenJSON/PaymentTokenJSON.html) documentation.
303383
304384
#### Processing Payments with a Payment Processor
@@ -307,7 +387,7 @@ When using a payment processor, you'll receive a `paymentToken` field within the
307387
```es6
308388
paymentRequest.show()
309389
.then(paymentResponse => {
310-
const { paymentToken } = paymentResponse.details;
390+
const { paymentToken } = paymentResponse.details; // On Android, you need to invoke the `getPaymentToken` method to receive the `paymentToken`.
311391

312392
return fetch('...', {
313393
method: 'POST',
@@ -321,6 +401,32 @@ paymentRequest.show()
321401
});
322402
```
323403
404+
<details>
405+
<summary><strong>See Android Pay Example</strong></summary>
406+
<br/>
407+
408+
```es6
409+
paymentRequest.show()
410+
.then(paymentResponse => {
411+
const { getPaymentToken } = paymentResponse.details;
412+
413+
return getPaymentToken()
414+
.then(paymentToken => fetch('...', {
415+
method: 'POST',
416+
body: {
417+
paymentToken
418+
}
419+
})
420+
.then(res => res.json())
421+
.then(successHandler)
422+
.catch(errorHandler);
423+
});
424+
});
425+
```
426+
427+
</details>
428+
<br/>
429+
324430
For a list of supported payment processors and how to enable them, see the [Add-ons](#add-ons) section.
325431
326432
### Dismissing the Payment Request
@@ -330,11 +436,15 @@ Dismissing the Payment Request is as simple as calling the `complete` method on
330436
paymentResponse.complete('success'); // Alternatively, you can call it with `fail` or `unknown`
331437
```
332438
439+
🚨 _Note: On Android, there is no need to call `paymentResponse.complete` -- the PaymentRequest dismisses itself._
440+
333441
## Add-ons
334442
Here's a list of Payment Processors that you can enable via add-ons:
335443
- [Stripe](https://github.com/naoufal/react-native-payments/blob/master/packages/react-native-payments-addon-stripe)
336444
- [Braintree](https://github.com/naoufal/react-native-payments/blob/master/cli/packages/react-native-payments-addon-braintree)
337445
446+
🚨 _Note: On Android, Payment Processors are enabled by default._
447+
338448
## API
339449
### [PaymentRequest](https://github.com/naoufal/react-native-payments/blob/master/cli/packages/react-native-payments/docs/PaymentRequest.md)
340450
### [PaymentRequestUpdateEvent](https://github.com/naoufal/react-native-payments/blob/master/cli/packages/react-native-payments/docs/PaymentRequestUpdateEvent.md)
@@ -354,6 +464,12 @@ Here's a list of Payment Processors that you can enable via add-ons:
354464
- [Processing Payments](https://developer.apple.com/library/content/ApplePay_Guide/ProcessPayment.html#//apple_ref/doc/uid/TP40014764-CH5-SW4)
355465
- [Payment Token Format Reference](https://developer.apple.com/library/content/documentation/PassKit/Reference/PaymentTokenJSON/PaymentTokenJSON.html#//apple_ref/doc/uid/TP40014929)
356466
467+
### Android Pay
468+
- [Setup Android Pay](https://developers.google.com/android-pay/setup)
469+
- [User Flows](https://developers.google.com/android-pay/payment-flows)
470+
- [Best Practices](https://developers.google.com/android-pay/best-practices)
471+
- [Gateway Token Approach](https://developers.google.com/web/fundamentals/discovery-and-monetization/payment-request/android-pay#gateway_token_approach)
472+
- [Network Token Approach](https://developers.google.com/web/fundamentals/discovery-and-monetization/payment-request/android-pay#network_token_approach)
357473
358474
# License
359475
Licensed under the MIT License, Copyright © 2017, [Naoufal Kadhom](https://twitter.com/naoufal).

packages/react-native-payments-addon-stripe/README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ const METHOD_DATA = [{
3636
+ paymentMethodTokenizationParameters: {
3737
+ parameters: {
3838
+ gateway: 'stripe',
39-
+ 'stripe:publishableKey': 'your_publishable_key'
39+
+ 'stripe:publishableKey': 'your_publishable_key',
40+
+ 'stripe:version': '5.0.0' // Only required on Android
4041
+ }
4142
+ }
4243
}
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,3 @@
1-
2-
buildscript {
3-
repositories {
4-
jcenter()
5-
}
6-
7-
dependencies {
8-
classpath 'com.android.tools.build:gradle:1.3.1'
9-
}
10-
}
11-
121
apply plugin: 'com.android.library'
132

143
android {
@@ -20,17 +9,17 @@ android {
209
targetSdkVersion 22
2110
versionCode 1
2211
versionName "1.0"
12+
ndk {
13+
abiFilters "armeabi-v7a", "x86"
14+
}
2315
}
2416
lintOptions {
25-
abortOnError false
17+
warning 'InvalidPackage'
2618
}
2719
}
2820

29-
repositories {
30-
mavenCentral()
31-
}
32-
3321
dependencies {
3422
compile 'com.facebook.react:react-native:+'
23+
compile 'com.google.android.gms:play-services-wallet:11.0.4'
24+
compile 'com.android.support:support-v4:23.0.1'
3525
}
36-
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11

22
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3-
package="com.reactlibrary">
3+
package="com.reactnativepayments">
44

55
</manifest>
6-

0 commit comments

Comments
 (0)