Flutter ns_upi 是一个Flutter插件,用于查找手机上已安装的统一支付接口(UPI)应用程

发布于 1周前 作者 yibo5220 最后一次编辑是 5天前 来自 Flutter

Flutter ns_upi 是一个Flutter插件,用于查找手机上已安装的统一支付接口(UPI)应用程

描述

ns_upi 是一个Flutter插件,用于查找手机上已安装的统一支付接口(UPI)应用程序,并通过这些应用程序进行支付。该插件可以帮助开发者轻松集成UPI支付功能到他们的Flutter应用中。

快速开始

1. 添加依赖

pubspec.yaml 文件中添加 ns_upi 作为依赖项:

dependencies:
  ...
  ns_upi: ^1.0.2
2. 导入包

在 Dart 文件中导入 ns_upi 包:

import 'package:ns_upi/ns_upi.dart';
3. iOS配置

Runner/Info.plist 文件中添加或修改 LSApplicationQueriesSchemes 键,以包含自定义查询方案。以下是一些常见的UPI应用程序的scheme列表:

<key>LSApplicationQueriesSchemes</key>
<array>
    <string>Bandhan</string>
    <string>BHIM</string>
    <string>CanaraMobility</string>
    <string>CentUPI</string>
    <string>com.amazon.mobile.shopping</string>
    <string>com.ausmallfinancebank.aupay.bhimupi</string>
    <string>com.jkbank.bhimjkbankupi</string>
    <string>com.rbl.rblimplicitjourney</string>
    <string>com.syndicate.syndupi</string>
    <string>com.vijayabank.UPI</string>
    <string>cred</string>
    <string>dbin</string>
    <string>freecharge</string>
    <string>gpay</string>
    <string>hdfcnewbb</string>
    <string>imobileapp</string>
    <string>in.cointab.app</string>
    <string>in.fampay.app</string>
    <string>kvb.app.upiapp</string>
    <string>lotza</string>
    <string>mobikwik</string>
    <string>money.bullet</string>
    <string>myairtel</string>
    <string>myJio</string>
    <string>paytm</string>
    <string>payzapp</string>
    <string>phonepe</string>
    <string>truecaller</string>
    <string>ucoupi</string>
    <string>upi</string>
    <string>upibillpay</string>
    <string>whatsapp</string>
    <string>www.citruspay.com</string>
</array>

使用方法

1. 获取已安装的应用程序列表

可以通过调用 NsUpi.getInstalledUpiApps() 方法来获取手机上已安装的UPI应用程序列表。返回的是一个 List<ApplicationMeta> 类型的列表,其中每个 ApplicationMeta 对象包含应用程序的元数据。

final List<ApplicationMeta> appMetaList = await NsUpi.getInstalledUpiApps();
2. 发起UPI交易

可以通过调用 NsUpi.initiateTransaction() 方法来发起一笔UPI交易。该方法需要提供金额、接收方名称、接收方UPI地址、交易参考号和交易备注等参数。发起交易后,用户可以选择一个已安装的UPI应用程序来完成支付。

Future<void> upiTransaction(ApplicationMeta appMeta) async {
  final UpiTransactionResponse response = await NsUpi.initiateTransaction(
    amount: '1.00', // 金额
    app: appMeta.application, // 选择的应用程序
    receiverName: 'Ajay Kumar', // 接收方名称
    receiverUpiAddress: '7875056731[@paytm](/user/paytm)', // 接收方UPI地址
    transactionRef: 'NONSTOPIO000001', // 交易参考号
    transactionNote: 'A TEST UPI Transaction', // 交易备注
  );
  debugPrint(response.status); // 打印交易状态
}

完整示例Demo

以下是一个完整的Flutter应用程序示例,展示了如何使用 ns_upi 插件来发起UPI交易。

import 'dart:io';
import 'dart:math';

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

void main() => runApp(const App());

class App extends StatelessWidget {
  const App({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('UPI Pay'),
        ),
        body: const Screen(),
      ),
    );
  }
}

class Screen extends StatefulWidget {
  const Screen({super.key});

  [@override](/user/override)
  State<Screen> createState() => _ScreenState();
}

class _ScreenState extends State<Screen> {
  String? _upiAddrError;

  final _upiAddressController = TextEditingController(text: '7875056731[@paytm](/user/paytm)');
  final _amountController = TextEditingController();

  bool _isUpiEditable = false;
  List<ApplicationMeta>? _apps;

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

    // 随机生成金额
    _amountController.text =
        (Random.secure().nextDouble() * 10).toStringAsFixed(2);

    // 获取已安装的UPI应用程序列表
    Future.delayed(const Duration(milliseconds: 0), () async {
      try {
        _apps = await NsUpi.getInstalledUpiApps(
            statusType: UpiApplicationDiscoveryAppStatusType.all);
        setState(() {});
      } catch (e, s) {
        debugPrint('getInstalledUpiApps error: $e, stack: $s');
      }
    });
  }

  [@override](/user/override)
  void dispose() {
    _amountController.dispose();
    _upiAddressController.dispose();
    super.dispose();
  }

  void _generateAmount() {
    setState(() {
      _amountController.text =
          (Random.secure().nextDouble() * 10).toStringAsFixed(2);
    });
  }

  Future<void> _onTap(ApplicationMeta app) async {
    // 验证UPI地址
    final err = _validateUpiAddress(_upiAddressController.text);
    if (err != null) {
      setState(() {
        _upiAddrError = err;
      });
      return;
    }
    setState(() {
      _upiAddrError = null;
    });

    // 生成交易参考号
    final transactionRef = Random.secure().nextInt(1 << 32).toString();
    debugPrint("Starting transaction with id $transactionRef");
    debugPrint("Using app ${app.upiApplication.getAppName()}");

    // 发起交易
    final response = await NsUpi.initiateTransaction(
      amount: _amountController.text,
      app: app.upiApplication,
      receiverName: 'Sharad',
      receiverUpiAddress: _upiAddressController.text,
      transactionRef: transactionRef,
      transactionNote: 'UPI Payment',
    );

    debugPrint(response.toString());
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 16),
      child: ListView(
        children: [
          _vpa(),
          if (_upiAddrError != null) _vpaError(),
          _amount(),
          if (Platform.isIOS) _submitButton(),
          Platform.isAndroid ? _androidApps() : _iosApps(),
        ],
      ),
    );
  }

  Widget _vpa() {
    return Container(
      margin: const EdgeInsets.only(top: 32),
      child: Row(
        children: [
          Expanded(
            child: TextFormField(
              controller: _upiAddressController,
              enabled: _isUpiEditable,
              decoration: const InputDecoration(
                border: OutlineInputBorder(),
                hintText: 'address@upi',
                labelText: 'Receiving UPI Address',
              ),
            ),
          ),
          Container(
            margin: const EdgeInsets.only(left: 8),
            child: IconButton(
              icon: Icon(
                _isUpiEditable ? Icons.check : Icons.edit,
              ),
              onPressed: () {
                setState(() {
                  _isUpiEditable = !_isUpiEditable;
                });
              },
            ),
          ),
        ],
      ),
    );
  }

  Widget _vpaError() {
    return Container(
      margin: const EdgeInsets.only(top: 4, left: 12),
      child: Text(
        _upiAddrError!,
        style: const TextStyle(color: Colors.red),
      ),
    );
  }

  Widget _amount() {
    return Container(
      margin: const EdgeInsets.only(top: 32),
      child: Row(
        children: [
          Expanded(
            child: TextField(
              controller: _amountController,
              readOnly: true,
              enabled: false,
              decoration: const InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Amount',
              ),
            ),
          ),
          Container(
            margin: const EdgeInsets.only(left: 8),
            child: IconButton(
              icon: const Icon(Icons.loop),
              onPressed: _generateAmount,
            ),
          ),
        ],
      ),
    );
  }

  Widget _submitButton() {
    return Container(
      margin: const EdgeInsets.only(top: 32),
      child: Row(
        children: [
          Expanded(
            child: MaterialButton(
              onPressed: () async => await _onTap(_apps!.last),
              color: Theme.of(context).colorScheme.secondary,
              height: 48,
              shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(6)),
              child: Text('Initiate Transaction',
                  style: Theme.of(context)
                      .textTheme
                      .labelLarge!
                      .copyWith(color: Colors.white)),
            ),
          ),
        ],
      ),
    );
  }

  Widget _androidApps() {
    return Container(
      margin: const EdgeInsets.only(top: 32, bottom: 32),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Container(
            margin: const EdgeInsets.only(bottom: 12),
            child: Text(
              'Pay Using',
              style: Theme.of(context).textTheme.bodyLarge,
            ),
          ),
          if (_apps != null) _appsGrid(_apps!.map((e) => e).toList()),
        ],
      ),
    );
  }

  Widget _iosApps() {
    return Container(
      margin: const EdgeInsets.only(top: 32, bottom: 32),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Container(
            margin: const EdgeInsets.only(bottom: 24),
            child: Text(
              'One of these will be invoked automatically by your phone to make a payment',
              style: Theme.of(context).textTheme.bodyMedium,
            ),
          ),
          Container(
            margin: const EdgeInsets.only(bottom: 12),
            child: Text(
              'Detected Installed Apps',
              style: Theme.of(context).textTheme.bodyLarge,
            ),
          ),
          if (_apps != null) _discoverableAppsGrid(),
          Container(
            margin: const EdgeInsets.only(top: 12, bottom: 12),
            child: Text(
              'Other Supported Apps (Cannot detect)',
              style: Theme.of(context).textTheme.bodyLarge,
            ),
          ),
          if (_apps != null) _nonDiscoverableAppsGrid(),
        ],
      ),
    );
  }

  GridView _discoverableAppsGrid() {
    List<ApplicationMeta> metaList = [];
    for (var e in _apps!) {
      if (e.upiApplication.discoveryCustomScheme != null) {
        metaList.add(e);
      }
    }
    return _appsGrid(metaList);
  }

  GridView _nonDiscoverableAppsGrid() {
    List<ApplicationMeta> metaList = [];
    for (var e in _apps!) {
      if (e.upiApplication.discoveryCustomScheme == null) {
        metaList.add(e);
      }
    }
    return _appsGrid(metaList, disableOnTap: true);
  }

  GridView _appsGrid(List<ApplicationMeta> apps, {bool disableOnTap = false}) {
    return GridView.count(
      crossAxisCount: 4,
      shrinkWrap: true,
      mainAxisSpacing: 4,
      crossAxisSpacing: 4,
      physics: const NeverScrollableScrollPhysics(),
      children: apps
          .map(
            (it) => Material(
              key: ObjectKey(it.upiApplication),
              child: InkWell(
                onTap: disableOnTap ? null : () => _onTap(it),
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    it.iconImage(48),
                    Container(
                      margin: const EdgeInsets.only(top: 4),
                      alignment: Alignment.center,
                      child: Text(
                        it.upiApplication.getAppName(),
                        textAlign: TextAlign.center,
                      ),
                    ),
                  ],
                ),
              ),
            ),
          )
          .toList(),
    );
  }
}

String? _validateUpiAddress(String value) {
  if (value.isEmpty) {
    return 'UPI VPA is required.';
  }
  if (value.split('@').length != 2) {
    return 'Invalid UPI VPA';
  }
  return null;
}

更多关于Flutter ns_upi 是一个Flutter插件,用于查找手机上已安装的统一支付接口(UPI)应用程的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter ns_upi 是一个Flutter插件,用于查找手机上已安装的统一支付接口(UPI)应用程的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


针对帖子中提到的Flutter未知功能插件ns_upi,虽然具体细节和API可能不为人知(因为这是一个假设性的或未知的插件),但我可以提供一个基于Flutter插件开发的一般性示例代码,展示如何集成和使用一个假设的UPI(Unified Payments Interface,统一支付接口)插件。请注意,以下代码是概念性的,并非针对具体的ns_upi插件,因为该插件的具体实现细节未知。

假设的UPI插件集成示例

1. 添加依赖项

首先,假设ns_upi插件已经在pub.dev上发布,你可以在pubspec.yaml文件中添加依赖项:

dependencies:
  flutter:
    sdk: flutter
  ns_upi: ^x.y.z  # 假设的版本号

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

2. 初始化插件

在你的Flutter应用中,你需要初始化这个插件。假设插件提供了一个UpiPlugin类:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter UPI Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late UpiPlugin _upiPlugin;

  @override
  void initState() {
    super.initState();
    _upiPlugin = UpiPlugin();
    // 初始化插件,可能需要一些配置
    // _upiPlugin.initialize(...);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter UPI Demo'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: _initiateUpiPayment,
          child: Text('Initiate UPI Payment'),
        ),
      ),
    );
  }

  Future<void> _initiateUpiPayment() async {
    try {
      // 假设的UPI支付发起方法
      String? result = await _upiPlugin.initiatePayment(
        receiverVpa: 'receiver@bank', // 收款人的VPA
        amount: '100.00', // 支付金额
        notes: 'Payment for goods', // 备注信息
      );
      // 处理支付结果
      if (result != null) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Payment Result: $result')),
        );
      }
    } catch (e) {
      // 处理异常
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Error: ${e.message}')),
      );
    }
  }
}

3. 插件方法假设

上述代码中,我们假设ns_upi插件有一个UpiPlugin类,并且该类有一个initiatePayment方法,该方法接受收款人的VPA、支付金额和备注信息作为参数,并返回一个Future,该Future在支付完成后解析为支付结果。

注意事项

  • 实际插件可能不同:上述代码仅作为概念性示例,实际ns_upi插件的API可能完全不同。你需要查阅该插件的官方文档或源代码来了解其实际API。
  • 权限和配置:UPI支付通常涉及敏感信息,因此在实际应用中,你可能需要配置必要的权限(如INTERNET、ACCESS_NETWORK_STATE等),并处理用户授权和安全性问题。
  • 错误处理:在实际应用中,你需要更细致地处理各种可能的错误情况,如网络错误、用户取消支付等。

由于ns_upi是一个假设性的插件,上述代码不能直接运行。如果你有一个具体的ns_upi插件或类似的UPI支付插件,请查阅其官方文档以获取正确的集成和使用指南。

回到顶部