Информация о считывании кредитной карты Flutter NFC

Здравствуйте, я пытаюсь получить информацию о кредитной или дебетовой карте с помощью NFC на Flutter. Я буду выполнять платежные операции с этой информацией. Я могу справиться с этой частью самостоятельно, но у меня возникли проблемы с получением информации о карте. Можете ли вы помочь? Заранее благодарны за Вашу помощь.

Я получаю эту ошибку прямо сейчас Не удалось извлечь AID из ответа PPSE.

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 (код пользовательского интерфейса)

    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,
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
0
0
79
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы неправильно перебираете ответ 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. Реализуйте тип объекта «дерево» и соберите все теги.

@MertYavuz - я ищу то же решение. Было бы здорово, если бы вы также поделитесь своим кодом с исправлением. Это мне поможет :)

mana 27.07.2024 00:11

Другие вопросы по теме