npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@taprails/tap-to-pay

v0.1.16

Published

TapRails SDK — React Native tap-to-pay for contactless stablecoin payments (NFC with USDC on Base network)

Readme

@taprails/tap-to-pay

A React Native SDK for contactless stablecoin payments using NFC tap-to-pay with USDC on Base network.

Features

  • 🚀 Easy integration into React Native apps
  • 📱 NFC tap-to-pay for contactless payments (HCE supported)
  • 💰 USDC stablecoin on Base network
  • 🔐 Backend API integration for secure blockchain operations
  • 🎨 Beautiful TapRails branded UI (optional, built-in)
  • 🔒 No private keys or blockchain code in the SDK
  • 📦 TypeScript support with full type definitions
  • 🎯 Built with Expo modules
  • ⚡ Automatic retry logic and error handling

[!WARNING] Platform Limitations Due to iOS restrictions on Host Card Emulation (HCE), the device acting as the Merchant (emitting the payment request) MUST be an Android device. The Customer (reading the request and processing payment) can use either iOS or Android.

🎨 TapRails UI — Neobank Design System

The SDK ships a production-ready UI layer built to the standard of modern neobank apps (Monzo, Revolut, Starling). Every screen is clean, focused, and animated — zero design work required.

UI Highlights

  • 🎯 Neobank-grade design — Pill-shaped buttons, bold amount heroes, bottom-sheet modal with drag handle
  • 📱 Full Payment Flows — Merchant and customer screens handled end-to-end
  • 🌗 Fully Themeable — Every color, spacing value, and border radius reads from the theme context at render time; StyleSheet.create holds zero hardcoded color or spacing values
  • ♿ Accessible — Screen reader labels, 44pt touch targets, WCAG AA contrast
  • 📲 Responsive — Safe area aware, adapts to all screen sizes

Quick Start with UI

1. Install Additional Dependencies

The TapRails UI requires these additional packages:

npm install react-native-reanimated react-native-safe-area-context
# or
yarn add react-native-reanimated react-native-safe-area-context

2. Wrap Your App with Theme Provider

import { TapRailsThemeProvider } from '@taprails/tap-to-pay';

function App() {
  return (
    <TapRailsThemeProvider
      colorOverrides={{
        primary: '#8B5CF6', // Optional: customize purple brand color
      }}
    >
      {/* Your app content */}
    </TapRailsThemeProvider>
  );
}

3. Use PaymentFlowManager

The PaymentFlowManager component handles the entire payment UI flow automatically:

import { PaymentFlowManager } from '@taprails/tap-to-pay';
import { useState } from 'react';

function MerchantScreen() {
  const [showFlow, setShowFlow] = useState(false);

  return (
    <>
      <Button title="Accept Payment" onPress={() => setShowFlow(true)} />

      {showFlow && (
        <PaymentFlowManager
          config={{
            type: 'merchant',
            onComplete: (data) => {
              console.log('Payment complete!', data);
              setShowFlow(false);
            },
            onCancel: () => setShowFlow(false),
            onError: (error) => {
              console.error('Payment error:', error);
            }
          }}
          onMerchantCancel={() => setShowFlow(false)}
        />
      )}
    </>
  );
}

That's it! The component handles amount entry (or skips it if you pass amount), NFC operations, and all payment states.

Merchant Flow — Pre-filling the Amount

If your app already knows the charge amount (e.g. from a cart or POS system), pass it directly to PaymentFlowManager. The SDK skips the manual entry screen and shows a clean confirmation card instead. The merchant must still press "Accept Payment" to proceed.

// Pre-filled: shows a confirmation card — no keypad needed
<PaymentFlowManager
  config={{ type: 'merchant', onComplete: ..., onCancel: ... }}
  amount="25.00"
  onMerchantCancel={() => setShowFlow(false)}
/>

// No amount: shows the large inline input + quick-select chips
<PaymentFlowManager
  config={{ type: 'merchant', onComplete: ..., onCancel: ... }}
  onMerchantCancel={() => setShowFlow(false)}
/>

| amount prop | Merchant sees | |---|---| | Provided | Read-only amount card + "Accept Payment" CTA | | Omitted | Large inline $ input + $5 $10 $25 $50 quick chips |

Payment Flow Screens

Merchant Flow

  1. Payment Creation / Confirmation — If amount prop is set: read-only confirmation card. If not: large inline $ input with quick-select chips.
  2. NFC Waiting Screen — Amount hero at top, animated NFC rings as focal point, expiry timer + status badge at bottom
  3. Processing Screen — Amount stays visible, spinner with track+arc animation, live status label from backend
  4. Success Screen — Green-tinted amount card, receipt with dividers (date, time, tx hash, network, status)

Customer Flow

  1. Tap Screen — NFC animation as hero, payment card shown when amount is known, instruction banner
  2. Processing Screen — Step-by-step indicators (grey → primary → success green)
  3. Success Screen — Identical receipt layout to merchant success

Error Screen

  • Smart error type detection (timeout, insufficient funds, network, NFC, cancelled)
  • Tinted error icon circle
  • Inline debug trace in __DEV__ builds (left-accent box)
  • Retry / Cancel action buttons

Theme Customization

Every color token in the table below can be overridden via colorOverrides. All SDK screens and components read values from the theme context at render time — there are no hardcoded colors anywhere in the UI layer.

<TapRailsThemeProvider
  colorOverrides={{
    // Brand
    primary:            '#8B5CF6', // Purple (TapRails default)
    primaryDark:        '#7C3AED',
    primaryLight:       '#A78BFA',

    // Semantic states
    success:            '#10B981',
    error:              '#EF4444',
    warning:            '#F59E0B',
    info:               '#3B82F6',

    // Surfaces
    background:         '#FFFFFF', // Main screen / modal background
    backgroundSecondary:'#F9FAFB', // Cards (PaymentCard, receipt, steps)
    backgroundTertiary: '#F3F4F6', // Feature highlight boxes

    // Text
    text:               '#1F2937',
    textSecondary:      '#6B7280',
    textTertiary:       '#9CA3AF',
    textInverse:        '#FFFFFF', // Text on primary-colored backgrounds

    // Borders
    border:             '#E5E7EB',
    borderLight:        '#F3F4F6',

    // Overlays
    overlay:            'rgba(0, 0, 0, 0.5)',  // Modal backdrop
    overlayLight:       'rgba(0, 0, 0, 0.3)',
  }}
>
  {/* App */}
</TapRailsThemeProvider>

[!TIP] To implement a dark mode, override the surface and text tokens:

colorOverrides={{
  background: '#0F0F0F',
  backgroundSecondary: '#1A1A1A',
  backgroundTertiary: '#252525',
  text: '#F9FAFB',
  textSecondary: '#9CA3AF',
  border: '#2D2D2D',
  overlay: 'rgba(0, 0, 0, 0.75)',
}}

Accessing Theme in Your Own Components

import { useTheme } from '@taprails/tap-to-pay';

function CustomComponent() {
  const theme = useTheme();

  return (
    <View
      style={{
        backgroundColor: theme.colors.backgroundSecondary,
        borderRadius: theme.borderRadius.xl,
        padding: theme.spacing.lg,
      }}
    >
      <Text style={[theme.typography.styles.h2, { color: theme.colors.text }]}>
        $25.00
      </Text>
    </View>
  );
}

Available Typography Styles

| Token | Size | Weight | Use for | |---|---|---|---| | h1 | 32px | Bold | Large amount displays | | h2 | 28px | Bold | Screen titles | | h3 | 24px | Semibold | Section headings | | h4 | 20px | Semibold | Sub-headings | | bodyLarge | 18px | Regular | Prominent body copy | | body | 16px | Regular | Standard body text | | bodySmall | 14px | Regular | Card labels, metadata | | caption | 12px | Regular | Timestamps, fine print | | button | 16px | Semibold | Button labels | | buttonLarge | 18px | Semibold | Large button labels |

Available Spacing Tokens

theme.spacing.xs   // 4
theme.spacing.sm   // 8
theme.spacing.md   // 12
theme.spacing.lg   // 16
theme.spacing.xl   // 20
theme.spacing['2xl'] // 24
theme.spacing['3xl'] // 32
theme.spacing['4xl'] // 40

Available Border Radius Tokens

theme.borderRadius.sm   // 4
theme.borderRadius.md   // 8
theme.borderRadius.lg   // 12
theme.borderRadius.xl   // 16
theme.borderRadius['2xl'] // 20
theme.borderRadius['3xl'] // 24 (modal sheet corners)
theme.borderRadius.full // 9999 (pill buttons)

Installation

1. Install the SDK

npm install @taprails/tap-to-pay
# or
yarn add @taprails/tap-to-pay

2. Install Peer Dependencies

npm install \
  buffer \
  react-native-get-random-values@^1.11.0 \
  react-native-keychain@^8.2.0 \
  react-native-nfc-manager \
  react-native-device-info \
  react-native-svg \
  react-native-reanimated \
  react-native-safe-area-context

# For iOS - link native modules
cd ios && pod install && cd ..

[!IMPORTANT] React Native Version Compatibility

  • This SDK is tested with React Native 0.72
  • Use react-native-keychain@^8.2.0 (v10+ requires AndroidX DataStore which conflicts with RN 0.72)
  • Use react-native-get-random-values@^1.11.0 (v2+ requires RN 0.81+)

3. Add Polyfill Imports

Add these lines to the very top of your app entry point (index.js or App.tsx):

import 'react-native-get-random-values';
import { Buffer } from 'buffer';
global.Buffer = Buffer;

Why these are needed:

  • react-native-get-random-values: Required by TweetNaCl for secure random number generation
  • buffer: Required by tweetnacl-util for encoding/decoding operations

4. Android Configuration

Add Required Dependencies

In android/app/build.gradle, add these dependencies:

dependencies {
    // ... other dependencies
    
    // Required by react-native-keychain v8
    implementation "androidx.datastore:datastore-core:1.0.0"
    implementation "androidx.datastore:datastore-preferences:1.0.0"
    implementation "androidx.datastore:datastore-preferences-core:1.0.0"
    
    // Fix Kotlin stdlib version conflicts
    configurations.all {
        resolutionStrategy {
            force "org.jetbrains.kotlin:kotlin-stdlib:1.8.0"
            force "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0"
            force "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0"
        }
    }
}

Update build.gradle (Project Level)

In android/build.gradle, ensure Kotlin is configured:

buildscript {
    ext {
        kotlinVersion = "1.8.0"
    }
    dependencies {
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
    }
}

5. Platform-Specific Notes

iOS

After installing dependencies, always run:

cd ios && pod install && cd ..

Android

No additional linking required - autolinking handles native modules.

[!NOTE] This SDK uses native modules (react-native-keychain, react-native-nfc-manager, etc.). It works with bare React Native CLI projects. For Expo projects, you must use Development Builds (not Expo Go).

Verification

To verify your installation:

# iOS
npm run ios
# or
react-native run-ios

# Android  
npm run android
# or
react-native run-android

The app should build and launch without errors.

Quick Start

1. Initialize the SDK

Initialize the SDK in your app's entry point with your API credentials:

import { ContactlessCryptoSDK, PaymentMode, TapRailsThemeProvider } from '@taprails/tap-to-pay';

// For Custodial fintechs & payment mode (app pays from pool)
ContactlessCryptoSDK.initialize({
  apiKey: 'pk_live_your_api_key',
  apiUrl: 'https://api.yourbackend.com',
  environment: 'production',
  merchantId: 'merchant_123',              // Required when acting as merchant
  aid: 'YOUR_UNIQUE_AID',                  // Unique AID assigned from your dashboard
  mode: PaymentMode.POOL,
  pool: {
    customerId: 'customer_456',            // Customer identifier
  }
});

// For non-custodial fintechs & payment providers session key mode (user's wallet, instant payments)
ContactlessCryptoSDK.initialize({
  apiKey: 'pk_live_your_api_key',
  apiUrl: 'https://api.yourbackend.com',
  environment: 'production',
  aid: 'YOUR_UNIQUE_AID',                  // Unique AID assigned from your dashboard
  mode: PaymentMode.SESSION_KEY,
  sessionKey: {
    walletAddress: '0x1234567890abcdef...',  // User's wallet address
    defaultDailyLimit: '100.00',              // Daily spending limit
    autoRenew: true,                          // Auto-renew expired keys
    onSignTransaction: async (tx) => {
      // Integrate with your wallet solution to sign
      const signature = await walletProvider.signTransaction(tx);
      return signature;
    },
    // Optional: Callbacks for session key setup flow
    onSetupComplete: () => {
      console.log('Session key setup completed successfully!');
    },
    onSetupCancel: () => {
      console.log('User cancelled session key setup');
    }
  }
});

// Wrap your app with TapRailsThemeProvider for automatic session key setup
function App() {
  return (
    <TapRailsThemeProvider>
      <YourApp />
    </TapRailsThemeProvider>
  );
}

[!NOTE] Payment Modes:

  • Custodial (POOL): App pays from a pooled wallet (requires to fund your company's pool on the TapRails dashboard)
  • Non-Custodial (SESSION_KEY): User's wallet with session keys for instant, gasless tap-to-paypayments (session setup handled automatically)

[!IMPORTANT] When using SESSION_KEY mode:

  • Session key setup flow is automatically managed by TapRailsThemeProvider
  • The SDK detects when a session key is needed and shows the setup UI
  • All session key configuration is in the sessionKey object
  • No manual state management needed!

2. Merchant Flow: Accept Payments

Use PaymentFlowManager for a complete, branded merchant payment experience:

import { PaymentFlowManager } from '@taprails/tap-to-pay';
import { useState } from 'react';

function MerchantScreen() {
  const [showFlow, setShowFlow] = useState(false);

  return (
    <>
      <Button title="Accept Payment" onPress={() => setShowFlow(true)} />

      {showFlow && (
        <PaymentFlowManager
          config={{
            type: 'merchant',
            onComplete: (data) => {
              console.log('Payment complete!', data);
              setShowFlow(false);
            },
            onCancel: () => setShowFlow(false),
            onError: (error) => console.error('Payment error:', error),
          }}
          // Optional: pass the amount from your POS/cart.
          // If omitted, the SDK shows a large inline amount input.
          amount="25.00"
          onMerchantCancel={() => setShowFlow(false)}
        />
      )}
    </>
  );
}

What happens (with amount prop):

  1. Confirmation screen — Read-only amount card with network/currency details
  2. Merchant presses "Accept Payment"
  3. NFC Waiting screen — Amount hero at top, animated NFC rings as focal point, expiry timer
  4. Customer taps their phone to the merchant's device
  5. Success screen — Green-tinted amount card + full receipt

What happens (without amount prop):

  1. Amount entry screen — Large Monzo-style $ input + $5 $10 $25 $50 quick chips
  2. Merchant enters amount and presses "Generate Tap Payment"
  3. → Same NFC waiting and success flow as above

[!NOTE] The PaymentFlowManager handles the entire UI flow including amount input, NFC writing, waiting for customer tap, and success/error states.

3. Customer Flow: Make Payments

For customers paying merchants:

import { PaymentFlowManager } from '@taprails/tap-to-pay';
import { useState } from 'react';

function CustomerScreen() {
  const [showFlow, setShowFlow] = useState(false);

  return (
    <>
      <Button title="Pay Now" onPress={() => setShowFlow(true)} />

      {showFlow && (
        <PaymentFlowManager
          config={{
            type: 'customer',
            onComplete: (data) => {
              console.log('Payment successful!', data);
              setShowFlow(false);
            },
            onCancel: () => setShowFlow(false),
            onError: (error) => {
              console.error('Payment failed:', error);
            }
          }}
          onCustomerCancel={() => setShowFlow(false)}
        />
      )}
    </>
  );
}

What happens:

  1. Tap instruction screen with animated NFC icon
  2. Customer taps phone to merchant's NFC tag/device
  3. SDK reads payment request from NFC
  4. Processing screen shows payment progress
  5. SDK processes payment (from pool or user's wallet depending on mode)
  6. Success screen displays transaction receipt

[!TIP] For SESSION_KEY mode, the SDK automatically handles session key setup before the first payment. Just wrap your app with TapRailsThemeProvider and the setup flow appears when needed.

SDK Configuration

ContactlessCryptoSDK.initialize(config)

Initialize the SDK with your configuration.

interface SDKConfig {
  apiKey: string;                              // Your API key
  apiUrl: string;                              // Backend API base URL
  environment: 'sandbox' | 'production';
  aid: string;                                 // Unique AID from your dashboard
  merchantId?: string;                         // Required when app acts as merchant
  mode?: PaymentMode;                          // POOL or SESSION_KEY
  
  // Pool payment configuration (for POOL mode)
  pool?: {
    customerId: string;                        // Customer identifier
  };
  
  // Session key configuration (for SESSION_KEY mode)
  sessionKey?: {
    walletAddress: string;                     // User's wallet address
    defaultDailyLimit: string;                 // Daily spending limit (e.g., "100.00")
    autoRenew: boolean;                        // Auto-renew expired session keys
    onSignTransaction: (tx: ApprovalTransaction) => Promise<string>;  // Transaction signer
    onSetupComplete?: () => void;              // Optional: Called when setup completes
    onSetupCancel?: () => void;                // Optional: Called when setup is cancelled
  };
}

enum PaymentMode {
  POOL = 'POOL',           // App pays from pooled wallet
  SESSION_KEY = 'SESSION_KEY'  // User's wallet with session keys
}

ContactlessCryptoSDK.getConfig()

Get current SDK configuration. Throws error if not initialized.

ContactlessCryptoSDK.isInitialized()

Check if SDK has been initialized.

Hooks

useNFCMerchant()

Hook for merchants to create payment requests.

Returns:

{
  createPaymentRequest: (params: { amount: string; merchantId: string }) => Promise<PaymentRequest | null>;
  isWriting: boolean;
  lastPaymentRequest: PaymentRequest | null;
  error: NFCPaymentError | null;
  clearError: () => void;
}

useNFCCustomer()

Hook for customers to scan and process payments.

Returns:

{
  scanPaymentRequest: () => Promise<PaymentRequest | null>;
  processPaymentRequest: (paymentId: string, txHash: string, customerWallet?: string) => Promise<ProcessPaymentResponse | null>;
  isReading: boolean;
  isProcessing: boolean;
  paymentRequest: PaymentRequest | null;
  processedPayment: ProcessPaymentResponse | null;
  error: NFCPaymentError | null;
  clearPayment: () => void;
  clearError: () => void;
}

usePayment()

Low-level hook for direct API calls.

Returns:

{
  createPaymentRequest: (request: CreatePaymentRequest) => Promise<CreatePaymentResponse | null>;
  processPaymentRequest: (request: ProcessPaymentRequest) => Promise<ProcessPaymentResponse | null>;
  isCreating: boolean;
  isProcessing: boolean;
  createdPayment: CreatePaymentResponse | null;
  processedPayment: ProcessPaymentResponse | null;
  error: APIError | null;
  clearError: () => void;
  reset: () => void;
}

usePaymentStatus(options?)

Hook for polling payment status.

Options:

{
  paymentId?: string;      // Payment ID to poll
  pollingInterval?: number; // Polling interval in ms (default: 2000)
  autoStart?: boolean;      // Auto-start polling (default: false)
}

Returns:

{
  startPolling: (paymentId?: string) => void;
  stopPolling: () => void;
  fetchStatus: (paymentId: string) => Promise<PaymentStatusResponse>;
  isPolling: boolean;
  status: PaymentStatusResponse | null;
  isConfirmed: boolean;
  isFailed: boolean;
  txHash?: string;
  confirmedAt?: number;
  error: APIError | null;
  clearError: () => void;
  reset: () => void;
}

Types

interface PaymentRequest {
  paymentId: string;
  amount: string;
  merchantWallet: string;
  transactionId: string;
  currency: 'USDC';
  network: 'base';
  timestamp: number;
  expiresAt?: number;
}

enum PaymentStatus {
  PENDING = 'pending',
  PROCESSING = 'processing',
  CONFIRMED = 'confirmed',
  FAILED = 'failed',
}

class NFCPaymentError extends Error {
  code: NFCErrorCode;
}

enum NFCErrorCode {
  NOT_SUPPORTED = 'NFC_NOT_SUPPORTED',
  NOT_ENABLED = 'NFC_NOT_ENABLED',
  READ_FAILED = 'READ_FAILED',
  WRITE_FAILED = 'WRITE_FAILED',
  INVALID_DATA = 'INVALID_DATA',
  USER_CANCELLED = 'USER_CANCELLED',
  API_ERROR = 'API_ERROR',
  NETWORK_ERROR = 'NETWORK_ERROR',
  TIMEOUT = 'TIMEOUT',
  UNAUTHORIZED = 'UNAUTHORIZED',
}

class APIError extends Error {
  code: APIErrorCode;
  statusCode?: number;
  details?: Record<string, any>;
}

Error Handling

The SDK provides comprehensive error handling:

const { createPaymentRequest, error } = useNFCMerchant();

const handlePayment = async () => {
  const result = await createPaymentRequest({
    amount: '10.50',
    merchantId: 'merchant_123',
  });

  if (error) {
    switch (error.code) {
      case NFCErrorCode.NOT_SUPPORTED:
        Alert.alert('NFC not supported on this device');
        break;
      case NFCErrorCode.NOT_ENABLED:
        Alert.alert('Please enable NFC in device settings');
        break;
      case NFCErrorCode.API_ERROR:
        Alert.alert('Backend API error', error.message);
        break;
      case NFCErrorCode.NETWORK_ERROR:
        Alert.alert('Network error', 'Please check your connection');
        break;
      case NFCErrorCode.UNAUTHORIZED:
        Alert.alert('Invalid API key');
        break;
      default:
        Alert.alert('Error', error.message);
    }
  }
};

Development

Running the Example App

# Install dependencies
yarn bootstrap

# Run the example app
yarn example start

Building

# Type check
yarn typecheck

# Lint
yarn lint

# Build the library
yarn prepack

Requirements

  • React Native 0.60+
  • iOS 13+ / Android 5.0+
  • Device with NFC capability
  • Backend API service with required endpoints

Permissions

iOS

Add to your Info.plist:

<key>NFCReaderUsageDescription</key>
<string>We need access to NFC to process contactless payments</string>

Android

Ensure your app targets minSdkVersion 23 or higher in android/build.gradle:

buildscript {
    ext {
        minSdkVersion = 23
    }
}

Add to your AndroidManifest.xml:

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

<application>
  <!-- Other components -->
  <service 
      android:name="com.taprails.hce.TapRailsHCEService" 
      android:exported="true" 
      android:enabled="true" 
      android:permission="android.permission.BIND_NFC_SERVICE">
      <intent-filter>
          <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE" />
          <category android:name="android.intent.category.DEFAULT"/>
      </intent-filter>
      <meta-data 
          android:name="android.nfc.cardemulation.host_apdu_service" 
          android:resource="@xml/aid_list" />
  </service>
</application>

Then create android/app/src/main/res/xml/aid_list.xml:

<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:description="@string/app_name"
    android:requireDeviceUnlock="true">
    <aid-group android:category="other" android:description="@string/app_name">
        <!-- REPLACE WITH THE UNIQUE AID FROM YOUR DASHBOARD -->
        <aid-filter android:name="YOUR_UNIQUE_AID" />
    </aid-group>
</host-apdu-service>

License

Business Source License (BSL 1.1)

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

Support

For issues and questions, please open an issue on GitHub.