Flutter支付处理插件flutter_nmi的使用

Flutter支付处理插件flutter_nmi的使用

本项目是一个Flutter插件包的起点,该插件包包含用于iOS和/或Android平台的特定实现代码。以下是关于如何使用flutter_nmi插件处理支付的详细示例。

开始使用

首先,确保你已经在项目中添加了flutter_nmi插件。在你的pubspec.yaml文件中添加以下依赖:

dependencies:
  flutter_nmi: ^版本号

然后运行flutter pub get来获取依赖。

示例代码

以下是使用flutter_nmi插件进行支付处理的完整示例代码。

示例代码

import 'dart:async';
import 'dart:convert';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_beep/flutter_beep.dart';
import 'package:flutter_nmi/flutter_nmi.dart';

class NMIDevice {
  static const kGeniusMini = "Genius Mini";
  static const kBBPOS = "BBPOS";
  static const kMiura = "Miura";
  static const kOther = "Other";
}

class Action {
  static const kTransaction = "Transaction";
  static const kTMSUpdate = "TMSUpdate";
  static const kPinPadStatus = "PinPadStatus";
}

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  [@override](/user/override)
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late FlutterNmi nmi;
  String transactionStatus = "点击下方按钮进行支付";
  bool isLoading = false;
  bool isTMSUpdate = false;
  bool isPinPadStatus = false;
  bool mShowWarningDialog = false;
  BuildContext? mBuilderContext;
  Timer? timer;

  TextEditingController amountController = TextEditingController();
  TextEditingController transactionIdController = TextEditingController();

  [@override](/user/override)
  void initState() {
    super.initState();
  }

  initialize() async {
    setState(() {
      isLoading = true;
    });

    var params = {
      "action": Action.kTransaction,
      "api_key": "VZueqyW43Ya8WgMD4Yx4G8qn6mED3yCq",
      "sandbox": "1",
      "signature_required": "1",
      "no_signature_below_amount": "3",
      "amount": "10",
      "surcharge": "0",
      "tip": "2",
      "device_type": NMIDevice.kBBPOS,
      "currency": "USD",
      "transactionId": ""
    };
    //服务费

    nmi = FlutterNmi.instance(
      onPinPadInitializationCompleted: onPinPadInitializationCompleted,
      onPinPadInitializationFailed: onPinPadInitializationFailed,
      onPinPadConnectionStarted: onPinPadConnectionStarted,
      onPinPadConnected: onPinPadConnected,
      onPinPadDisConnected: onPinPadDisConnected,
      onPinPadConnectionFailed: onPinPadConnectionFailed,
      onPinPadConfigurationUpdate: onPinPadConfigurationUpdate,
      onPinPadTMSUpdateCompleted: onPinPadTMSUpdateCompleted,
      onPinPadTMSUpdateFailed: onPinPadTMSUpdateFailed,
      onTransactionStatusUpdate: onTransactionStatusUpdate,
      onTransactionFailed: onTransactionFailed,
      onTransactionCompleted: onTransactionCompleted,
      onPinPadStatusUpdated: onPinPadStatusUpdated,
      onTransactionTerminated: onTransactionTerminated,
    );
    mShowWarningDialog = true;

    nmi.initialize(params);
  }

  requestTMSUpdate() {
    setState(() {
      isLoading = true;
    });

    isTMSUpdate = true;

    var params = {
      "action": Action.kTMSUpdate,
      "api_key": "VZueqyW43Ya8WgMD4Yx4G8qn6mED3yCq",
      "sandbox": "1",
      "device_type": NMIDevice.kBBPOS,
    };

    nmi = FlutterNmi.instance(
      onPinPadInitializationCompleted: onPinPadInitializationCompleted,
      onPinPadInitializationFailed: onPinPadInitializationFailed,
      onPinPadConnectionStarted: onPinPadConnectionStarted,
      onPinPadConnected: onPinPadConnected,
      onPinPadDisConnected: onPinPadDisConnected,
      onPinPadConnectionFailed: onPinPadConnectionFailed,
      onPinPadConfigurationUpdate: onPinPadConfigurationUpdate,
      onPinPadTMSUpdateCompleted: onPinPadTMSUpdateCompleted,
      onPinPadTMSUpdateFailed: onPinPadTMSUpdateFailed,
    );

    nmi.initialize(params);
  }

  selectPinPad() {
    setState(() {
      isLoading = true;
    });

    nmi = FlutterNmi.instance(
      onPinPadInitializationCompleted: onPinPadInitializationCompleted,
      onPinPadInitializationFailed: onPinPadInitializationFailed,
      onPinPadConnectionStarted: onPinPadConnectionStarted,
      onPinPadConnected: onPinPadConnected,
      onPinPadDisConnected: onPinPadDisConnected,
      onPinPadConnectionFailed: onPinPadConnectionFailed,
      onPinPadConfigurationUpdate: onPinPadConfigurationUpdate,
      onPinPadTMSUpdateCompleted: onPinPadTMSUpdateCompleted,
      onPinPadTMSUpdateFailed: onPinPadTMSUpdateFailed,
    );

    nmi.selectPinPad();
  }

  getPinPadStatus() {
    setState(() {
      isLoading = true;
    });

    isPinPadStatus = true;

    var params = {
      "action": Action.kPinPadStatus,
      "api_key": "VZueqyW43Ya8WgMD4Yx4G8qn6mED3yCq",
      "sandbox": "1",
      "device_type": NMIDevice.kBBPOS,
    };

    nmi = FlutterNmi.instance(
      onPinPadInitializationCompleted: onPinPadInitializationCompleted,
      onPinPadInitializationFailed: onPinPadInitializationFailed,
      onPinPadConnectionStarted: onPinPadConnectionStarted,
      onPinPadConnected: onPinPadConnected,
      onPinPadDisConnected: onPinPadDisConnected,
      onPinPadConnectionFailed: onPinPadConnectionFailed,
      onPinPadConfigurationUpdate: onPinPadConfigurationUpdate,
      onPinPadTMSUpdateCompleted: onPinPadTMSUpdateCompleted,
      onPinPadTMSUpdateFailed: onPinPadTMSUpdateFailed,
      onPinPadStatusUpdated: onPinPadStatusUpdated,
    );

    nmi.initialize(params);
  }

  requestRefund() {
    setState(() {
      isLoading = true;
    });

    var params = {
      "api_key": "VZueqyW43Ya8WgMD4Yx4G8qn6mED3yCq",
      "sandbox": "1",
      "device_type": NMIDevice.kBBPOS,
      "currency": "USD",
      "transactionId": transactionIdController.text,
      "amount": amountController.text,
    };

    nmi = FlutterNmi.instance(
      onTransactionStatusUpdate: onTransactionStatusUpdate,
      onTransactionFailed: onTransactionFailed,
      onTransactionCompleted: onTransactionCompleted,
    );
    mShowWarningDialog = false;

    nmi.requestRefund(params);
  }

  cancelTransaction() {
    nmi.cancelTransaction();
  }

  disconnectPinPad() {
    nmi.disconnectPinPad();
  }

  onPinPadInitializationFailed() {
    if (kDebugMode) {
      print("Flutter ==== onPinPad Initialization Failed");
    }

    setState(() {
      isLoading = false;
      transactionStatus = "初始化PIN Pad失败";
    });
  }

  onPinPadInitializationCompleted() {
    if (kDebugMode) {
      print("Flutter ==== onPinPad Initialization Completed");
    }

    setState(() {
      //isLoading = false;
      transactionStatus = "初始化PIN Pad完成";
    });
  }

  onPinPadConnected(value) {
    if (kDebugMode) {
      print("Flutter ==== onPinPad Connection Completed $value");
    }

    setState(() {
      transactionStatus = "连接到PIN Pad";
    });

    /*if (isTMSUpdate) {
      nmi.requestTMSUpdate();
    } else if (isPinPadStatus) {
      nmi.getPinPadStatus();
    }*/
  }

  onPinPadConnectionFailed() {
    if (kDebugMode) {
      print("Flutter ==== onPinPad Connection Failed");
    }

    setState(() {
      isLoading = false;
      transactionStatus = "连接到PIN Pad失败";
    });
  }

  onPinPadDisConnected() {
    if (kDebugMode) {
      print("Flutter ==== onPinPad DisConnected");
    }

    setState(() {
      isLoading = false;
      transactionStatus = "断开连接PIN Pad";
    });
  }

  onPinPadConfigurationUpdate(value) {
    if (kDebugMode) {
      print("Flutter ==== onPinPad Configuration Update");
    }

    setState(() {
      transactionStatus = ((value as String).replaceAll("_", " "));
    });
  }

  onPinPadConnectionStarted() {
    if (kDebugMode) {
      print("Flutter ==== onPinPad Connection Started");
    }

    setState(() {
      transactionStatus = "正在连接到PIN Pad...";
    });
  }

  onTransactionStatusUpdate(value) {
    if (kDebugMode) {
      print("Flutter ==== onPinPad Status Update");
    }

    setState(() {
      transactionStatus = ((value as String).replaceAll("_", " "));
    });
  }

  onPinPadTMSUpdateCompleted() {
    if (kDebugMode) {
      print("Flutter ==== TMS Update Completed");
    }

    setState(() {
      isLoading = false;
      transactionStatus = "TMS更新完成";
    });
  }

  onPinPadTMSUpdateFailed(value) {
    if (kDebugMode) {
      print("Flutter ==== TMS Update Failed $value");
    }

    setState(() {
      isLoading = false;
      transactionStatus = "TMS更新失败。$value";
    });
  }

  onTransactionFailed(value) {
    if (kDebugMode) {
      print("Flutter ==== Transaction Failed $value");
    }

    setState(() {
      isLoading = false;
      transactionStatus = "交易失败\n$value";
    });
  }

  onTransactionCompleted(value) {
    if (kDebugMode) {
      print("Flutter ==== Transaction Completed $value");
    }

    if (mShowWarningDialog) {
      showWarningDialog(mBuilderContext!);
    }

    setState(() {
      isLoading = false;
      transactionStatus = "交易完成";
    });
  }

  onTransactionTerminated() {
    if (kDebugMode) {
      print("Flutter ==== Transaction Terminated");
    }

    setState(() {
      isLoading = false;
      transactionStatus = "交易终止";
    });
  }

  onPinPadStatusUpdated(value) {
    setState(() {
      isLoading = false;
      transactionStatus = "PIN Pad状态更新";
    });

    if (kDebugMode) {
      print("Flutter ==== Transaction Completed $value");
    }
  }

  showWarningDialog(BuildContext context) {
    timer = Timer.periodic(const Duration(seconds: 1), (Timer t) {
      FlutterBeep.beep();
    });
    showDialog(
        context: context,
        builder: (_) {
          Future.delayed(const Duration(seconds: 5), () {
            timer!.cancel();
            Navigator.of(context).pop();
          });
          return Dialog(
            insetPadding: const EdgeInsets.symmetric(horizontal: 16),
            elevation: 0,
            backgroundColor: Colors.white,
            child: StatefulBuilder(
              builder: (BuildContext _, StateSetter _setState) {
                return Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    const SizedBox(
                      height: 30,
                    ),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: const [
                        Icon(
                          Icons.warning,
                          color: Colors.yellow,
                          size: 100,
                        ),
                      ],
                    ),
                    Row(
                      children: [
                        Expanded(
                          child: Container(
                            margin: const EdgeInsets.only(
                                top: 20, left: 15, right: 15),
                            child: const Text(
                              "请不要忘记取出卡片",
                              style: TextStyle(fontSize: 20),
                            ),
                          ),
                        ),
                      ],
                    ),
                    const SizedBox(
                      height: 10,
                    ),
                    GestureDetector(
                      onTap: () {
                        Navigator.pop(context);
                      },
                      child: Container(
                        margin: const EdgeInsets.only(top: 20, bottom: 20),
                        padding: const EdgeInsets.only(
                            top: 5, bottom: 5, right: 20, left: 20),
                        decoration: BoxDecoration(
                          borderRadius: BorderRadius.circular(10),
                          color: Colors.white,
                          border: Border.all(
                            color: Colors.black,
                            width: 1,
                          ),
                          boxShadow: const [
                            BoxShadow(
                              color: Colors.white,
                              spreadRadius: 5,
                              offset: Offset(0, 3),
                            ),
                          ],
                        ),
                        child: const Text("关闭"),
                      ),
                    )
                  ],
                );
              },
            ),
          );
        });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Flutter NMI Demo'),
        ),
        body: Builder(
          builder: (context) {
            mBuilderContext = context;
            return SingleChildScrollView(
              child: Column(
                children: [
                  Visibility(
                    visible: isLoading,
                    child: Container(
                      margin: const EdgeInsets.only(top: 40),
                      child: const CircularProgressIndicator(
                        backgroundColor: Colors.grey,
                        color: Colors.purple,
                        strokeWidth: 5,
                      ),
                    ),
                  ),
                  const SizedBox(
                    height: 20,
                  ),
                  Text(transactionStatus),
                  const SizedBox(
                    height: 20,
                  ),
                  GestureDetector(
                    child: Container(
                      padding: const EdgeInsets.all(20),
                      child: const Text("支付\$10"),
                      color: (isLoading == true) ? Colors.grey : Colors.amber,
                    ),
                    onTap: () {
                      if (isLoading == false) {
                        initialize();
                      }
                    },
                  ),
                  const SizedBox(
                    height: 20,
                  ),
                  GestureDetector(
                    child: Container(
                      padding: const EdgeInsets.all(20),
                      child: const Text("请求TMS更新"),
                      color: (isLoading == true) ? Colors.grey : Colors.amber,
                    ),
                    onTap: () {
                      if (isLoading == false) {
                        requestTMSUpdate();
                      }
                    },
                  ),
                  const SizedBox(
                    height: 20,
                  ),
                  GestureDetector(
                    child: Container(
                      padding: const EdgeInsets.all(20),
                      child: const Text("选择PIN Pad"),
                      color: (isLoading == true) ? Colors.grey : Colors.amber,
                    ),
                    onTap: () {
                      if (isLoading == false) {
                        selectPinPad();
                      }
                    },
                  ),
                  const SizedBox(
                    height: 20,
                  ),
                  GestureDetector(
                    child: Container(
                      padding: const EdgeInsets.all(20),
                      child: const Text("取消交易"),
                      color: Colors.amber,
                    ),
                    onTap: () {
                      cancelTransaction();
                    },
                  ),
                  const SizedBox(
                    height: 40,
                  ),
                  GestureDetector(
                    child: Container(
                      padding: const EdgeInsets.all(20),
                      child: const Text("获取PIN Pad状态"),
                      color: (isLoading == true) ? Colors.grey : Colors.amber,
                    ),
                    onTap: () {
                      if (isLoading == false) {
                        getPinPadStatus();
                      }
                    },
                  ),
                  const SizedBox(
                    height: 40,
                  ),
                  GestureDetector(
                    child: Container(
                      padding: const EdgeInsets.all(20),
                      child: const Text("断开PIN Pad连接"),
                      color: (isLoading == true) ? Colors.grey : Colors.amber,
                    ),
                    onTap: () {
                      if (isLoading == false) {
                        disconnectPinPad();
                      }
                    },
                  ),
                  const SizedBox(
                    height: 40,
                  ),
                  Row(
                    children: [
                      const SizedBox(
                        width: 20,
                      ),
                      Expanded(
                        child: TextField(
                          controller: amountController,
                          keyboardType: TextInputType.number,
                          decoration: const InputDecoration(
                            border: OutlineInputBorder(),
                            hintText: '输入退款金额',
                          ),
                        ),
                      ),
                      const SizedBox(
                        width: 20,
                      ),
                      Expanded(
                        child: TextField(
                          controller: transactionIdController,
                          keyboardType: TextInputType.number,
                          decoration: const InputDecoration(
                            border: OutlineInputBorder(),
                            hintText: '输入交易ID',
                          ),
                        ),
                      ),
                      const SizedBox(
                        width: 20,
                      ),
                    ],
                  ),
                  const SizedBox(
                    height: 20,
                  ),
                  GestureDetector(
                    child: Container(
                      padding: const EdgeInsets.all(20),
                      child: const Text("请求退款"),
                      color: (isLoading == true) ? Colors.grey : Colors.amber,
                    ),
                    onTap: () {
                      if (isLoading == false) {
                        if (amountController.text != "" && transactionIdController.text != "") {
                          requestRefund();
                        }
                      }
                    },
                  ),
                  const SizedBox(
                    height: 20,
                  ),
                  GestureDetector(
                    child: const Text("打开对话框"),
                    onTap: () {
                      showWarningDialog(context);
                    },
                  )
                  /*const SizedBox(
              height: 40,
            ),
            GestureDetector(
              child: Container(
                padding: const EdgeInsets.all(20),
                child: const Text("打开签名页面"),
                color: (isLoading == true) ? Colors.grey : Colors.amber,
              ),
              onTap: () {
                goToSignaturePad();
              },
            ),*/
                ],
              ),
            );
          },
        ),
      ),
    );
  }
}

更多关于Flutter支付处理插件flutter_nmi的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter支付处理插件flutter_nmi的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


flutter_nmi 是一个用于处理支付的 Flutter 插件,它集成了 NMI (Network Merchants, Inc.) 支付网关。使用这个插件,你可以在 Flutter 应用中处理信用卡支付等操作。以下是如何使用 flutter_nmi 插件的基本步骤:

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 flutter_nmi 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_nmi: ^1.0.0  # 请使用最新版本

然后运行 flutter pub get 来获取依赖。

2. 配置插件

flutter_nmi 插件中,你需要配置 NMI 的 API 密钥和其他必要的参数。通常,这些配置可以在应用的初始化阶段完成。

import 'package:flutter_nmi/flutter_nmi.dart';

void configureNMI() {
  FlutterNmi.configure(
    apiKey: 'your_nmi_api_key',
    // 其他配置参数
  );
}

3. 处理支付

使用 flutter_nmi 插件处理支付通常涉及以下几个步骤:

  1. 创建支付请求:你需要创建一个支付请求对象,包含支付金额、信用卡信息等。

  2. 发起支付请求:使用 FlutterNmi 提供的方法发起支付请求。

  3. 处理支付结果:根据支付结果更新 UI 或执行其他操作。

以下是一个简单的支付处理示例:

import 'package:flutter/material.dart';
import 'package:flutter_nmi/flutter_nmi.dart';

class PaymentScreen extends StatefulWidget {
  [@override](/user/override)
  _PaymentScreenState createState() => _PaymentScreenState();
}

class _PaymentScreenState extends State<PaymentScreen> {
  final _formKey = GlobalKey<FormState>();
  final _cardNumberController = TextEditingController();
  final _expiryDateController = TextEditingController();
  final _cvvController = TextEditingController();

  Future<void> _processPayment() async {
    if (_formKey.currentState.validate()) {
      final paymentRequest = PaymentRequest(
        amount: 100.0, // 支付金额
        cardNumber: _cardNumberController.text,
        expiryDate: _expiryDateController.text,
        cvv: _cvvController.text,
        // 其他支付信息
      );

      try {
        final paymentResponse = await FlutterNmi.processPayment(paymentRequest);
        if (paymentResponse.success) {
          // 支付成功
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(content: Text('Payment successful!')),
          );
        } else {
          // 支付失败
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(content: Text('Payment failed: ${paymentResponse.message}')),
          );
        }
      } catch (e) {
        // 处理异常
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('An error occurred: $e')),
        );
      }
    }
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Payment')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Form(
          key: _formKey,
          child: Column(
            children: [
              TextFormField(
                controller: _cardNumberController,
                decoration: InputDecoration(labelText: 'Card Number'),
                validator: (value) {
                  if (value.isEmpty) {
                    return 'Please enter card number';
                  }
                  return null;
                },
              ),
              TextFormField(
                controller: _expiryDateController,
                decoration: InputDecoration(labelText: 'Expiry Date'),
                validator: (value) {
                  if (value.isEmpty) {
                    return 'Please enter expiry date';
                  }
                  return null;
                },
              ),
              TextFormField(
                controller: _cvvController,
                decoration: InputDecoration(labelText: 'CVV'),
                validator: (value) {
                  if (value.isEmpty) {
                    return 'Please enter CVV';
                  }
                  return null;
                },
              ),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: _processPayment,
                child: Text('Pay Now'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
回到顶部