SwahiliNFC
A comprehensive Flutter package for NFC business card applications with a focus on secure contact exchange.
Overview
SwahiliNFC simplifies NFC operations for business card applications, abstracting the complexities of NFC communication while providing robust security features and an intuitive API.
Originally developed for SwahiliCard, this package helps developers quickly implement NFC functionality without the need to understand the underlying NFC protocols and security implementations.

Key Features
- Simplified Tag Operations: One-line tag reading with automatic format detection
- Advanced Security Model: Multiple protection levels from open access to encrypted data with digital signatures
- Business Card Data Format: Standardized format specifically for contact exchange
- Multi-Device Management: Support for different NFC form factors (cards, tags, wristbands)
- Analytics & Insights: Built-in support for scan analytics
- Offline Capabilities: Cache contacts for offline exchange
Installation
Add SwahiliNFC to your pubspec.yaml
:
dependencies:
swahili_nfc: ^0.1.15
Platform Setup
Android
Add the following permissions to your AndroidManifest.xml
:
<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
:
<key>NFCReaderUsageDescription</key>
<string>This app uses NFC to read and write business cards</string>
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
<string>NDEF</string>
<string>TAG</string>
</array>
You'll also need to enable the NFC capabilities in your app's entitlements.
Basic Usage
Reading an NFC Card
// Check if NFC is available
final isAvailable = await SwahiliNFC.isAvailable();
if (!isAvailable) {
print('NFC is not available on this device');
return;
}
// Read a card
try {
final cardData = await SwahiliNFC.readTag();
print('Card read successfully: ${cardData.name}');
} catch (e) {
print('Error reading card: $e');
}
Writing an NFC Card
// Write operation with verification
final success = await SwahiliNFC.writeTag(
data: BusinessCardData(
name: "John Doe",
company: "SwahiliTech",
phone: "+25571234567",
email: "john@example.com",
social: {
"linkedin": "johndoe",
"twitter": "@johndoe",
},
custom: {
"position": "Software Engineer",
"website": "example.com",
},
),
verifyAfterWrite: true,
);
Background Scanning
// Continuous background reading
SwahiliNFC.startBackgroundScan(
onTagDetected: (CardData data) {
// Process the data
print('Card detected: ${data.name}');
},
scanDuration: Duration(minutes: 5),
);
Advanced Features
Security Levels
SwahiliNFC offers four security levels for your NFC cards:
-
Open (
SecurityLevel.open
):- Standard NDEF records, readable by any NFC reader
- No authentication required
- Great for public information sharing
-
Basic (
SecurityLevel.basic
):- Password-protected with simple PIN/password
- Lightweight security for semi-private information
-
Enhanced (
SecurityLevel.enhanced
):- Encrypted data with app-specific decryption
- Strong protection for sensitive information
-
Premium (
SecurityLevel.premium
):- Digital signatures and authentication tokens
- Tamper detection to prevent modification
- Highest level of security for critical data
Applying Security
// Applying security to a card
await SwahiliNFC.setCardSecurity(
securityLevel: SecurityLevel.enhanced,
credentials: SecurityCredentials(
password: "1234",
encryptionKey: SwahiliNFC.generateRandomKey(),
expiration: DateTime.now().add(Duration(days: 365)),
),
);
Reading Protected Cards
// Reading a protected card
final cardData = await SwahiliNFC.readProtectedTag(
credentials: SecurityCredentials(
password: "1234",
),
onAuthenticationError: (error) {
// Handle authentication failure
print('Authentication error: $error');
},
);
Card Management
// List all active cards
final activeCards = await SwahiliNFC.getActiveCards();
// Deactivate a specific card
await SwahiliNFC.deactivateCard(cardId: "abc123");
// Activate a new card
final newCardId = await SwahiliNFC.activateNewCard(
deviceType: NFCDeviceType.card,
deviceName: "Metal Business Card",
);
Analytics
// Enable scan analytics
SwahiliNFC.enableAnalytics(
analyticsConfig: AnalyticsConfig(
collectLocationData: false,
collectDeviceInfo: true,
collectTimestamps: true,
),
);
// Get scan history for a card
final scanHistory = await SwahiliNFC.getCardScanHistory(
cardId: "abc123",
);
Offline Mode
// Enable offline mode
SwahiliNFC.enableOfflineMode(
cacheSize: 100, // Maximum number of contacts to store offline
syncWhenOnline: true,
);
// Force sync when back online
await SwahiliNFC.syncOfflineData();
SwahiliCard Integration
// SwahiliCard specific configuration
SwahiliNFC.configureForSwahiliCard(
baseUrl: "https://me.swahilicard.com/",
apiKey: "your_api_key", // Optional
);
// Generate SwahiliCard compatible URL
final cardUrl = SwahiliNFC.generateCardUrl(
userId: "user123",
cardId: "card456",
isSecure: true,
);
Complete Example: Card Activation Flow
Future<void> activateNewCard() async {
// 1. Check NFC availability
final isAvailable = await SwahiliNFC.isAvailable();
if (!isAvailable) {
showError('NFC not available on this device');
return;
}
// 2. Get user profile
final userProfile = await getUserProfile();
// 3. Prepare business card data
final cardData = BusinessCardData(
name: userProfile.name,
company: userProfile.company,
position: userProfile.position,
email: userProfile.email,
phone: userProfile.phone,
social: userProfile.socialLinks,
profileImage: userProfile.profileImageBytes,
);
// 4. Configure security
final securityOptions = SecurityOptions(
level: SecurityLevel.enhanced,
password: generatePassword(),
expiry: DateTime.now().add(Duration(days: 365)),
);
// 5. Start the writing process
SwahiliNFC.startCardActivation(
cardData: cardData,
security: securityOptions,
deviceType: NFCDeviceType.card,
// 6. Event callbacks
onActivationStarted: () {
showProgress('Please hold your card near the device');
},
onProgress: (progress) {
updateProgressBar(progress);
},
onActivationComplete: (cardId) {
showSuccess('Card activated successfully');
// 7. Register card with backend
registerCardWithBackend(cardId);
},
onError: (error) {
showError('Activation failed: ${error.message}');
},
);
}
Advanced Use Cases
Working with Multiple Security Levels
If your application needs to support different security levels based on user needs:
enum CardUserType { public, staff, admin }
SecurityLevel getSecurityLevelForUser(CardUserType userType) {
switch (userType) {
case CardUserType.public:
return SecurityLevel.open;
case CardUserType.staff:
return SecurityLevel.basic;
case CardUserType.admin:
return SecurityLevel.premium;
default:
return SecurityLevel.open;
}
}
void createCardForUser(String name, CardUserType userType) async {
// Create card data
final cardData = BusinessCardData(
name: name,
// Other fields...
);
// Get appropriate security level
final securityLevel = getSecurityLevelForUser(userType);
// Configure security based on level
SecurityCredentials credentials;
switch (securityLevel) {
case SecurityLevel.open:
credentials = SecurityCredentials();
break;
case SecurityLevel.basic:
credentials = SecurityCredentials(
password: generateSimplePassword(),
);
break;
case SecurityLevel.enhanced:
case SecurityLevel.premium:
final encryptionKey = SwahiliNFC.generateRandomKey();
credentials = SecurityCredentials(
password: generateSimplePassword(),
encryptionKey: encryptionKey,
expiration: DateTime.now().add(Duration(days: 365)),
);
// Store encryption key securely for later use
await storeEncryptionKey(encryptionKey);
break;
}
// Set security
await SwahiliNFC.setCardSecurity(
securityLevel: securityLevel,
credentials: credentials,
);
// Write card
await SwahiliNFC.writeTag(data: cardData);
}
Event Registration System
For creating an NFC-based event registration system:
class EventAttendee {
final String name;
final String email;
final String ticketId;
final bool isVIP;
EventAttendee({
required this.name,
required this.email,
required this.ticketId,
this.isVIP = false,
});
// Convert to BusinessCardData for NFC writing
BusinessCardData toBusinessCardData() {
return BusinessCardData(
name: name,
email: email,
custom: {
'ticketId': ticketId,
'isVIP': isVIP.toString(),
'eventName': 'Tech Conference 2024',
},
cardType: CardType.event,
isTemporary: true,
);
}
// Create from BusinessCardData when reading NFC
static EventAttendee fromBusinessCardData(BusinessCardData data) {
return EventAttendee(
name: data.name,
email: data.email ?? '',
ticketId: data.custom['ticketId'] ?? '',
isVIP: data.custom['isVIP'] == 'true',
);
}
}
// Register attendee and write to their NFC badge
Future<void> registerAttendee(EventAttendee attendee) async {
// Convert to business card format
final cardData = attendee.toBusinessCardData();
// Write to NFC badge
await SwahiliNFC.writeTag(
data: cardData,
verifyAfterWrite: true,
);
// Track attendance with analytics
SwahiliNFC.enableAnalytics(
analyticsConfig: AnalyticsConfig(
collectTimestamps: true,
collectDeviceInfo: false,
),
);
}
// Check in attendee by scanning their badge
Future<void> checkInAttendee() async {
try {
// Read NFC badge
final cardData = await SwahiliNFC.readTag();
// Convert to attendee
final attendee = EventAttendee.fromBusinessCardData(cardData);
// Register check-in
await recordAttendeeCheckIn(attendee);
// Show confirmation
showMessage('Welcome, ${attendee.name}!');
if (attendee.isVIP) {
showMessage('VIP access granted!');
}
} catch (e) {
showError('Failed to check in: $e');
}
}
Error Handling
SwahiliNFC provides detailed error codes and messages to help you troubleshoot issues:
try {
await SwahiliNFC.readTag();
} catch (e) {
if (e is NFCError) {
// Access error details
print('Error code: ${e.code}');
print('Error message: ${e.message}');
print('User-friendly message: ${e.userMessage}');
// Get troubleshooting tips
for (final tip in e.troubleshootingTips) {
print('Tip: $tip');
}
}
}
Documentation
For full documentation, please see:
Security Implementation Details
Data Protection
- AES-256 encryption for sensitive data
- Secure storage of encryption keys
- Key rotation policies
- Tamper detection mechanisms
Authentication Methods
- PIN/Password authentication
- App-based authentication
- Biometric authentication (where available)
- Time-based one-time passwords (TOTP)
Anti-Cloning Features
- Unique device signatures
- Rate limiting on authentications
- Anomaly detection for suspicious scan patterns
Cross-Platform Considerations
Android
- Handles different NFC formats (NDEF, ISO-DEP, NfcA, etc.)
- Manages Android's Foreground Dispatch system
- Supports Android Beam for older devices
iOS
- Works with CoreNFC
- Handles limited iOS NFC capabilities
- Manages iOS-specific permission prompts
- Provides alternative solutions for older iOS devices
Commercial Applications
Beyond the open-source core, SwahiliNFC supports commercial applications:
- Enterprise security features
- White-labeling capabilities
- Analytics dashboard integration
- High-volume card provisioning
- Custom hardware integrations
License
This project is licensed under the MIT License - see the LICENSE file for details.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.