8
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Flutterで、flutter_stripeを利用してサブスクリプションの決済画面を作成する

Posted at

この記事は、Flutter Advent Calendar 2022 23日目の記事です。

Flutterを利用してDartでiOS / Androidに対応したアプリケーションを開発できます。

この記事では、FlutterでStripeの決済情報入力画面を表示するためのライブラリ「flutter_stripe」を利用して、サブスクリプションの申し込みを完了する方法を紹介します。

事前準備

Flutterを動かすために、DartとFlutter CLIをインストールしましょう。

Dartのインストール

Homebrewを利用して、Dartをインストールします。

$ brew tap dart-lang/dart
$ brew install dart

今回は、以下のバージョンを利用しています。

dart --version
Dart SDK version: 2.18.5 (stable) (Tue Nov 22 15:47:29 2022 +0000) on "macos_arm64"

Flutterのインストール

ドキュメントのガイドに従って、Flutterをインストールします。

今回は、以下のバージョンを利用しています。

$ flutter --version
Flutter 3.3.9 • channel stable • https://github.com/flutter/flutter.git
Framework • revision b8f7f1f986 (2 weeks ago) • 2022-11-23 06:43:51 +0900
Engine • revision 8f2221fbef
Tools • Dart 2.18.5 • DevTools 2.15.0

アプリのセットアップ

準備ができれば、アプリをセットアップします。

ここでは、flutter createを実行しましょう。

$ flutter create first_app
Creating project first_app...
Running "flutter pub get" in first_app...                        1,398ms
Wrote 127 files.

All done!
In order to run your application, type:

  $ cd first_app
  $ flutter run

Your application code is in first_app/lib/main.dart.

flutter runでアプリを起動できます。

スクリーンショット 2022-12-14 19.40.09.png

サブスクリプションデータを作成するAPIを用意しよう

Express.jsやNestJSなどで、サブスクリプションを作成するAPIを事前に用意しましょう。

app.post('/create_subscription', async (req, res) => {
    const { id: customerId } = await stripe.customers.create()
    const ephemeralKey = await stripe.ephemeralKeys.create({
      customer: customerId,
    }, {
      apiVersion: '2022-08-01'
    })
    const subscription = await stripe.subscriptions.create({
      customer: customerId,
      items: [{
        price: 'price_xxxx',
        quantity: 1,
      }],
      payment_behavior: 'default_incomplete',
      expand: ['latest_invoice.payment_intent'],
      payment_settings: {
          save_default_payment_method: 'on_subscription',
      },
    })
    return {
      clientSecret: subscription.latest_invoice.payment_intent.client_secret,
      ephemeralKey: ephemeralKey.secret,
      customerId
    }
})

Stripeのカード登録フォームを追加する

サブスクリプションの契約に利用するための、カード情報登録フォームを追加しましょう。

flutter_stripeパッケージを追加する

まずはflutter_stripeパッケージを追加します。

$ flutter pub get flutter_stripe
Downloading flutter_stripe 7.0.0...
Downloading stripe_platform_interface 7.0.0...
Downloading stripe_ios 7.0.0...
Downloading stripe_android 7.0.1...
Downloading json_annotation 4.7.0...
Downloading freezed_annotation 2.2.0...
Changed 7 dependencies!

pod installに失敗する場合

flutter runを実行すると、次のようなエラーが出ることがあります。

Analyzing dependencies
[!] CocoaPods could not find compatible versions for pod "stripe_ios":
  In Podfile:
    stripe_ios (from `.symlinks/plugins/stripe_ios/ios`)

Specs satisfying the `stripe_ios (from `.symlinks/plugins/stripe_ios/ios`)` dependency were found, but they required a higher minimum deployment target.

ios/Podfile/ios/Runner.xcodeproj/project.pbxprojのiOSバージョンを新しいバージョンに変更すると、解決することがあります。

+++ b/ios/Podfile
@@ -1,5 +1,5 @@
 # Uncomment this line to define a global platform for your project
-# platform :ios, '11.0'
+platform :ios, '13.0'
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -272,7 +272,7 @@
                                GCC_WARN_UNINITIALIZED_AUTOS = YES_AG
GRESSIVE;
                                GCC_WARN_UNUSED_FUNCTION = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+                               IPHONEOS_DEPLOYMENT_TARGET = 13.0;

参考: https://stackoverflow.com/questions/72485674/error-with-flutter-stripe-3-0-2-for-ios-11394

M1/M2系のMacbookなどを利用されている場合は、こちらもお試しください。

https://github.com/flutter/flutter/wiki/Developing-with-Flutter-on-Apple-Silicon

また、サーバー側でサブスクリプションを作成して取得するため、httpモジュールも追加します。

$ flutter pub add http
...
Downloading http 0.13.5...
Downloading http_parser 4.0.2...
Changed 3 dependencies!

flutter_stripeをセットアップする

lib/main.dartを変更して、ライブラリをセットアップします。

+import 'package:flutter_stripe/flutter_stripe.dart';
+import 'dart:developer' as developer;
import 'dart:convert';
+import 'package:http/http.dart' as http;

void main() {
  WidgetsFlutterBinding.ensureInitialized();
+  Stripe.publishableKey =
      'pk_test_から始まるStripeの公開可能キー';
  runApp(const MyApp());
}

lib/main.dartに決済画面を表示するボタンを追加する

決済画面(PaymentSheet)を表示するためのボタンを追加しましょう。

            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
+            ElevatedButton(
+              onPressed: () async {
+                try {
+                  developer.log("Hello");
+                } catch (e) {
+                  developer.log("error", error: e);
+                }
+              },
+              child: const Text("Show card form"),
+            )
          ],

ボタンが追加されました。

スクリーンショット 2022-12-15 15.34.45.png

決済フォームを表示する

作成したElevatedButtononPressedイベントに、フォームを表示するための処理を追加しましょう。

            ElevatedButton(
              onPressed: () async {
                try {
+                  final response =
+                      await http.get(Uri.http("localhost:3100", "/stripe"));
+                  final jsonResponse = jsonDecode(response.body);
+
+                  await Stripe.instance.initPaymentSheet(
+                    paymentSheetParameters: SetupPaymentSheetParameters(
+                        customerEphemeralKeySecret:
+                            jsonResponse['ephemeralKey'],
+                        customerId: jsonResponse['customerId'],
+                        paymentIntentClientSecret:
+                            jsonResponse['clientSecret']),
+                  );
+                  await Stripe.instance.presentPaymentSheet();
                } catch (e) {
                  developer.log("error", error: e);
                }
              },
              child: const Text("Show card form"),
            )

再読み込みに成功すると、ボタンクリックで決済フォームが表示されます。

スクリーンショット 2022-12-15 15.38.38.png

すでにカード情報が登録されている顧客のIDをサーバー側で指定した場合、登録済みのカードを選ぶこともできます。

スクリーンショット 2022-12-15 15.38.18.png

また、iOSではカードのスキャン機能も利用可能です。

スクリーンショット 2022-12-15 15.38.44.png

Documents

8
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?