You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter开发:如何实现可自动提取UPI ID的二维码扫描器

Flutter 扫描UPI二维码提取UPI ID实现方案

UPI支付二维码遵循EMVco通用支付二维码规范,字符串结构有固定规则,按规则解析的准确率远高于直接写正则硬匹配,实现效果和Paytm、WhatsApp等主流应用完全一致。

核心规则

你扫描得到的长串采用2位标签 + 2位长度值 + 定长内容的TLV结构,其中:

  • 印度国家支付公司NPCI的全局唯一应用标识为A000000524,所有合规UPI二维码都包含该字段
  • UPI ID存储在标签号26~51区间、内容以A000000524开头的商户信息段内,对应段内子标签01的内容值

实现逻辑

  • 校验合法性:判断扫描到的原始字符串是否包含A000000524标识,不包含则直接判定为非UPI二维码,终止解析
  • 定位目标段:按TLV结构逐段遍历顶层标签,找到标签号在26~51区间、内容以A000000524开头的段
  • 提取UPI ID:在目标段内跳过开头的应用标识,继续按TLV结构遍历子标签,找到子标签01对应的内容,即为UPI ID
  • 兜底兼容:针对少数不按标准生成的UPI二维码,增加正则匹配逻辑作为 fallback,避免解析失败

开箱即用的Dart代码

直接在mobile_scanner的扫码回调中,把拿到的原始二维码字符串传入下方函数即可,解析成功返回UPI ID,失败返回null:

String? extractUpiId(String rawQrContent) {
  // 基础校验:非UPI码直接返回
  if (!rawQrContent.contains('A000000524')) {
    return null;
  }

  int cursor = 0;
  const npciAppId = 'A000000524';
  // 遍历顶层TLV块
  while (cursor < rawQrContent.length - 4) {
    final tag = rawQrContent.substring(cursor, cursor + 2);
    cursor += 2;
    final contentLen = int.tryParse(rawQrContent.substring(cursor, cursor + 2));
    cursor += 2;
    if (contentLen == null || cursor + contentLen > rawQrContent.length) break;
    final blockContent = rawQrContent.substring(cursor, cursor + contentLen);
    cursor += contentLen;

    final tagNum = int.tryParse(tag);
    // 命中NPCI对应的支付信息块
    if (tagNum != null && tagNum >= 26 && tagNum <= 51 && blockContent.startsWith(npciAppId)) {
      int subCursor = npciAppId.length;
      // 遍历块内子TLV标签
      while (subCursor < blockContent.length - 4) {
        final subTag = blockContent.substring(subCursor, subCursor + 2);
        subCursor += 2;
        final subLen = int.tryParse(blockContent.substring(subCursor, subCursor + 2));
        subCursor += 2;
        if (subLen == null || subCursor + subLen > blockContent.length) break;
        final subContent = blockContent.substring(subCursor, subCursor + subLen);
        subCursor += subLen;
        // 子标签01对应UPI ID,校验@格式避免误取
        if (subTag == '01' && subContent.contains('@')) {
          return subContent;
        }
      }
    }
  }

  // 兜底正则:适配非标准生成的UPI码
  final upiMatch = RegExp(r'[a-zA-Z0-9.\-_]{2,}@[a-zA-Z]{2,}').firstMatch(rawQrContent);
  return upiMatch?.group(0);
}

效果验证

传入你提供的示例二维码串:

000201010211021644038462029515060415522024062029515061661000306202951570825HDFC00000015020000391584826490010A0000005240131shradhatravel.62029515@hdfcbank27420010A0000005240124STQD571562516354474448275204599953033565802IN5914SHRADHA TRAVEL6008VARANASI610622100262400524STQD571562516354474448270708620295156304f4ea

函数返回值为shradhatravel.62029515@hdfcbank,和预期结果完全一致。

使用提示

  • 不要直接只用正则匹配提取,容易把二维码串内其他格式相似的字符串误判为UPI ID
  • 规范解析逻辑覆盖所有官方标准UPI二维码,兜底正则仅作异常场景兼容
  • mobile_scanner 3.x及以上版本可直接通过Barcode.rawValue获取原始字符串传入函数,无需额外引入其他依赖包

内容的提问来源于stack exchange,提问作者Divyam Makar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 04:45:48