npm package: @owl-eyes/react-native-nfc
Description: React Native NFC passport reading SDK for Owl Eyes identity verification
Author: Sequenxa
Latest version: 1.0.8

# @owl-eyes/react-native-nfc

React Native NFC passport reading SDK for Owl Eyes identity verification.

Cross-platform bridge to native Android and iOS NFC passport reading libraries.

## Features

- 🔐 **BAC/PACE Authentication** - Automatic protocol selection
- 📖 **Data Group Reading** - DG1-DG16, SOD, COM
- ✅ **Passive Authentication** - SOD signature verification
- 🛡️ **Active Authentication** - Chip authenticity verification
- 🔒 **Chip Authentication** - Clone detection
- 📱 **Cross-Platform** - iOS 14+ and Android 7+
- ⚡ **React Hooks** - Easy integration with React Native apps
- 📊 **Progress Events** - Real-time progress updates
- 🎯 **TypeScript** - Full type safety

## Installation

```bash
# Using npm
npm install @owl-eyes/react-native-nfc

# Using yarn
yarn add @owl-eyes/react-native-nfc
```

### iOS Setup

1. Add NFC entitlements to your app:

```xml
<!-- ios/YourApp/YourApp.entitlements -->
<key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
<array>
    <string>A0000002471001</string>
</array>
```

2. Add NFC usage description to Info.plist:

```xml
<key>NFCReaderUsageDescription</key>
<string>We need NFC access to read your passport chip for identity verification.</string>
```

3. Install pods:

```bash
cd ios && pod install
```

### Android Setup

1. Add NFC permissions to AndroidManifest.xml:

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

2. The SDK automatically enables NFC foreground dispatch.

## Quick Start

```typescript
import { OwlEyesNFC } from '@owl-eyes/react-native-nfc';

// Check NFC availability
const isSupported = await OwlEyesNFC.isNFCSupported();
const isEnabled = await OwlEyesNFC.isNFCEnabled();

if (!isEnabled) {
  await OwlEyesNFC.openNFCSettings();
}

// Read passport
const result = await OwlEyesNFC.readPassport({
  documentNumber: '123456789',
  dateOfBirth: '1990-01-15',    // YYYY-MM-DD
  dateOfExpiry: '2028-01-15',
  includeImages: true,
});

if (result.success) {
  console.log('Name:', result.data?.mrz.firstName);
  console.log('Passive Auth:', result.data?.passiveAuthPassed);
  console.log('Active Auth:', result.data?.activeAuthPassed);
}
```

## Using React Hooks

### useNFCReader

Full-featured hook for managing NFC reader state:

```typescript
import { useNFCReader } from '@owl-eyes/react-native-nfc';

function PassportReader() {
  const {
    isAvailable,
    isEnabled,
    isReading,
    progress,
    result,
    readPassport,
    openSettings,
  } = useNFCReader();

  if (!isAvailable) {
    return <Text>NFC not available on this device</Text>;
  }

  if (!isEnabled) {
    return (
      <Button title="Enable NFC" onPress={openSettings} />
    );
  }

  return (
    <View>
      <Button
        title="Scan Passport"
        disabled={isReading}
        onPress={() => readPassport({
          documentNumber: '123456789',
          dateOfBirth: '1990-01-15',
          dateOfExpiry: '2028-01-15',
        })}
      />
      
      {isReading && (
        <View>
          <ProgressBar progress={progress?.progress ?? 0} />
          <Text>{progress?.message}</Text>
        </View>
      )}
      
      {result?.success && (
        <Text>Name: {result.data?.mrz.firstName}</Text>
      )}
    </View>
  );
}
```

### usePassportRead

Simplified hook focused on the read operation:

```typescript
import { usePassportRead } from '@owl-eyes/react-native-nfc';

function PassportScanner() {
  const {
    state,      // 'idle' | 'waiting' | 'reading' | 'complete' | 'error'
    progress,   // 0-100
    message,
    passport,
    error,
    read,
    cancel,
    reset,
  } = usePassportRead();

  // ... render based on state
}
```

### useNFCState

Simple hook for monitoring NFC availability:

```typescript
import { useNFCState } from '@owl-eyes/react-native-nfc';

function App() {
  const { availability, isReady, isLoading } = useNFCState();

  if (isLoading) {
    return <ActivityIndicator />;
  }

  if (!isReady) {
    return <NFCNotAvailableScreen />;
  }

  return <PassportReaderScreen />;
}
```

## API Reference

### OwlEyesNFC

#### Methods

| Method | Description |
|--------|-------------|
| `isNFCSupported()` | Check if device has NFC hardware |
| `isNFCEnabled()` | Check if NFC is enabled |
| `getCapabilities()` | Get detailed NFC capabilities |
| `openNFCSettings()` | Open device NFC settings |
| `readPassport(options)` | Read passport via NFC |
| `cancelRead()` | Cancel ongoing read |
| `fetchCertificates(countryCode?)` | Pre-fetch CSCA certificates |
| `hasCertificates()` | Check if certificates are loaded |
| `clearCertificates()` | Clear cached certificates |

### NFCReadOptions

```typescript
interface NFCReadOptions {
  documentNumber: string;       // Passport number
  dateOfBirth: string;         // YYYY-MM-DD
  dateOfExpiry: string;        // YYYY-MM-DD
  includeImages?: boolean;     // Include face/signature images
  performActiveAuth?: boolean; // Attempt Active Authentication
  performChipAuth?: boolean;   // Attempt Chip Authentication
  timeout?: number;            // Timeout in milliseconds
  dataGroups?: DataGroupSelection[]; // Specific data groups to read
}
```

### NFCReadResult

```typescript
interface NFCReadResult {
  success: boolean;
  data?: {
    mrz: MRZData;
    faceImage?: string;        // Base64
    signatureImage?: string;   // Base64
    passiveAuthPassed: boolean;
    activeAuthPassed?: boolean;
    chipAuthPassed?: boolean;
    documentInfo: DocumentInfo;
  };
  error?: NFCError;
  readTimeMs?: number;
  protocolUsed?: 'BAC' | 'PACE';
}
```

## Event Emitter

Subscribe to NFC events:

```typescript
import { NFCEventEmitter } from '@owl-eyes/react-native-nfc';

// NFC state changes (Android)
const unsubscribe1 = NFCEventEmitter.addStateChangeListener((event) => {
  console.log('NFC enabled:', event.enabled);
});

// Progress updates
const unsubscribe2 = NFCEventEmitter.addProgressListener((progress) => {
  console.log(`${progress.stage}: ${progress.progress}%`);
});

// Tag detected
const unsubscribe3 = NFCEventEmitter.addTagDetectedListener((event) => {
  console.log('Tag detected:', event.isISODEP);
});

// Clean up
unsubscribe1();
unsubscribe2();
unsubscribe3();
```

## Utility Functions

### MRZ Helpers

```typescript
import {
  formatDateForMRZ,
  parseDateFromMRZ,
  validateMRZInput,
  sanitizeDocumentNumber,
} from '@owl-eyes/react-native-nfc';

// Format date for BAC/PACE key
const dob = formatDateForMRZ('1990-01-15'); // '900115'

// Parse MRZ date
const date = parseDateFromMRZ('900115'); // Date object

// Validate inputs
const error = validateMRZInput('123456789', '1990-01-15', '2028-01-15');
if (error) {
  console.error(error);
}

// Clean document number
const docNum = sanitizeDocumentNumber('AB<123456<'); // 'AB123456'
```

## Error Handling

```typescript
import { NFC_ERROR_CODES } from '@owl-eyes/react-native-nfc';

const result = await OwlEyesNFC.readPassport(options);

if (!result.success) {
  switch (result.error?.code) {
    case NFC_ERROR_CODES.TAG_LOST:
      // Ask user to hold steady
      break;
    case NFC_ERROR_CODES.BAC_FAILED:
      // Check document details
      break;
    case NFC_ERROR_CODES.PASSIVE_AUTH_FAILED:
      // Document may be tampered
      break;
  }
}
```

## Testing

### Device Requirements

- **Android**: Any device with NFC (API 24+)
- **iOS**: iPhone 7 or later (iOS 14+)

### Testing Guide

1. Use real passports with NFC chips for testing
2. Test both BAC-only and PACE passports
3. Test expired passports (chips still work)
4. Test with various countries' passports

See [Testing Documentation](./TESTING.md) for detailed testing procedures.

## Troubleshooting

### Common Issues

**"Tag lost" errors**
- Hold the device steady against the passport
- Try different positioning (passport photo page)
- Remove phone case if thick

**BAC authentication fails**
- Verify document number, DOB, and expiry are correct
- Check for OCR errors in MRZ reading
- Some documents use "filler" characters (<) - try without them

**NFC not detected**
- Ensure NFC is enabled in device settings
- Check that the passport has an NFC chip (look for the chip symbol)
- Try positioning the phone differently

## License

MIT

## Links

- [Owl Eyes Documentation](https://docs.owleyes.io)
- [API Reference](https://docs.owleyes.io/api/nfc)
- [GitHub](https://github.com/sequenxa/owl-eyes)