Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ Future<void> confirmApplePayPayment(...);
Future<SetupIntent> confirmSetupIntent(...);
Future<PaymentIntent> retrievePaymentIntent(...);
Future<String> createTokenForCVCUpdate(...);

Future<void> initPaymentSheet(...);
Future<void> presentPaymentSheet(...);
Future<void> confirmPaymentSheetPayment()
```
The example app offers examples on how to use these methods.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.flutter.stripe.example

import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.android.FlutterFragmentActivity

class MainActivity: FlutterActivity() {
class MainActivity: FlutterFragmentActivity() {
}
4 changes: 2 additions & 2 deletions stripe/example/android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
buildscript {
ext.kotlin_version = '1.3.50'
ext.kotlin_version = '1.5.0'
repositories {
google()
jcenter()
}

dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath 'com.android.tools.build:gradle:4.1.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
Expand Down
38 changes: 38 additions & 0 deletions stripe/example/assets/google_pay_payment_profile.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"provider": "google_pay",
"data": {
"environment": "TEST",
"apiVersion": 2,
"apiVersionMinor": 0,
"allowedPaymentMethods": [
{
"type": "CARD",
"tokenizationSpecification": {
"type": "PAYMENT_GATEWAY",
"parameters": {
"gateway": "stripe",
"stripe:version": "2020-08-27",
"stripe:publishableKey": "<ADD_YOUR_KEY_HERE>"
}
},
"parameters": {
"allowedCardNetworks": ["VISA", "MASTERCARD"],
"allowedAuthMethods": ["PAN_ONLY", "CRYPTOGRAM_3DS"],
"billingAddressRequired": true,
"billingAddressParameters": {
"format": "FULL",
"phoneNumberRequired": true
}
}
}
],
"merchantInfo": {
"merchantId": "01234567890123456789",
"merchantName": "Example Merchant Name"
},
"transactionInfo": {
"countryCode": "US",
"currencyCode": "USD"
}
}
}
18 changes: 12 additions & 6 deletions stripe/example/ios/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
PODS:
- Flutter (1.0.0)
- Stripe (21.4.0):
- Stripe/Stripe3DS2 (= 21.4.0)
- Stripe/Stripe3DS2 (21.4.0)
- pay_ios (0.0.1):
- Flutter
- Stripe (21.5.1):
- Stripe/Stripe3DS2 (= 21.5.1)
- Stripe/Stripe3DS2 (21.5.1)
- stripe_ios (0.0.1):
- Flutter
- Stripe (~> 21.4.0)
- Stripe (~> 21.5.1)

DEPENDENCIES:
- Flutter (from `Flutter`)
- pay_ios (from `.symlinks/plugins/pay_ios/ios`)
- stripe_ios (from `.symlinks/plugins/stripe_ios/ios`)

SPEC REPOS:
Expand All @@ -18,13 +21,16 @@ SPEC REPOS:
EXTERNAL SOURCES:
Flutter:
:path: Flutter
pay_ios:
:path: ".symlinks/plugins/pay_ios/ios"
stripe_ios:
:path: ".symlinks/plugins/stripe_ios/ios"

SPEC CHECKSUMS:
Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
Stripe: 7c594b943abb65cf7bc28e37fd5124e65db3ce9e
stripe_ios: feb8a911b1c8ffb18da7aa225d3cc9c10c91100b
pay_ios: 8c7beb9c61d885f3f51b61f75f8793023fc8843a
Stripe: 515db5536fd659b5d79a0898ce1b882b61ab597e
stripe_ios: ce035050135b58a5a838e0d410d53b26f1dc026a

PODFILE CHECKSUM: 7368163408c647b7eb699d0d788ba6718e18fb8d

Expand Down
1 change: 1 addition & 0 deletions stripe/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'widgets/dismiss_focus_overlay.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
Stripe.publishableKey = stripePublishableKey;
Stripe.merchantIdentifier = 'MerchantIdentifier';
runApp(App());
}

Expand Down
107 changes: 107 additions & 0 deletions stripe/example/lib/screens/apple_pay_screen.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:flutter_stripe/flutter_stripe.dart';
import 'package:stripe_example/widgets/loading_button.dart';
import 'package:stripe_platform_interface/stripe_platform_interface.dart';

import '../config.dart';

class ApplePayScreen extends StatefulWidget {
@override
_ApplePayScreenState createState() => _ApplePayScreenState();
}

class _ApplePayScreenState extends State<ApplePayScreen> {

@override
void initState() {
Stripe.instance.isApplePaySupported.addListener(update);
super.initState();
}

@override
void dispose() {
Stripe.instance.isApplePaySupported.removeListener(update);
super.dispose();
}

void update() {
setState(() {});
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
children: [
if (Stripe.instance.isApplePaySupported.value)
Padding(
padding: EdgeInsets.all(16),
child: ApplePayButton(
onPressed: _handlePayPress,
),
)
else
Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Text('Apple Pay is not available in this device'),
),
],
),
);
}

Future<void> _handlePayPress() async {
try {
// 1. Present Apple Pay sheet
await Stripe.instance.presentApplePay(
ApplePayPresentParams(
cartItems: [
ApplePayCartSummaryItem(
label: 'Product Test',
amount: '20',
),
],
country: 'Es',
currency: 'EUR',
),
);

// 2. fetch Intent Client Secret from backend
final response = await fetchPaymentIntentClientSecret();
final clientSecret = response['clientSecret'];

// 2. Confirm apple pay payment
await Stripe.instance.confirmApplePayPayment(clientSecret);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Apple Pay payment succesfully completed')),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: $e')),
);
}
}

Future<Map<String, dynamic>> fetchPaymentIntentClientSecret() async {
final url = Uri.parse('$kApiUrl/create-payment-intent');
final response = await http.post(
url,
headers: {
'Content-Type': 'application/json',
},
body: json.encode({
'email': '[email protected]',
'currency': 'usd',
'items': [
{'id': 'id'}
],
'request_three_d_secure': 'any',
}),
);
return json.decode(response.body);
}
}
140 changes: 140 additions & 0 deletions stripe/example/lib/screens/google_pay_screen.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import 'dart:convert';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;
import 'package:flutter_stripe/flutter_stripe.dart';
import 'package:stripe_example/widgets/loading_button.dart';
import 'package:stripe_platform_interface/stripe_platform_interface.dart';
import 'package:pay/pay.dart' as pay;
import '../config.dart';

const _paymentItems = [
pay.PaymentItem(
label: 'Total',
amount: '99.99',
status: pay.PaymentItemStatus.final_price,
)
];

class GooglePayScreen extends StatefulWidget {
@override
_GooglePayScreenState createState() => _GooglePayScreenState();
}

class _GooglePayScreenState extends State<GooglePayScreen> {
@override
void initState() {
super.initState();
}

@override
void dispose() {
super.dispose();
}

void update() {
setState(() {});
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: const EdgeInsets.all(16),
child: pay.GooglePayButton(
paymentConfigurationAsset: 'google_pay_payment_profile.json',
paymentItems: _paymentItems,
margin: const EdgeInsets.only(top: 15),
onPaymentResult: onGooglePayResult,
loadingIndicator: const Center(
child: CircularProgressIndicator(),
),
onPressed: () async {
// 1. Add your stripe publishable key to assets/google_pay_payment_profile.json
await debugChangedStripePublishableKey();
},
onError: (e) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
'There was an error while trying to perform the payment'),
),
);
},
),
)
],
),
);
}

Future<void> onGooglePayResult(paymentResult) async {
try {
// 1. Add your stripe publishable key to assets/google_pay_payment_profile.json


debugPrint(paymentResult.toString());
// 2. fetch Intent Client Secret from backend
final response = await fetchPaymentIntentClientSecret();
final clientSecret = response['clientSecret'];
final token =
paymentResult['paymentMethodData']['tokenizationData']['token'];
final Map<String, dynamic> tokenJson = Map.castFrom(json.decode(token));
print(tokenJson);

final params = PaymentMethodParams.cardFromToken(
token: tokenJson['id'], // TODO extract the actual token
);

// 3. Confirm Google pay payment method
await Stripe.instance.confirmPaymentMethod(
clientSecret,
params,
);

ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Google Pay payment succesfully completed')),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: $e')),
);
}
}

Future<Map<String, dynamic>> fetchPaymentIntentClientSecret() async {
final url = Uri.parse('$kApiUrl/create-payment-intent');
final response = await http.post(
url,
headers: {
'Content-Type': 'application/json',
},
body: json.encode({
'email': '[email protected]',
'currency': 'usd',
'items': [
{'id': 'id'}
],
'request_three_d_secure': 'any',
}),
);
return json.decode(response.body);
}

Future<void> debugChangedStripePublishableKey() async {
if (kDebugMode) {
final profile =
await rootBundle.loadString('assets/google_pay_payment_profile.json');
final isValidKey = !profile.contains('<ADD_YOUR_KEY_HERE>');
assert(isValidKey,
'No stripe publishable key added to assets/google_pay_payment_profile.json',);
}
}
}
Loading