Flutter NFC信用卡读取信息

问题描述 投票:0回答:1

您好,我正在尝试使用 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,
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
android flutter mobile nfc credit-card
1个回答
0
投票

您没有正确迭代 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 标签的单个周期中退出。实现树对象类型并收集所有标签。

© www.soinside.com 2019 - 2024. All rights reserved.