nfcsigner 1.0.4 copy "nfcsigner: ^1.0.4" to clipboard
nfcsigner: ^1.0.4 copied to clipboard

Plugin cho thẻ BCard cho Android, iOS, Windows

example/lib/main.dart

import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:async';
import 'dart:convert';
import 'package:nfcsigner/nfcsigner.dart';
import 'package:open_filex/open_filex.dart';
import 'package:file_picker/file_picker.dart';
import 'package:path_provider/path_provider.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  bool _isSigning = false;
  bool _isLoading = false;
  String _statusMessage = 'Sẵn sàng để ký số';
  String _signatureHex = '';
  ServiceResult? _lastResult;
  String _publicKeyHex = '';
  String _certificateHex = '';

  String _bytesToHexString(Uint8List bytes) {
    return bytes.map((byte) => byte.toRadixString(16).padLeft(2, '0')).join('');
  }
/*
 * Phần giao tiếp dữ liệu Thẻ
 */
  Future<void> _handleSignData() async {
    setState(() {
      _isSigning = true;
      _signatureHex = '';
      _lastResult = null;
      _statusMessage = 'Đang chuẩn bị dữ liệu...';
    });

    final dataToSign = Uint8List.fromList(utf8.encode('Hello, Flutter!'));
    setState(() {
      _statusMessage = 'Đang băm dữ liệu (SHA-256)...';
    });
    // BƯỚC 1: Băm và tạo DigestInfo từ dữ liệu gốc
    final digestInfoToSend = createSha256DigestInfo(dataToSign);

    setState(() {
      _statusMessage = 'Đang chờ thẻ...';
    });
    // Gọi plugin và nhận về đối tượng ServiceResult
    final result = await Nfcsigner.generateSignature(
      appletID: 'D27600012401',
      pin: '123456',
      dataToSign: digestInfoToSend,
      keyIndex: 0
    );

    if (mounted) {
      setState(() {
        _isSigning = false;
        _lastResult = result; // Lưu lại kết quả để hiển thị chi tiết

        if (result.isSuccess && result.data != null) {
          _statusMessage = result.message;
          _signatureHex = _bytesToHexString(result.data as Uint8List);
        } else {
          // Xây dựng thông báo lỗi chi tiết
          String errorMessage = 'Lỗi: ${result.message}';
          if (result.sw1 != null && result.sw2 != null) {
            final swHex = '${result.sw1!.toRadixString(16)}${result.sw2!.toRadixString(16)}'.toUpperCase();
            errorMessage += ' (Mã lỗi: $swHex)';
          }
          _statusMessage = errorMessage;
        }
      });
    }
  }
  Future<void> _handleGetPublicKey() async {
    setState(() {
      _isLoading = true;
      _signatureHex = '';
      _publicKeyHex = '';
      _lastResult = null;
      _statusMessage = 'Đang chờ thẻ...';
    });

    final result = await Nfcsigner.getRsaPublicKey(
      appletID: 'D27600012401', // Thay bằng AID của bạn
      keyRole: KeyRole.sig, // Lấy khóa dùng để ký
    );

    if (mounted) {
      setState(() {
        _isLoading = false;
        _lastResult = result;
        if (result.isSuccess && result.data != null) {
          _statusMessage = 'Lấy khóa công khai thành công!';
          _publicKeyHex = _bytesToHexString(result.data as Uint8List);
        } else {
          // Xây dựng thông báo lỗi chi tiết
          String errorMessage = 'Lỗi: ${result.message}';
          if (result.sw1 != null) {
            final swHex = '${result.sw1!.toRadixString(16)}${result.sw2!.toRadixString(16)}'.toUpperCase();
            errorMessage += ' (Mã thẻ: $swHex)';
          }
          _statusMessage = errorMessage;
        }
      });
    }
  }
  // HÀM ĐỂ LẤY CERTIFICATE
  Future<void> _handleGetCertificate() async {
    setState(() {
      _isLoading = true;
      _signatureHex = '';
      _publicKeyHex = '';
      _certificateHex = '';
      _lastResult = null;
      _statusMessage = 'Đang chờ thẻ...';
    });

    final result = await Nfcsigner.getCertificate(
      appletID: 'D27600012401', // Applet ID
      keyRole: KeyRole.sig, // Lấy Ceftificate của Signature
    );

    if (mounted) {
      setState(() {
        _isLoading = false;
        _lastResult = result;
        if (result.isSuccess && result.data != null) {
          _statusMessage = 'Lấy certificate thành công!';
          _certificateHex = _bytesToHexString(result.data as Uint8List);
        } else {
          // Xây dựng thông báo lỗi chi tiết
          String errorMessage = 'Lỗi: ${result.message}';
          if (result.sw1 != null) {
            final swHex = '${result.sw1!.toRadixString(16)}${result.sw2!.toRadixString(16)}'.toUpperCase();
            errorMessage += ' (Mã thẻ: $swHex)';
          }
          _statusMessage = errorMessage;
        }
      });
    }
  }

  // --- HÀM MỚI ĐỂ TẠO VÀ KÝ PDF ---
  Future<void> _handleSignPdf() async {
    setState(() {
      _isLoading = true;
      _clearResults();
      _statusMessage = 'Vui lòng chọn file PDF...';
    });

    // 1. Chọn file
    FilePickerResult? result = await FilePicker.platform.pickFiles(
      type: FileType.custom,
      allowedExtensions: ['pdf'],
      withData: true, // Rất quan trọng: để lấy được nội dung file
    );

    if (result == null || result.files.single.bytes == null) {
      setState(() { _isLoading = false; _statusMessage = 'Đã hủy chọn file.'; });
      return;
    }
    final pdfBytes = result.files.single.bytes!;
    final pdfDigestInfoBytes = createSha256DigestInfo(pdfBytes);
    setState(() { _statusMessage = 'Đã chọn file. Vui lòng chạm thẻ để ký...'; });

    // 2. Tạo cấu hình chữ ký (có thể lấy ảnh từ assets hoặc file)
    final signatureConfig = PdfSignatureConfig(
      x: 350.0,           // Vị trí từ trái
      y: 700.0,          // Vị trí từ dưới
      width: 250.0,      // Chiều rộng
      height: 80.0,      // Chiều cao
      pageNumber: 1,     // Trang số 1
      contact: '[email protected]',
      signerName: 'Màu Văn Phương',
      signDate: DateTime.now(),
      signatureImage: await _loadSignatureImage(), // Tùy chọn: load ảnh chữ ký
      signatureImageHeight: 50,
      signatureImageWidth: 50,
    );
    // 3. Gọi plugin để ký
    final signResult = await Nfcsigner.signPdf(
      pdfBytes: pdfBytes,
      pdfHashBytes: pdfDigestInfoBytes,
      appletID: 'D27600012401',
      pin: '123456',
      reason: 'Ky nhay tam thoi',
      location: 'Hanoi',
      signatureConfig: signatureConfig, // TRUYỀN CẤU HÌNH VÀO
      signatureLength: 512,
    );

    // 4. Xử lý kết quả
    if (mounted) {
      setState(() {
        _isLoading = false;
        _lastResult = signResult;
        if (signResult.isSuccess && signResult.data != null) {
          _statusMessage = 'Ký PDF thành công! Đang lưu file...';
          // 4. Lưu file đã ký
          _saveSignedPdf(signResult.data!);
        } else {
          _statusMessage = 'Lỗi: ${signResult.message}';
        }
      });
    }
  }

  // HÀM _saveSignedPdf PHIÊN BẢN MỚI
  Future<void> _saveSignedPdf(Uint8List signedBytes) async {
    try {
      // 1. Lấy thư mục tạm thời của ứng dụng
      final tempDir = await getTemporaryDirectory();
      final filePath = '${tempDir.path}/signed_${DateTime.now().millisecondsSinceEpoch}.pdf';
      final file = File(filePath);

      // 2. Lưu file vào thư mục tạm thời
      await file.writeAsBytes(signedBytes);
      if (kDebugMode) {
        print("Đã lưu file tạm thời tại: $filePath");
      }

      // 3. Dùng open_filex để MỞ file
      final result = await OpenFilex.open(filePath);

      // 4. Cập nhật trạng thái cho người dùng
      setState(() {
        _statusMessage = 'Ký thành công lưu file tại: $filePath';
      });

    } catch (e) {
      setState(() {
        _statusMessage = 'Lỗi khi lưu hoặc mở file: ${e.toString()}';
      });
    }
  }
  // Hàm helper để reset trạng thái hiển thị
  void _clearResults() {
    setState(() {
      _lastResult = null;
    });
  }
  // Hàm tùy chọn để load ảnh chữ ký từ assets
  Future<Uint8List?> _loadSignatureImage() async {
    try {
      final ByteData data = await rootBundle.load('assets/signature.png');
      return data.buffer.asUint8List();
    } catch (e) {
      print('Không thể load ảnh chữ ký: $e');
      return null;
    }
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Ví dụ Plugin Ký số'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(24.0),
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[

              Text(
                _statusMessage,
                textAlign: TextAlign.center,
                style: Theme.of(context).textTheme.titleMedium?.copyWith(
                    color: _lastResult == null ? null : (_lastResult!.isSuccess ? Colors.green.shade800 : Colors.red.shade800)
                ),
              ),
              const SizedBox(height: 32),
              if (_isSigning)
                const Center(child: CircularProgressIndicator())
              else
                ElevatedButton(
                  onPressed: _handleSignData,
                  style: ElevatedButton.styleFrom(
                    padding: const EdgeInsets.symmetric(vertical: 16),
                  ),
                  child: const Text('Bắt đầu Ký'),
                ),
              const SizedBox(height: 12),
              ElevatedButton(
                onPressed: _handleGetPublicKey,
                style: ElevatedButton.styleFrom(
                    backgroundColor: Colors.blueGrey,
                    padding: const EdgeInsets.symmetric(vertical: 16),
                ),
                child: const Text('Lấy Khóa Công Khai RSA'),
              ),
              const SizedBox(height: 12),
              // NÚT BẤM MỚI
              ElevatedButton(
                onPressed: _handleGetCertificate,
                style: ElevatedButton.styleFrom(
                    backgroundColor: Colors.teal,
                    padding: const EdgeInsets.symmetric(vertical: 16),
                ),
                child: const Text('Lấy Certificate'),
              ),
              const SizedBox(height: 16),
              if (_isLoading)
                const Center(child: CircularProgressIndicator())
              else
                ElevatedButton(
                  onPressed: _handleSignPdf,
                  style: ElevatedButton.styleFrom(
                      backgroundColor: Colors.deepPurple,
                      padding: const EdgeInsets.symmetric(vertical: 16)
                  ),
                  child: const Text('Tạo và Ký File PDF Mới'),
                ),
              if (_signatureHex.isNotEmpty)
                Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text(
                      'Chữ ký (Hex):',
                      style: TextStyle(fontWeight: FontWeight.bold),
                    ),
                    const SizedBox(height: 8),
                    Container(
                      padding: const EdgeInsets.all(12),
                      decoration: BoxDecoration(
                        color: Colors.grey.shade200,
                        borderRadius: BorderRadius.circular(8),
                      ),
                      child: SelectableText(
                        _signatureHex,
                        style: const TextStyle(fontFamily: 'monospace'),
                      ),
                    ),
                  ],
                ),
              if (_publicKeyHex.isNotEmpty)
                Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text('Khóa công khai (Hex):', style: TextStyle(fontWeight: FontWeight.bold)),
                    const SizedBox(height: 8),
                    Container(
                      padding: const EdgeInsets.all(12),
                      decoration: BoxDecoration(color: Colors.grey.shade200, borderRadius: BorderRadius.circular(8)),
                      child: SelectableText(_publicKeyHex, style: const TextStyle(fontFamily: 'monospace')),
                    ),
                  ],
                ),
              if (_certificateHex.isNotEmpty)
                Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text('Certificate (Hex):', style: TextStyle(fontWeight: FontWeight.bold)),
                    const SizedBox(height: 8),
                    Container(
                      padding: const EdgeInsets.all(12),
                      decoration: BoxDecoration(color: Colors.grey.shade200, borderRadius: BorderRadius.circular(8)),
                      child: SelectableText(_certificateHex, style: const TextStyle(fontFamily: 'monospace')),
                    ),
                  ],
                ),
            ],
          ),
        ),
      ),
    );
  }
}
1
likes
0
points
10
downloads

Publisher

unverified uploader

Weekly Downloads

Plugin cho thẻ BCard cho Android, iOS, Windows

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

crypto, flutter, flutter_web_plugins, pdf, plugin_platform_interface, printing

More

Packages that depend on nfcsigner

Packages that implement nfcsigner