0.1.3 • Published 8 months ago
capsule-native v0.1.3
@capsule/native
This package provides production-ready native functionality for React Native applications built with Capsule.
Features
- 📸 Camera API - Take photos and record videos
- 🔐 Biometric Authentication - Secure your app with fingerprint, face recognition, or other biometric methods
- 🔔 Push Notifications - Send and receive push notifications
- 💾 Offline Storage - Store data securely on the device
- 📍 Geolocation - Access the device's location
- 📱 NFC - Read from and write to NFC tags
- 📁 File System Access - Read and write files on the device
- 🌐 Network Connectivity Monitoring - Monitor network status and changes
Installation
npm install @capsule/nativeAdditional Setup Required
- iOS: Add the following to your Info.plist:
<key>NSCameraUsageDescription</key>
<string>We need access to your camera for...</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>We need access to your location for...</string>
<key>NSFaceIDUsageDescription</key>
<string>We need access to Face ID for secure authentication</string>
<key>NFCReaderUsageDescription</key>
<string>We need access to NFC for...</string>- Android: Add the following permissions to your AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.NFC" />Basic Usage
import { NativeFeatures } from '@capsule/native';
// Initialize with default configuration
const native = new NativeFeatures();
// Or initialize with custom configuration
const native = new NativeFeatures({
  featureToggles: {
    camera: true,
    biometricAuth: true,
    nfc: true
  }
});Feature Usage
📸 Camera API
// Initialize camera
const camera = await native.initializeCamera({
  quality: 'high',
  flash: 'auto'
});
// Take a photo
try {
  const photo = await native.takePhoto({
    quality: 'high',
    flash: 'auto'
  });
  console.log('Photo taken:', photo.uri);
} catch (error) {
  console.error('Failed to take photo:', error);
}
// Record video
try {
  await native.startVideoRecording();
  
  // Later...
  const video = await native.stopVideoRecording();
  console.log('Video saved at:', video.path);
} catch (error) {
  console.error('Video recording error:', error);
}🔐 Biometric Authentication
// Check if biometrics are available
const { available, biometryType } = await native.isBiometricAvailable();
if (available) {
  try {
    // Authenticate user
    const result = await native.authenticateWithBiometrics(
      'Verify your identity',
      {
        cancelButtonText: 'Cancel',
        fallbackPromptMessage: 'Please use your device passcode'
      }
    );
    
    if (result.success) {
      // User authenticated successfully
      console.log('Authentication successful');
    }
  } catch (error) {
    if (error.code === 'permission_denied') {
      console.error('Biometric permission denied');
    } else {
      console.error('Authentication failed:', error);
    }
  }
}🔔 Push Notifications
// Initialize notifications
try {
  await native.initializeNotifications();
  
  // Request permission
  const permission = await native.requestNotificationPermission();
  
  if (permission === 'granted') {
    // Register for push notifications
    const token = await native.registerForPushNotifications();
    console.log('Push token:', token);
    
    // Send to your backend
    await sendTokenToBackend(token);
  }
  
  // Send a local notification
  await native.sendLocalNotification({
    title: 'Hello',
    body: 'This is a local notification',
    data: { screen: 'home' }
  });
  
  // Listen for notifications
  const unsubscribe = native.onNotificationReceived((notification) => {
    console.log('Received notification:', notification);
  });
  
  // Later, when no longer needed
  unsubscribe();
} catch (error) {
  console.error('Notification error:', error);
}💾 Offline Storage
// Store data
try {
  await native.storeData('user-profile', {
    id: 123,
    name: 'John Doe',
    preferences: { theme: 'dark' }
  });
  
  // Retrieve data
  const userData = await native.getData('user-profile');
  
  // Remove data
  await native.removeData('user-profile');
  
  // Check if data exists
  const exists = await native.hasData('user-profile');
} catch (error) {
  console.error('Storage error:', error);
}📍 Geolocation
// Get current position
try {
  const position = await native.getCurrentPosition({
    enableHighAccuracy: true,
    timeout: 15000
  });
  
  console.log(
    `Latitude: ${position.coords.latitude}, ` +
    `Longitude: ${position.coords.longitude}`
  );
} catch (error) {
  console.error('Location error:', error);
}
// Watch position changes
const watchId = native.watchPosition(
  (position) => {
    console.log('Position updated:', position);
  },
  (error) => {
    console.error('Watch position error:', error);
  },
  { 
    enableHighAccuracy: true,
    distanceFilter: 10 // minimum distance in meters
  }
);
// Stop watching
native.clearWatch(watchId);📱 NFC (Near Field Communication)
// Check if NFC is supported
const isSupported = await native.isNfcSupported();
if (isSupported) {
  try {
    // Initialize NFC
    await native.initializeNfc();
    
    // Read an NFC tag
    const tag = await native.readNfcTag({
      alertMessage: 'Hold your device near an NFC tag',
      invalidateAfterFirstRead: true
    });
    
    console.log('Tag ID:', tag.id);
    console.log('Tag type:', tag.type);
    
    if (tag.data) {
      // Process tag data
      tag.data.records.forEach(record => {
        console.log('Record type:', record.recordType);
        console.log('Payload:', record.payload);
      });
    }
    
    // Write to an NFC tag
    const success = await native.writeNfcTag(
      [
        // Text record
        {
          recordType: 'text',
          payload: 'Hello from Capsule!'
        },
        // URI record
        {
          recordType: 'uri',
          payload: 'https://example.com'
        },
        // Custom MIME data
        {
          recordType: 'mime',
          mimeType: 'application/json',
          payload: JSON.stringify({ id: 123, name: 'Product' })
        }
      ],
      {
        alertMessage: 'Hold your device near an NFC tag to write',
        formatReadOnly: false
      }
    );
    
    if (success) {
      console.log('Successfully wrote to NFC tag');
    }
    
    // Stop NFC when done
    await native.stopNfc();
  } catch (error) {
    console.error('NFC error:', error);
  }
}📁 File System Access
try {
  // Write a file
  await native.writeFile('documents/note.txt', 'Hello, World!', {
    encoding: 'utf8'
  });
  
  // Read a file
  const content = await native.readFile('documents/note.txt');
  
  // Check if file exists
  const exists = await native.fileExists('documents/note.txt');
  
  // Delete a file
  await native.deleteFile('documents/note.txt');
  
  // List directory contents
  const files = await native.listDirectory('documents');
} catch (error) {
  console.error('File system error:', error);
}🌐 Network Connectivity
try {
  // Check current network status
  const networkStatus = await native.checkNetworkStatus();
  console.log('Connected:', networkStatus.isConnected);
  console.log('Connection type:', networkStatus.type); // 'wifi', 'cellular', etc.
  
  // Subscribe to network changes
  const unsubscribe = native.subscribeToNetworkChanges((status) => {
    console.log('Network status changed:', status);
  });
  
  // Later, when no longer needed
  unsubscribe();
} catch (error) {
  console.error('Network error:', error);
}Permissions
Most native features require user permissions. The bridge handles permission requests automatically, but you can also request them explicitly:
// Request camera permission
const cameraPermission = await native.requestPermission('camera');
// Request location permission
const locationPermission = await native.requestPermission('location');
// Request NFC permission (Android only)
const nfcPermission = await native.requestPermission('nfc');
// Check permission status
const notificationStatus = await native.checkPermission('notifications');Error Handling
All methods throw descriptive errors with error codes when permissions are denied or operations fail. Always wrap calls in try-catch blocks:
try {
  await native.initializeCamera();
} catch (error) {
  if (error.code === 'permission_denied') {
    // Handle permission denial
    console.error('Camera permission denied');
  } else if (error.code === 'device_unavailable') {
    // Handle device unavailability
    console.error('Camera not available on this device');
  } else {
    // Handle other errors
    console.error('Camera initialization failed:', error);
  }
}Available error codes:
- permission_denied- User denied permission
- device_unavailable- Device doesn't have the required hardware
- feature_unsupported- Feature is not supported on this platform
- initialization_failed- Failed to initialize the feature
- operation_failed- Operation failed
- invalid_parameter- Invalid parameter provided
- timeout- Operation timed out
- network_error- Network-related error
- unknown_error- Unknown error
Configuration
The native feature bridge can be configured using the Capsule configuration system:
import { NativeFeatures } from '@capsule/native';
// Initialize with custom configuration
const native = new NativeFeatures({
  featureToggles: {
    camera: true,
    biometricAuth: true,
    nfc: false,
    pushNotifications: true,
    geolocation: true,
    fileSystem: true,
    networkMonitoring: true,
    localStorage: true
  },
  appSettings: {
    // App-specific settings
  }
});
// Check if a feature is enabled
if (native.isFeatureEnabled('camera')) {
  // Camera is enabled
}Security Considerations
- Biometric Authentication - Uses the device's secure hardware (TouchID/FaceID on iOS, Fingerprint/Face Unlock on Android)
- Credentials never leave the secure hardware
 
- Storage - Sensitive data is stored using the platform's secure storage mechanisms
- Consider encrypting sensitive data before storage
 
- Permissions - All features request permissions at runtime
- Users can revoke permissions at any time through system settings
 
Performance Considerations
- Camera - Initialize camera only when needed
- Release camera resources when not in use
 
- Geolocation - Consider battery impact of continuous location tracking
- Use appropriate accuracy settings based on needs
 
- Network Monitoring - Unsubscribe from network changes when no longer needed
- Use unsubscribe()function returned bysubscribeToNetworkChanges
 
- NFC - Stop NFC scanning when not in use to save battery
- Use stopNfc()when done with NFC operations
 
Platform-Specific Considerations
NFC Platform Considerations
- iOS: NFC reading is supported on iPhone 7 and newer running iOS 11+. NFC writing requires iOS 13+. Background NFC scanning is only available on iOS 13+.
- Android: Most Android devices with NFC hardware support both reading and writing. Background scanning is supported.
- Web: NFC is supported via the Web NFC API, but only in Chrome for Android (version 89+) and with limited functionality.
Contributing
Please read CONTRIBUTING.md for details on our code of conduct and the process for submitting pull requests.