Hello, I am trying to obtain credit card or debit card information with nfc on flutter. I will perform payment transactions with this information, I can handle that part myself, but I am having trouble getting card information, can you help? Thanks for your help in advance.
I'm getting this error right now Failed to extract AID from PPSE response
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 Code)
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,
),
),
),
],
),
),
);
}
}
You are not correctly iterating over PPSE response. It is constructed as a tree and you need to extract all the tags from the response as recursive:
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)
Your loop iterates over a list by only root tag and it is exiting in single cycle for 0x6F tag. Implement tree object type and collect all tags.