fix(mining-app): QR码解析加固 + debugPrint排查
- 清除不可见字符(BOM/零宽空格) - 三级宽松解析:正则→Uri.parse→兜底phone=提取 - 添加 [QR_SCAN] 调试日志定位实际扫码值 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
8c31dee000
commit
03cc5bc324
|
|
@ -570,6 +570,7 @@ class _SendSharesPageState extends ConsumerState<SendSharesPage> {
|
||||||
if (result == null) return;
|
if (result == null) return;
|
||||||
|
|
||||||
// 解析二维码内容
|
// 解析二维码内容
|
||||||
|
debugPrint('[QR_SCAN] scanner returned: "$result"');
|
||||||
final phone = parseTransferQrCode(result);
|
final phone = parseTransferQrCode(result);
|
||||||
if (phone != null) {
|
if (phone != null) {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|
|
||||||
|
|
@ -250,37 +250,42 @@ class _QrScannerSheetState extends State<QrScannerSheet> {
|
||||||
/// 返回手机号,解析失败返回 null
|
/// 返回手机号,解析失败返回 null
|
||||||
String? parseTransferQrCode(String qrCode) {
|
String? parseTransferQrCode(String qrCode) {
|
||||||
try {
|
try {
|
||||||
final trimmed = qrCode.trim();
|
// 去除首尾空白及不可见字符(BOM、零宽空格等)
|
||||||
|
final trimmed = qrCode.trim().replaceAll(RegExp(r'[\u200B-\u200D\uFEFF\u00A0]'), '');
|
||||||
|
|
||||||
// 使用正则表达式匹配,兼容有无 / 的格式
|
debugPrint('[QR_SCAN] raw length=${qrCode.length}, trimmed length=${trimmed.length}');
|
||||||
// durian://transfer/?phone=xxx 或 durian://transfer?phone=xxx
|
debugPrint('[QR_SCAN] raw codeUnits=${qrCode.codeUnits}');
|
||||||
final regex = RegExp(r'^durian://transfer/?[?]phone=(\d{11})$');
|
debugPrint('[QR_SCAN] trimmed="$trimmed"');
|
||||||
|
|
||||||
|
// 方案1:宽松正则 - 只要包含 durian://transfer 和 phone=11位数字
|
||||||
|
final regex = RegExp(r'durian://transfer[/?].*?phone=(\d{11})');
|
||||||
final match = regex.firstMatch(trimmed);
|
final match = regex.firstMatch(trimmed);
|
||||||
|
|
||||||
if (match != null) {
|
if (match != null) {
|
||||||
|
debugPrint('[QR_SCAN] regex matched, phone=${match.group(1)}');
|
||||||
return match.group(1);
|
return match.group(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 备用方案:使用 Uri.parse
|
// 方案2:Uri.parse
|
||||||
final uri = Uri.parse(trimmed);
|
final uri = Uri.tryParse(trimmed);
|
||||||
|
if (uri != null && uri.scheme == 'durian') {
|
||||||
// 检查 scheme
|
final phone = uri.queryParameters['phone'];
|
||||||
if (uri.scheme != 'durian') return null;
|
if (phone != null && RegExp(r'^\d{11}$').hasMatch(phone)) {
|
||||||
|
debugPrint('[QR_SCAN] Uri.parse matched, phone=$phone');
|
||||||
// 检查 host (即 authority 部分)
|
return phone;
|
||||||
if (uri.host != 'transfer') return null;
|
}
|
||||||
|
|
||||||
// 获取 phone 参数
|
|
||||||
final phone = uri.queryParameters['phone'];
|
|
||||||
if (phone == null || phone.isEmpty) return null;
|
|
||||||
|
|
||||||
// 简单验证手机号格式
|
|
||||||
if (phone.length != 11 || !RegExp(r'^\d{11}$').hasMatch(phone)) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return phone;
|
// 方案3:最宽松兜底 - 字符串中任何 phone=11位数字
|
||||||
|
final fallback = RegExp(r'phone=(\d{11})').firstMatch(trimmed);
|
||||||
|
if (fallback != null) {
|
||||||
|
debugPrint('[QR_SCAN] fallback matched, phone=${fallback.group(1)}');
|
||||||
|
return fallback.group(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
debugPrint('[QR_SCAN] all parsing failed for: "$trimmed"');
|
||||||
|
return null;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
debugPrint('[QR_SCAN] exception: $e');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue