Flutter多功能插件flutterduplo的使用

Flutter多功能插件flutterduplo的使用

Flutter插件用于通过Duplo支付系统进行付款。完全支持所有平台。

功能特性

当前功能包括:

  • 卡支付
  • 银行支付

安装

要使用此插件,在pubspec.yaml文件中添加flutterduplo依赖项。

然后在您的widget的initState方法中初始化插件。

import 'package:flutterduplo/flutterduplo.dart';

class _ExamplePayementPageState extends State<ExamplePayementPage> {
  var publicKey = '添加你的Duplo公共密钥';
  var secretKey = '添加你的Duplo私有密钥';
  final plugin = Duplo();

  [@override](/user/override)
  void initState() {
    plugin.initialize(publicKey: publicKey, secretKey: secretKey);
  }
}

进行支付

您可以选择两种方式进行支付:

1. 结账(推荐)

这是一种简单的方法;插件处理所有涉及的付款过程(除了交易初始化和验证,这些应从您的后端完成)。

Charge charge = Charge()
      ..amount = 10000
      ..reference = _getReference()
      ..email = 'customer@email.com';
CheckoutResponse response = await plugin.checkout(
  context,
  method: CheckoutMethod.card, // 默认为CheckoutMethod.selectable
  charge: charge,
);

plugin.checkout()返回一个包含支付状态和详细信息的CheckoutResponse实例。

2. 刷卡

这是一种更复杂的方法;您需要处理所有回调和UI状态。

Charge charge = Charge();
charge.card = _getCardFromUI();
charge
  ..amount = 2000
  ..email = 'user@email.com'
  ..reference = _getReference()
  ..putCustomField('Charged From', 'Flutter PLUGIN');
_chargeCard();

验证卡详情

您需要但不强制要求构建用户输入其付款详情的UI。为了更简单的验证,将TextFormField包裹在一个Form小部件内。如果您对此不熟悉,请参阅这篇文章:如何使用Flutter轻松验证表单和用户输入

注意:您不必向Charge传递卡对象。插件会调用一个UI供用户输入他们的卡信息。

您可以使用以下方法验证字段:

card.validNumber

此方法帮助检查卡号是否有效。

card.validCVC

此方法检查卡安全码是否有效。

card.validExpiryDate

此方法检查过期日期(年月组合)是否有效。

card.isValid

此方法检查卡是否有效。在刷卡之前始终进行此检查。

card.getType

此方法返回卡类型(发行者)的字符串表示估计值。

运行示例项目

对于如何开始使用Flutter,请参阅在线文档:Flutter文档

在这个插件中提供了一个示例项目。克隆此仓库并导航到example文件夹。使用支持的IDE打开它,或者从该文件夹在终端执行flutter run

贡献、问题和错误报告

该项目对公众开放贡献。请自由贡献。 遇到问题或想报告错误?请在此处报告:报告问题。记得尽可能详细描述。


示例代码

import 'dart:developer';
import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'dart:async';

import 'package:flutter/services.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:flutterduplo/flutterduplo.dart';

import 'themeclass.dart';

// 定义您的后端URL和Duplo公共密钥。
String backendUrl = '{YOUR_BACKEND_URL}';
String DuploPublicKey = '{YOUR_duplo_PUBLIC_KEY}';
const String appName = 'Buplo Example';

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

// MyApp是主要的应用程序小部件。
class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);
  [@override](/user/override)
  State<MyApp> createState() => _MyAppState();

  // 从任何上下文中获取MyApp小部件的状态。
  static _MyAppState of(BuildContext context) =>
      context.findAncestorStateOfType<_MyAppState>()!;
}

class _MyAppState extends State<MyApp> {
  // 默认主题模式为系统。
  ThemeMode _themeMode = ThemeMode.system;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: appName,
      debugShowCheckedModeBanner: false,
      themeMode: _themeMode,
      theme: ThemeClass.lightTheme,
      darkTheme: ThemeClass.darkTheme,
      home: const Newpage(),
    );
  }

  // 更改主题模式的函数。
  void changeTheme(ThemeMode themeMode) {
    setState(() {
      _themeMode = themeMode;
    });
  }
}

// 检查应用是否运行在暗模式下。
bool get isDarkMode {
  var brightness = SchedulerBinding.instance.window.platformBrightness;
  return brightness == Brightness.dark;
}

// Newpage是应用程序的主要界面。
class Newpage extends StatefulWidget {
  const Newpage({Key? key}) : super(key: key);
  [@override](/user/override)
  _NewpageState createState() => _NewpageState();
}

class _NewpageState extends State<Newpage> {
  var currency = ["USD", "NGN"]; // 支持的货币。
  String dropdownvalue = 'NGN'; // 默认货币。
  TextEditingController phoneController = TextEditingController(); // 金额文本框控制器。
  bool isloading = false; // 结账按钮加载状态。
  final plugin = Duplo(); // Duplo插件实例。
  final _formKey = GlobalKey<FormState>(); // 表单键以验证表单。
  bool check = false; // 暗模式复选框状态。

  [@override](/user/override)
  void initState() {
    check = isDarkMode;
    plugin.initialize(
      secretKey: 'sk_test_qez90izgknchzxjejas1nw8pdnhrli7khdr6hq9',
      publicKey: 'pk_live_cllwoquh6duwcojl6ils7mhoieene068gc3dgv',
    ); // 替换为您的密钥
    super.initState();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.black,
        title: const Text("DUPLO SDK SAMPLE"),
      ),
      body: Center(
        child: Form(
          key: _formKey,
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              Checkbox(
                  value: check,
                  onChanged: (bool? value) {
                    setState(() {
                      check = !check;
                    });
                    if (!check) {
                      MyApp.of(context).changeTheme(ThemeMode.light);
                    } else {
                      MyApp.of(context).changeTheme(ThemeMode.dark);
                    }
                  }),
              const SizedBox(
                height: 20,
              ),
              DropdownButton(
                // 初始值
                value: dropdownvalue,

                // 下箭头图标
                icon: const Icon(Icons.keyboard_arrow_down),

                // 选项列表
                items: currency.map((String items) {
                  return DropdownMenuItem(
                    value: items,
                    child: Text(items),
                  );
                }).toList(),
                // 选择新选项时,更改按钮值
                onChanged: (String? newValue) {
                  setState(() {
                    dropdownvalue = newValue!;
                  });
                },
              ),
              const SizedBox(
                height: 30,
              ),
              Container(
                decoration: const BoxDecoration(
                    color: Color(0xffF4F4F6),
                    borderRadius: BorderRadius.all(Radius.circular(15.0))),
                padding: const EdgeInsets.symmetric(horizontal: 15),
                child: TextFormField(
                  decoration: InputDecoration(
                    fillColor: const Color(0xffF4F4F6),
                    hintText: "1000",
                    hintStyle: TextStyle(
                        fontSize: 16.56,
                        fontWeight: FontWeight.w500,
                        color: isDarkMode ? null : Colors.black),
                    enabledBorder: const OutlineInputBorder(
                      borderRadius: BorderRadius.all(Radius.circular(15.0)),
                      borderSide: BorderSide(color: Color(0xffF4F4F6)),
                    ),
                    focusedBorder: const OutlineInputBorder(
                      borderRadius: BorderRadius.all(Radius.circular(15.0)),
                      borderSide: BorderSide(color: Color(0xffF4F4F6)),
                    ),
                    disabledBorder: const OutlineInputBorder(
                      borderRadius: BorderRadius.all(Radius.circular(15.0)),
                      borderSide: BorderSide(color: Color(0xffF4F4F6)),
                    ),
                  ),
                  style: TextStyle(
                      fontSize: 16.56,
                      fontWeight: FontWeight.w500,
                      color: isDarkMode ? null : Colors.black),
                  controller: phoneController,
                  keyboardType: TextInputType.phone,
                  onChanged: (value) {
                    if (value.isEmpty) {
                      setState(() {
                        // widget.emailfield(true);
                      });
                    } else {
                      setState(() {});
                    }
                  },
                  validator: (value) {
                    if (value!.isEmpty) {
                      return "This field can't be empty";
                    }

                    return null;
                  },
                ),
              ),
              const SizedBox(
                height: 50,
              ),
              GestureDetector(
                child: Container(
                  decoration: const BoxDecoration(
                      borderRadius: BorderRadius.all(Radius.circular(15)),
                      color: Colors.black),
                  height: 65,
                  padding: const EdgeInsets.symmetric(vertical: 15),
                  margin: const EdgeInsets.symmetric(
                      horizontal: 50, vertical: 10),
                  alignment: Alignment.center,
                  child: isloading
                      ? loadingWidget
                      : const Text(
                    "Checkout",
                    style: TextStyle(color: Colors.white, fontSize: 20),
                  ),
                ),
                onTap: () {
                  if (_formKey.currentState!.validate()) {
                    _handleCheckout(context);
                  }
                },
              )
            ],
          ),
        ),
      ),
    );
  }

  _handleCheckout(BuildContext context) async {
    setState(() => isloading = true);
    _formKey.currentState?.save();
    Charge charge = Charge()
      ..amount = int.parse(phoneController.text) // 基础货币单位
      ..email = 'sdkapp1@email.com'
      ..currency = dropdownvalue;

    charge.reference = _getReference();

    try {
      var response = await plugin.checkout(
        context,
        charge: charge,
      );
      log('Response = $response');
      setState(() => isloading = false);
      _updateStatus(response.reference, '$response');
    } catch (e) {
      setState(() => isloading = false);
      _showMessage("Check console for error");
      rethrow;
    }
  }

  String _getReference() {
    String platform;
    if (!kIsWeb) {
      if (Platform.isIOS) {
        platform = 'iOS';
      } else {
        platform = 'Android';
      }
    } else {
      platform = "WEB";
    }
    return 'ChargedFrom${platform}_${DateTime.now().millisecondsSinceEpoch}';
  }

  _updateStatus(String? reference, String message) {
    _showMessage('Reference: $reference \n Response: $message',
        const Duration(seconds: 7));
  }

  _showMessage(String message,
      [Duration duration = const Duration(seconds: 4)]) {
    ScaffoldMessenger.of(context).showSnackBar(SnackBar(
      content: Text(message),
      duration: duration,
      action: SnackBarAction(
          label: 'CLOSE',
          onPressed: () =>
              ScaffoldMessenger.of(context).removeCurrentSnackBar()),
    ));
  }
}

const loadingWidget = SpinKitThreeBounce(
  color: Colors.white,
  size: 30.0,
);

更多关于Flutter多功能插件flutterduplo的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

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


当然,flutterduplo 是一个假想的 Flutter 插件名称,因为实际上并没有一个广泛认可的名为 flutterduplo 的插件。不过,我可以基于 Flutter 插件开发的通用模式,给出一个多功能插件使用的示例代码框架,来帮助你理解如何在 Flutter 应用中使用多功能插件。

假设我们有一个名为 multifunctional_plugin 的多功能插件,它提供了文件操作、网络请求和设备信息获取等功能。以下是如何在 Flutter 应用中使用这个插件的示例代码:

1. 添加插件依赖

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

dependencies:
  flutter:
    sdk: flutter
  multifunctional_plugin: ^x.y.z  # 假设这是插件的版本号

然后运行 flutter pub get 来获取插件。

2. 导入插件并使用其功能

在你的 Dart 文件中导入插件,并使用其提供的功能。以下是一个示例,展示了如何使用文件操作、网络请求和设备信息获取功能:

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

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String _deviceInfo = '';
  String _fileContent = '';
  String _networkResponse = '';

  @override
  void initState() {
    super.initState();
    _getDeviceInfo();
    _readFile();
    _makeNetworkRequest();
  }

  Future<void> _getDeviceInfo() async {
    String deviceInfo = await MultifunctionalPlugin.deviceInfo();
    setState(() {
      _deviceInfo = deviceInfo;
    });
  }

  Future<void> _readFile() async {
    String filePath = 'path/to/your/file.txt'; // 替换为你的文件路径
    String fileContent = await MultifunctionalPlugin.readFile(filePath);
    setState(() {
      _fileContent = fileContent;
    });
  }

  Future<void> _makeNetworkRequest() async {
    String url = 'https://api.example.com/data'; // 替换为你的API URL
    Map<String, String> headers = {'Content-Type': 'application/json'};
    String networkResponse = await MultifunctionalPlugin.networkRequest(
      url: url,
      method: 'GET',
      headers: headers,
    );
    setState(() {
      _networkResponse = networkResponse;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Multifunctional Plugin Demo'),
        ),
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Text('Device Info:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
              Text(_deviceInfo, style: TextStyle(fontSize: 16)),
              SizedBox(height: 20),
              Text('File Content:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
              Text(_fileContent, style: TextStyle(fontSize: 16)),
              SizedBox(height: 20),
              Text('Network Response:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
              Text(_networkResponse, style: TextStyle(fontSize: 16)),
            ],
          ),
        ),
      ),
    );
  }
}

3. 插件功能实现(假设)

虽然这不是你要求的,但为了完整性,这里简要说明一下插件可能如何实现这些功能。在插件的 Dart 代码中,你会定义这些功能的接口,并在原生代码(iOS 的 Swift/Objective-C 和 Android 的 Kotlin/Java)中实现它们。

Dart 接口

class MultifunctionalPlugin {
  static const MethodChannel _channel = MethodChannel('com.example.multifunctional_plugin');

  static Future<String> deviceInfo() async {
    final String deviceInfo = await _channel.invokeMethod('getDeviceInfo');
    return deviceInfo;
  }

  static Future<String> readFile(String filePath) async {
    final String fileContent = await _channel.invokeMethod('readFile', {'filePath': filePath});
    return fileContent;
  }

  static Future<String> networkRequest({required String url, required String method, Map<String, String>? headers}) async {
    final Map<String, dynamic> arguments = <String, dynamic>{
      'url': url,
      'method': method,
      'headers': headers,
    };
    final String response = await _channel.invokeMethod('networkRequest', arguments);
    return response;
  }
}

原生代码实现

在原生代码中,你需要监听这些方法的调用,并实现相应的逻辑。由于篇幅限制,这里不展示具体的原生代码实现,但你可以参考 Flutter 官方文档了解如何在原生代码中实现插件功能。

这个示例框架展示了如何在 Flutter 应用中使用一个假设的多功能插件。实际使用时,你需要根据插件的具体文档和 API 来调整代码。

回到顶部