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
相关产品推荐
相关产品推荐

