Saturday, October 23, 2021

PCSC sample in Flutter/Dart

Here is a new PC/SC sample in Dart language I promised in PC/SC sample in different languages.

Fabien Rousseau wrote a PC/SC wrapper for Dart (the language) and Flutter (the UI toolkit).

The library is at It is available for GNU/Linux, macOS and Windows.

The source code is at and uses the MIT license. The current version is 0.0.4.

Fabien also provides an sample code at I reused this code for my example bellow.



I just cloned the flutter_pcsc git repository.

You also need to install the flutter SDK to build and run the application. But if you use Flutter I imagine your already have the SDK installed.

Source code

You can use flutter create test to create a sample application with the correct structure and configuration files.

Then edit the pubspec.yaml file to add in the dependencies: section something like:

    path: /home/rousseau/Documents/github/flutter_pcsc/flutter_pcsc

Of course you adapt the path to the location of your flutter_pcsc directory.

The source code of the sample application lib/main.dart is:

import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:convert';

import 'package:flutter_pcsc/flutter_pcsc.dart';

void main() {
  MyApp? myApp;

  runZonedGuarded(() async {
    FlutterError.onError = (FlutterErrorDetails details) {

    runApp(myApp = MyApp());
  }, (Object error, StackTrace stack) {

class MyApp extends StatelessWidget {
  final GlobalKey<_MyAppBodyState> _myAppKey = GlobalKey();

  MyApp({Key? key}) : super(key: key);

  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
          appBar: AppBar(
            title: const Text('PCSC example app'),
          body: MyAppBody(key: _myAppKey)),

  void addError(String msg) {

class MyAppBody extends StatefulWidget {
  const MyAppBody({required Key key}) : super(key: key);

  _MyAppBodyState createState() {
    return _MyAppBodyState();

enum MessageType { info, error }

class Message {
  final String content;
  final MessageType type;
  Message(this.type, this.content);

  static info(String content) {
    return Message(, content);

  static error(String content) {
    return Message(MessageType.error, content);

class _MyAppBodyState extends State<MyAppBody> {
  static const List<int> selectAppletCommand = [
    0x00, 0xA4, 0x04, 0x00, 0x0A, 0xA0, 0x00, 0x00, 0x00, 0x62,
    0x03, 0x01, 0x0C, 0x06, 0x01
  static const List<int> appCommand = [
    0x00, 0x00, 0x00, 0x00
  final ScrollController _scrollController = ScrollController();

  final List<Message> messages = [];

  void initState() {

  Future<void> helloWorld() async {
    /* establish PCSC context */
    int ctx = await Pcsc.establishContext(PcscSCope.user);
    CardStruct? card;
    try {
      /* get the reader list */
      List<String> readers = await Pcsc.listReaders(ctx);

      if (readers.isEmpty) {
        messages.add(Message.error('Could not detect any reader'));
      } else {
        /* use the first reader */
        String reader = readers[0];
        setState(() {
          messages.add('Using reader: $reader'));

        /* connect to the card */
        card = await Pcsc.cardConnect(
            ctx, reader, PcscShare.shared, PcscProtocol.any);

        /* send select applet APDU */
        var response = await Pcsc.transmit(card, selectAppletCommand);
            messages.add('Card returned: ${hexDump(response)}'));

        /* send applet test command */
        response = await Pcsc.transmit(card, appCommand);
        var sw = response.sublist(response.length - 2);
        var bytes = response.sublist(0, response.length - 2);
        var text = utf8.decode(bytes);

        messages.add('Card returned: ${hexDump(response)}'));

        if (sw[0] != 0x90 || sw[1] != 0x00) {
          setState(() {
                .add(Message.error('Card returned an error: ${hexDump(sw)}'));
        } else {
          setState(() {
            messages.add('text is: ${text}'));
    } finally {
      if (card != null) {
        try {
          /* disconnect from the card */
          await Pcsc.cardDisconnect(card.hCard, PcscDisposition.resetCard);
        } on Exception catch (e) {
      try {
        /* release PCSC context */
        await Pcsc.releaseContext(ctx);
      } on Exception catch (e) {

  static String hexDump(List<int> csn) {
    return csn
        .map((i) => i.toRadixString(16).padLeft(2, '0').toUpperCase())
        .join(' ');

  _scrollToBottom() {

  Widget build(BuildContext context) {
    TextStyle errorStyle = const TextStyle(color:;
    WidgetsBinding.instance?.addPostFrameCallback((_) => _scrollToBottom());
    return Row(crossAxisAlignment: CrossAxisAlignment.start, children: [
          child: Column(children: [
            child: ListView(
                controller: _scrollController,
                children: messages
                    .map((e) => Text(e.content,
                        style: e.type == MessageType.error ? errorStyle : null))
            margin: const EdgeInsets.all(10),
            child: ElevatedButton(
                onPressed: () async {
                  await tryAgain();
                child: const Text("Try again")))

  tryAgain() async {
    await helloWorld();


$ flutter run
hanging current working directory to: /home/rousseau/Documents/flutter/blog
Launching lib/main.dart on Linux in debug mode...
Building Linux application...                                           
Syncing files to device Linux...                                    55ms

Flutter run key commands.
r Hot reload. 🔥🔥🔥
R Hot restart.
h List all available interactive commands.
d Detach (terminate "flutter run" but leave application running).
c Clear the screen
q Quit (terminate the application on the device).

💪 Running with sound null safety 💪

An Observatory debugger and profiler on Linux is available at:
The Flutter DevTools debugger and profiler on Linux is available at:

Flutter is a framework to create graphical applications. So when you run the sample code you get a new window.


The code is long because it is a complete Flutter application so you have to handle the graphical interface.

I asked Fabien for a Dart only interface but flutter_pcsc depends on some Flutter mechanisms to handle asynchronism. So it is not possible to write a PC/SC application for the console just using Dart. But if you use Dart I guess you also use flutter.

Despite of his (nice) name Fabien Rousseau is not part of my direct family. So I do not have a potential conflict of interest here 😜.


Thanks to Fabien for telling about his Dart/Flutter project.

If you work on a Free Software PC/SC wrapper that is not yet in my list please let me know.