您好,我正在尝试使用 flutter 上的 nfc 获取信用卡或借记卡信息。我将使用这些信息执行支付交易,我可以自己处理这部分,但我在获取卡信息时遇到问题,你能帮忙吗? 感谢您提前的帮助。
我现在收到此错误 无法从 PPSE 响应中提取 AID
nfc_view_model.dart
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:nfc_manager/nfc_manager.dart';
import 'package:nfc_manager/platform_tags.dart';
class NfcViewModel extends GetxController {
RxString message = ''.obs;
Future<void> startNFCReading() async {
try {
final bool isAvailable = await NfcManager.instance.isAvailable();
if (isAvailable) {
message.value = 'NFC is available.';
await NfcManager.instance.startSession(
onDiscovered: (NfcTag tag) async {
try {
if (kDebugMode) {
print('Tag found: ${tag.data}');
}
message.value = 'Tag found: ${tag.data}';
final IsoDep? isoDep = IsoDep.from(tag);
if (isoDep != null) {
// PPSE (Proximity Payment System Environment) seçimi
var ppseCommand = [
0x00,
0xA4,
0x04,
0x00,
0x0E,
0x32,
0x50,
0x41,
0x59,
0x2E,
0x53,
0x59,
0x53,
0x2E,
0x44,
0x44,
0x46,
0x30,
0x31,
0x00
];
var ppseResponse = await isoDep.transceive(
data: Uint8List.fromList(ppseCommand));
if (kDebugMode) {
print('PPSE Response: $ppseResponse');
}
if (ppseResponse.isEmpty) {
message.value = 'PPSE Response is empty.';
await NfcManager.instance.stopSession();
return;
}
// PPSE yanıtını işle ve AID'yi al
var aid = extractAidFromPpseResponse(ppseResponse);
if (aid == null) {
message.value = 'Failed to extract AID from PPSE response.';
await NfcManager.instance.stopSession();
return;
}
// AID seçim komutu
var aidCommand = [
0x00,
0xA4,
0x04,
0x00,
aid.length,
...aid,
0x00
];
var aidResponse = await isoDep.transceive(
data: Uint8List.fromList(aidCommand));
if (kDebugMode) {
print('AID Response: $aidResponse');
}
if (aidResponse.isEmpty) {
message.value = 'AID Response is empty.';
await NfcManager.instance.stopSession();
return;
}
// GET PROCESSING OPTIONS komutu
var gpoCommand = [
0x80,
0xA8,
0x00,
0x00,
0x02,
0x83,
0x00,
0x00
];
var gpoResponse = await isoDep.transceive(
data: Uint8List.fromList(gpoCommand));
if (kDebugMode) {
print('GPO Response: $gpoResponse');
}
if (gpoResponse.isEmpty) {
message.value = 'GPO Response is empty.';
await NfcManager.instance.stopSession();
return;
}
// RECORD okuma komutu
var readRecordCommand = [0x00, 0xB2, 0x01, 0x0C, 0x00];
var readRecordResponse = await isoDep.transceive(
data: Uint8List.fromList(readRecordCommand));
if (kDebugMode) {
print('Read Record Response: $readRecordResponse');
}
if (readRecordResponse.isEmpty) {
message.value = 'Read Record Response is empty.';
await NfcManager.instance.stopSession();
return;
}
// Kart bilgilerini ayıkla
final cardDetails = parseCardDetails(readRecordResponse);
message.value = cardDetails;
await NfcManager.instance.stopSession();
} else {
message.value = 'IsoDep not supported on this tag.';
}
} catch (e) {
message.value = 'Error: $e';
await NfcManager.instance.stopSession(errorMessage: e.toString());
}
},
);
} else {
message.value = 'NFC is not available.';
}
} catch (e) {
message.value = e.toString();
}
}
List<int>? extractAidFromPpseResponse(Uint8List response) {
try {
int index = 0;
while (index < response.length) {
int tag = response[index++];
int length = response[index++];
if (tag == 0x4F) {
// AID tag
return response.sublist(index, index + length);
}
index += length;
}
return null;
} catch (e) {
if (kDebugMode) {
print('Error extracting AID: $e');
}
return null;
}
}
String parseCardDetails(Uint8List response) {
String hexString = response
.map((e) => e.toRadixString(16).padLeft(2, '0'))
.join()
.toUpperCase();
// Yanıtın uzunluğunu kontrol edin
if (hexString.length < 20) {
return 'Error: Insufficient data length. Response length is ${hexString.length}';
}
try {
// Example extraction logic (adjust based on actual card data structure)
final cardNumber =
hexString.substring(0, 16); // Example: first 16 characters
final expiryDate =
hexString.substring(16, 20); // Example: next 4 characters
return 'Card Number: $cardNumber, Expiry Date: $expiryDate';
} catch (e) {
return 'Error parsing card details: $e';
}
}
}
nfc_screen.dart(UI代码)
import 'package:digipos/core/base/view/base_view.dart';
import 'package:digipos/view/payment/nfc/view_model/nfc_view_model.dart';
import 'package:digipos/view/widgets/appbar/custom_appbar_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import '../../../core/base/state/base_state.dart';
import '../../../core/constants/icons.dart';
class NfcScreen extends StatefulWidget {
const NfcScreen({super.key});
@override
State<NfcScreen> createState() => _NfcScreenState();
}
class _NfcScreenState extends BaseState<NfcScreen> {
final NfcViewModel _viewModel = Get.put(NfcViewModel());
@override
void initState() {
super.initState();
_viewModel.startNFCReading();
}
@override
Widget build(BuildContext context) {
return BaseView(
viewModel: _viewModel,
onPageBuilder: (context, dynamic viewModel) => scaffoldBody(),
);
}
Scaffold scaffoldBody() {
return Scaffold(
appBar: const CustomAppBarWidget(appBarType: AppBarType.back),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(
AppIcons.nfcPay.iconPath,
width: dynamicHeight(0.25),
),
const SizedBox(height: 20),
Obx(
() => Text(
_viewModel.message.value,
textAlign: TextAlign.center,
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
),
],
),
),
);
}
}
您没有正确迭代 PPSE 响应。 它被构造为一棵树,您需要以递归方式从响应中提取所有标签:
6F File Control Information (FCI) Template
840E325041592E5359532E4444463031A514BF0C11610F4F07A0000000031010500456697361
84 Dedicated File (DF) Name
325041592E5359532E4444463031 (2PAY.SYS.DDF01)
A5 File Control Information (FCI) Proprietary Template
BF0C11610F4F07A0000000031010500456697361
BF0C File Control Information (FCI) Issuer Discretionary Data
610F4F07A0000000031010500456697361
61 Application Template
4F07A0000000031010500456697361
4F Application Identifier (ADF Name)
A0000000031010
50 Application Label
56697361 (Visa)
您的循环仅通过根标签迭代列表,并且它在 0x6F 标签的单个周期中退出。实现树对象类型并收集所有标签。