Skip to content

dalafiarisamuel/NfcReaderKMP

Repository files navigation

NfcReaderKMP 📱

Kotlin Compose Multiplatform License

A powerful, easy-to-use Kotlin Multiplatform (KMP) library for reading NFC tags on Android and iOS using Compose Multiplatform.

📖 View Full API Documentation


🚧 Work in Progress

This library is currently under active development and has not yet been published to Maven Central.

The core functionality is implemented and working on both Android and iOS, but we are still completing testing before the first stable release. The API may change before the official release.

Watch or star this repository to be notified when it is released.


✨ Features

  • 🚀 Unified API: A single, clean API to handle NFC scanning on both platforms.
  • 🎨 Compose Native: Lifecycle-aware state management that fits perfectly into your Compose UI.
  • 🛠️ Fully Customizable:
    • Android: Custom Bottom Sheet with support for Lottie animations (via Compottie).
    • iOS: Seamless integration with the native system NFC scanning dialog.
  • ⚙️ Flexible Configuration: Control timeouts, dismissal behaviors, and UI strings with a type-safe DSL.
  • 📊 Detailed Tag Info: Extract Serial Numbers, NDEF payloads, and supported technology lists.

📦 Installation

Add the dependency to your commonMain source set in build.gradle.kts:

sourceSets {
    commonMain.dependencies {
        implementation("com.devtamuno.kmp:nfcreader:<version>")
    }
}

🛠️ Platform Setup

Android 🤖

  1. Add NFC permissions to your AndroidManifest.xml:
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" android:required="false" />

iOS

  1. Add NFCReaderUsageDescription to your Info.plist.
  2. Enable the Near Field Communication Tag Reading capability in your Xcode project.
  3. Add NDEF support to the com.apple.developer.nfc.readersession.formats entitlement.

🚀 Usage

1. Initialize the State Manager

Create an NfcConfig and pass it to rememberNfcReadManagerState:

val nfcManager = rememberNfcReadManagerState(
    config = NfcConfig(
        titleMessage = "Ready to Scan",
        subtitleMessage = "Hold your tag near the device.",
        buttonText = "Cancel",
        nfcReadTimeout = 30.seconds
    )
)

2. Observe Results

Collect the nfcReadResult and react to different scanning states:

val result by nfcManager.nfcReadResult.collectAsState()

when (val state = result) {
    is NfcReadResult.Success -> {
        Text("Tag ID: ${state.data.serialNumber}")
        Text("Type: ${state.data.type}")
        Text("Payload: ${state.data.payload}")
        Text("Technologies: ${state.data.techList.joinToString()}")
    }
    is NfcReadResult.Error -> {
        Text("Error: ${state.message}", color = Color.Red)
    }
    NfcReadResult.Scanning -> {
        Text("Scanning for NFC tag...")
    }
    NfcReadResult.OperationCancelled -> {
        Text("Scanning cancelled")
    }
    NfcReadResult.Initial -> {
        Button(onClick = { nfcManager.startScanning() }) {
            Text("Start Scanning")
        }
    }
}

⚙️ Configuration Options (NfcConfig)

Property Type Default Platform
titleMessage String Required Android
subtitleMessage String Required Android & iOS
buttonText String Required Android
nfcReadTimeout Duration 60.seconds (min 5s) Android
nfcUnsupportedMessage String "NFC is not supported on this device" Android
nfcDisabledMessage String "NFC is disabled on this device" Android
nfcScanTimeoutMessage String "NFC scan timed out" Android
nfcSuccessMessage String "Tag scanned successfully" iOS
sheetGesturesEnabled Boolean true Android
shouldDismissBottomSheetOnBackPress Boolean false Android
shouldDismissBottomSheetOnClickOutside Boolean false Android
nfcScanningAnimationSlot @Composable ColumnScope.() -> Unit Built-in Lottie animation Android

Note: On iOS, only subtitleMessage is used — it maps directly to the native system NFC scanning dialog message. All other properties are Android-specific.


📄 Data Models

NfcTagData

  • serialNumber: The tag's unique ID as a hex-encoded string (available on both Android and iOS).
  • type: The tag type as an NfcTagType enum — see values below.
  • payload: The decoded string content of the tag. null if the tag is empty or non-NDEF.
  • techList: A list of hardware technologies detected (e.g., "Mifare Classic", "ISO 14443-3A").

NfcTagType

Value Description
NDEF NFC Data Exchange Format tag
NON_NDEF Tag that does not contain NDEF data
MIFARE MIFARE-based tag (Classic, Ultralight, DESFire)
ISO15693 ISO 15693 vicinity tag
ISO7816 ISO 7816-4 based smart card or tag
FELICA Sony FeliCa tag (transit/payments)

NfcReadResult

State Description
Initial No scan has been initiated yet
Scanning Actively scanning for a tag
Success(data) Tag was read successfully
Error(message) An error occurred during scanning
OperationCancelled Scanning was cancelled by the user or system

📺 Demo

Android Implementation iOS Implementation

🤝 Contributing

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


📜 License

This project is licensed under the MIT License - see the LICENSE file for details.

About

A Kotlin Multiplatform (KMP) library for reading NFC tags on Android and iOS using Compose Multiplatform.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors