prism_ekyc

A Flutter plugin for eKYC (electronic Know Your Customer) of Japanese IC cards. Reads Residence Cards (在留カード) via NFC, captures the card backside via camera, and verifies the user's face.

Platform support: Android · iOS


Features

Feature Android iOS
NFC read (Residence Card) ✅ libjeid ✅ libjeid.xcframework
Card front image (PNG)
Face photo ✅ JPEG ✅ JPEG2000
Chip address / permissions
Card backside camera capture
Face verification (Vision / ML Kit)
OCR (card front text fields) ✅ ML Kit ✅ Vision

Installation

Add to your pubspec.yaml:

dependencies:
  prism_ekyc: 0.2.0

Android Setup

1. Maven repository

Add the libjeid repository to your root android/build.gradle (or build.gradle.kts):

// android/build.gradle.kts
allprojects {
    repositories {
        google()
        mavenCentral()
        maven { url = uri("https://cdn.osstech.co.jp/android") }
    }
}

2. App-level dependencies

In android/app/build.gradle.kts:

dependencies {
    // libjeid — NFC reading of Japanese IC cards
    implementation("jp.co.osstech:libjeid-free:20251031@aar")
    // BouncyCastle — required by libjeid for BAC/DES crypto
    implementation("org.bouncycastle:bcprov-lts8on:2.73.9")
    // ML Kit Japanese text recognition (for OCR of card front)
    implementation("com.google.mlkit:text-recognition-japanese:16.0.1")
}

3. Permissions

In android/app/src/main/AndroidManifest.xml:

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

Set launchMode="singleTop" on your MainActivity:

<activity
    android:name=".MainActivity"
    android:launchMode="singleTop"
    ...>

4. ProGuard rules

In android/app/proguard-rules.pro:

-keep class org.bouncycastle.** { *; }
-dontwarn org.bouncycastle.**
-keep class jp.co.osstech.libjeid.** { *; }
-dontwarn jp.co.osstech.libjeid.**

iOS Setup

1. NFC capability

In Xcode, enable the Near Field Communication Tag Reading capability for your app target.

2. Info.plist

<!-- ios/Runner/Info.plist -->
<key>NFCReaderUsageDescription</key>
<string>NFC is used to read your IC card for identity verification.</string>

<key>NSCameraUsageDescription</key>
<string>Camera is used to capture your ID card for identity verification.</string>

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

3. Entitlements

Add to Runner.entitlements:

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

4. libjeid.xcframework

libjeid.xcframework is bundled inside the plugin at ios/Frameworks/libjeid.xcframework. No additional CocoaPod or manual linking is required — the plugin's podspec handles it.


Usage

import 'package:prism_ekyc/prism_ekyc.dart';

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (_) => PrismEkyc.screen(
      PrismEkycConfig(
        // debugBypassNfc: true,  // skip real NFC scan during development
        onComplete: (EkycResult result) {
          print('Name: ${result.formData.fullName}');
          print('Card #: ${result.formData.cardNumber}');
          print('NFC address: ${result.nfcData?.chipAddress}');
          print('Face verified: ${result.faceVerified}');
        },
      ),
    ),
  ),
);

EkycResult

Field Type Description
formData UserFormData User-entered form data
nfcData NfcScanResult? Chip-read data (address, images, etc.)
backsideImage Uint8List? Card backside JPEG bytes
faceVerified bool Whether face matched the ID photo
faceMatchConfidence double? 0.0–1.0 confidence (null if not run)

NFC Method Channel Reference

The plugin exposes com.rubilabs.prism_ekyc/nfc for direct use if needed:

const _nfc = MethodChannel('com.rubilabs.prism_ekyc/nfc');

// Check if NFC is available and enabled
final bool available = await _nfc.invokeMethod('isNfcAvailable');

// Read a Residence Card (blocks until card is physically tapped)
final Map result = await _nfc.invokeMethod('readResidenceCard', {
  'cardNumber': 'AA12345678BC',  // 12-character number printed on the card front
});
// Returned keys:
//   cardFrontImage  — "data:image/png;base64,..."
//   photo           — "data:image/jpeg;base64,..."  (Android) or jp2 (iOS)
//   address         — String
//   addressCode     — String
//   addressDate     — String
//   comprehensivePermission — String
//   individualPermission    — String
//   updateStatus    — String
//   rcCardType      — "1" (regular) or "2" (special permanent)
//   isValid         — bool (chip signature validation)

// Cancel an in-progress read (e.g. when the screen is popped)
await _nfc.invokeMethod('stopRead');

eKYC Screen Flow

Welcome → NationalitySelector → IdInstruction → NfcScan →
BacksideCapture → FaceVerification → RegistrationForm → Completion
  • NationalitySelector — determines isJapanese (Japanese vs non-Japanese resident)
  • IdInstruction — for Japanese users, selects Driver's License vs My Number Card
  • NfcScan — reads the chip; non-Japanese users always scan a Residence Card
  • BacksideCapture — camera captures the physical card back → triggers OCR
  • FaceVerification — live camera + blink/smile challenge
  • RegistrationForm — user fills in remaining details
  • Completion — calls onComplete with the full EkycResult

Plugin Architecture

Android

Class Role
PrismEkycPlugin Flutter plugin entry point; ActivityAware; registers NFC + face channels
AndroidNfcReader NFC via NfcAdapter.enableReaderMode + libjeid-free
AndroidFaceComparison Face similarity via ML Kit Face Detection

iOS

Class Role
PrismEkycPlugin Flutter plugin entry point; registers NFC + face channels
NfcReader NFC via NFCTagReaderSession + libjeid.xcframework
FaceComparison Face similarity via Apple Vision VNGenerateImageFeaturePrintRequest

Troubleshooting

Android: NoClassDefFoundError: org.bouncycastle.* Add -keep class org.bouncycastle.** { *; } to proguard-rules.pro.

Android: app crashes immediately after "Reading data" in NFC dialog R8 is stripping libjeid or BouncyCastle classes in release builds. Add both -keep rules listed above.

iOS: NFC session never starts

  • Ensure the NFC capability is enabled in Xcode
  • Ensure NFCReaderUsageDescription is in Info.plist
  • NFC only works on physical devices (not simulator)

iOS: card not detected / Invalid tag Hold the card flat against the back/top of the iPhone and do not move either until the session closes.


License

Proprietary — RubiLabs © 2026

Libraries

prism_ekyc