MRT Card Reader

style: very good analysis Pub Version License: GPL-3.0

A Flutter package for reading transaction data from Dhaka MRT (Mass Rapid Transit) metro rail cards using NFC. This package allows you to easily access card balance and transaction history.

MRT Card Reader Demo

Features

  • Check NFC availability on the device
  • Read Dhaka MRT card balance
  • Retrieve transaction history (journeys and top-ups)
  • Parse transaction details including:
    • Transaction timestamps
    • Origin and destination
    • Journey costs
    • Top-up amounts
    • Current balance

Requirements

  • Flutter 3.0.0 or higher
  • Android device with NFC capabilities (API level 19+)
  • iOS device with NFC capabilities (iOS 13+)

Installation

Add mrt_card_reader to your pubspec.yaml:

dependencies:
  mrt_card_reader: ^0.1.0

Then run:

flutter pub get

Platform-specific setup

Android

Add the following permissions to your AndroidManifest.xml file:

<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" android:required="true" />

iOS

Add the following to your Info.plist file:

<key>NFCReaderUsageDescription</key>
<string>This app needs access to NFC to read MRT card data.</string>

<key>com.apple.developer.nfc.readersession.formats</key>
<array>
    <string>TAG</string>
</array>

You also need to enable the Near Field Communication Tag Reading capability in your Xcode project.

Usage

Basic Example

import 'package:flutter/material.dart';
import 'package:mrt_card_reader/mrt_card_reader.dart';

class MrtCardReaderDemo extends StatefulWidget {
  const MrtCardReaderDemo({Key? key}) : super(key: key);

  @override
  State<MrtCardReaderDemo> createState() => _MrtCardReaderDemoState();
}

class _MrtCardReaderDemoState extends State<MrtCardReaderDemo> {
  String _status = 'Ready to scan';
  int? _balance;
  List<MrtTransaction> _transactions = [];

  Future<void> _startScan() async {
    // Check if NFC is available
    final isNfcAvailable = await MrtCardReader.isAvailable();
    
    if (!isNfcAvailable) {
      setState(() {
        _status = 'NFC is not available on this device';
      });
      return;
    }

    // Start NFC session to read the card
    await MrtCardReader.startSession(
      onStatus: (status) {
        setState(() {
          _status = status;
        });
      },
      onBalance: (balance) {
        setState(() {
          _balance = balance;
        });
      },
      onTransactions: (transactions) {
        setState(() {
          _transactions = transactions;
        });
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('MRT Card Reader')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Status: $_status'),
            if (_balance != null) Text('Balance: \$${_balance! / 100}'),
            ElevatedButton(
              onPressed: _startScan,
              child: const Text('Scan MRT Card'),
            ),
            if (_transactions.isNotEmpty) ...[
              const SizedBox(height: 20),
              const Text('Recent Transactions', 
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
              Expanded(
                child: ListView.builder(
                  itemCount: _transactions.length,
                  itemBuilder: (context, index) {
                    final transaction = _transactions[index];
                    return ListTile(
                      title: Text(transaction.isTopup 
                        ? 'Top-up at ${transaction.fromStation}'
                        : 'Journey from ${transaction.fromStation} to ${transaction.toStation}'),
                      subtitle: Text(transaction.timestamp),
                      trailing: Text(
                        transaction.isTopup
                          ? '+\$${transaction.cost ?? 0 / 100}'
                          : '-\$${transaction.cost ?? 0 / 100}',
                        style: TextStyle(
                          color: transaction.isTopup ? Colors.green : Colors.red,
                        ),
                      ),
                    );
                  },
                ),
              ),
            ],
          ],
        ),
      ),
    );
  }
}

For a complete example, check out the example directory in the repository.

API Reference

MrtCardReader

static Future<bool> isAvailable()

Checks if NFC is available on the device.

Returns true if NFC is available and enabled, false otherwise.

static Future<void> startSession({required Function(String) onStatus, required Function(int?) onBalance, required Function(List<MrtTransaction>) onTransactions})

Starts an NFC reading session to retrieve MRT card data.

Parameters:

  • onStatus: Callback that provides status updates during the reading process.
  • onBalance: Callback that provides the current card balance after successful reading.
  • onTransactions: Callback that provides the list of transactions read from the card.

MrtTransaction

Represents a transaction record from an MRT card.

Properties

  • timestamp: Timestamp of when the transaction occurred.
  • fromStation: Name of the origin station (or top-up location).
  • toStation: Name of the destination station (may be empty for top-ups).
  • balance: Card balance after this transaction (in local currency).
  • cost: Cost of the journey or amount topped up (in local currency).
  • isTopup: Whether this transaction represents a top-up rather than a journey.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the terms of the GNU General Public License v3.0 (GPL-3.0). See the LICENSE file for details.

Acknowledgements

The core idea and logic for this project were inspired by MRT Buddy, created by Aniruddha Adhikary. Thanks to the team for the original work!

Libraries

mrt_card_reader
A Flutter package for reading transaction data from Dhaka MRT (Mass Rapid Transit) metro rail cards using NFC.