0.1.3 • Published 2 months ago

capsule-native v0.1.3

Weekly downloads
-
License
MIT AND Commons C...
Repository
github
Last release
2 months ago

@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/native

Additional Setup Required

  1. 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>
  1. 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

  1. Biometric Authentication

    • Uses the device's secure hardware (TouchID/FaceID on iOS, Fingerprint/Face Unlock on Android)
    • Credentials never leave the secure hardware
  2. Storage

    • Sensitive data is stored using the platform's secure storage mechanisms
    • Consider encrypting sensitive data before storage
  3. Permissions

    • All features request permissions at runtime
    • Users can revoke permissions at any time through system settings

Performance Considerations

  1. Camera

    • Initialize camera only when needed
    • Release camera resources when not in use
  2. Geolocation

    • Consider battery impact of continuous location tracking
    • Use appropriate accuracy settings based on needs
  3. Network Monitoring

    • Unsubscribe from network changes when no longer needed
    • Use unsubscribe() function returned by subscribeToNetworkChanges
  4. 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.