You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

13 KiB

DailyNotification Plugin - Capacitor Integration Guide

Author: Matthew Raymer
Version: 1.0.0
Created: 2025-10-08 06:24:57 UTC

Overview

The DailyNotification plugin is specifically designed for Capacitor-based mobile applications. It provides native mobile functionality that is not available in web-only PWAs. This guide explains when and how to use the plugin in your TimeSafari PWA.

When to Use the Plugin

Use the Plugin When:

  • Capacitor is installed in your TimeSafari PWA project
  • Building for mobile platforms (Android, iOS)
  • Need native mobile features like:
    • Background notifications
    • Native notification scheduling
    • Background task execution
    • Platform-specific notification channels
    • Battery optimization handling
    • Exact alarm permissions

Don't Use the Plugin When:

  • Web-only PWA (no Capacitor)
  • Desktop-only Electron app (though Electron support is available)
  • Server-side rendering (SSR)
  • Static site generation (SSG)

Integration Scenarios

Scenario 1: Web-Only PWA (No Plugin Needed)

// In your web-only TimeSafari PWA
// You continue using your existing code as-is

private async loadNewStarredProjectChanges() {
  if (this.activeDid && this.starredPlanHandleIds.length > 0) {
    try {
      const starredProjectChanges = await getStarredProjectsWithChanges(
        this.axios,
        this.apiServer,
        this.activeDid,
        this.starredPlanHandleIds,
        this.lastAckedStarredPlanChangesJwtId,
      );
      this.numNewStarredProjectChanges = starredProjectChanges.data.length;
      this.newStarredProjectChangesHitLimit = starredProjectChanges.hitLimit;
    } catch (error) {
      console.warn("[HomeView] Failed to load starred project changes:", error);
      this.numNewStarredProjectChanges = 0;
      this.newStarredProjectChangesHitLimit = false;
    }
  }
}

What happens:

  • Your existing code works perfectly in the browser
  • No plugin integration needed
  • No native mobile features (background notifications, etc.)
  • Limited to web browser capabilities
// In your Capacitor-based TimeSafari PWA
import { DailyNotification } from '@timesafari/daily-notification-plugin';
import { Capacitor } from '@capacitor/core';

class TimeSafariHomeView {
  async initialize() {
    // Check if running in Capacitor
    if (Capacitor.isNativePlatform()) {
      // Initialize plugin for native mobile features
      await this.setupDailyNotification();
    } else {
      // Use existing web-only code
      console.log('Running in web browser - using existing code');
    }
  }
  
  async setupDailyNotification() {
    // Only runs on native platforms (Android, iOS)
    await DailyNotification.configure({
      timesafariConfig: {
        activeDid: this.activeDid,
        endpoints: {
          projectsLastUpdated: `${this.apiServer}/api/v2/report/plansLastUpdatedBetween`
        },
        starredProjectsConfig: {
          enabled: true,
          starredPlanHandleIds: this.starredPlanHandleIds,
          lastAckedJwtId: this.lastAckedStarredPlanChangesJwtId,
          fetchInterval: '0 8 * * *'
        }
      },
      networkConfig: {
        httpClient: this.axios,
        baseURL: this.apiServer,
        timeout: 30000
      }
    });
  }
  
  async loadNewStarredProjectChanges() {
    if (Capacitor.isNativePlatform()) {
      // Use plugin-enhanced method on native platforms
      await this.loadNewStarredProjectChangesNative();
    } else {
      // Use existing web method in browser
      await this.loadNewStarredProjectChangesWeb();
    }
  }
  
  async loadNewStarredProjectChangesNative() {
    // Plugin-enhanced method with native features
    const starredProjectChanges = await this.integrationService.getStarredProjectsWithChanges(
      this.activeDid,
      this.starredPlanHandleIds,
      this.lastAckedStarredPlanChangesJwtId
    );
    this.numNewStarredProjectChanges = starredProjectChanges.data.length;
    this.newStarredProjectChangesHitLimit = starredProjectChanges.hitLimit;
  }
  
  async loadNewStarredProjectChangesWeb() {
    // Existing web-only method
    const starredProjectChanges = await getStarredProjectsWithChanges(
      this.axios,
      this.apiServer,
      this.activeDid,
      this.starredPlanHandleIds,
      this.lastAckedStarredPlanChangesJwtId,
    );
    this.numNewStarredProjectChanges = starredProjectChanges.data.length;
    this.newStarredProjectChangesHitLimit = starredProjectChanges.hitLimit;
  }
}

Platform Detection

Check if Capacitor is Available

import { Capacitor } from '@capacitor/core';

// Check if running in Capacitor
if (Capacitor.isNativePlatform()) {
  // Use plugin for native mobile features
  await this.setupDailyNotification();
} else {
  // Use existing web-only code
  console.log('Running in web browser');
}

// Check specific platform
if (Capacitor.getPlatform() === 'android') {
  // Android-specific configuration
} else if (Capacitor.getPlatform() === 'ios') {
  // iOS-specific configuration
} else {
  // Web browser
}

Conditional Plugin Loading

// Only load plugin when needed
let DailyNotification: any = null;
let TimeSafariIntegrationService: any = null;

if (Capacitor.isNativePlatform()) {
  // Dynamically import plugin only on native platforms
  const plugin = await import('@timesafari/daily-notification-plugin');
  DailyNotification = plugin.DailyNotification;
  TimeSafariIntegrationService = plugin.TimeSafariIntegrationService;
}

// Use plugin conditionally
if (DailyNotification) {
  await DailyNotification.configure({...});
} else {
  // Use existing web-only code
}

Capacitor Configuration

1. Install Capacitor (if not already installed)

# Install Capacitor
npm install @capacitor/core @capacitor/cli

# Initialize Capacitor
npx cap init

# Add platforms
npx cap add android
npx cap add ios

2. Configure Capacitor for TimeSafari PWA

// capacitor.config.ts
import { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'app.timesafari',
  appName: 'TimeSafari',
  webDir: 'dist',
  plugins: {
    DailyNotification: {
      // Plugin configuration
      storage: 'tiered',
      ttlSeconds: 1800,
      enableETagSupport: true,
      enableErrorHandling: true,
      enablePerformanceOptimization: true
    }
  }
};

export default config;

3. Build and Sync

# Build your PWA
npm run build

# Sync with Capacitor
npx cap sync

# Open in IDE
npx cap open android
npx cap open ios

Platform-Specific Features

Android Features (Only with Plugin)

// Android-specific features
if (Capacitor.getPlatform() === 'android') {
  // WorkManager for background tasks
  // AlarmManager for exact notifications
  // Notification channels
  // Battery optimization handling
  // Exact alarm permissions
}

iOS Features (Only with Plugin)

// iOS-specific features
if (Capacitor.getPlatform() === 'ios') {
  // BGTaskScheduler for background tasks
  // UNUserNotificationCenter for notifications
  // Background App Refresh
  // Provisional authorization
  // Notification categories
}

Web Features (Existing Code)

// Web browser features
if (!Capacitor.isNativePlatform()) {
  // Service Worker (if implemented)
  // Web Notifications API
  // Local Storage
  // IndexedDB
  // Your existing web-only code
}

Integration Strategy

1. Progressive Enhancement

class TimeSafariHomeView {
  async initialize() {
    // Always initialize with existing web code
    await this.initializeWeb();
    
    // Enhance with plugin if on native platform
    if (Capacitor.isNativePlatform()) {
      await this.initializeNative();
    }
  }
  
  async initializeWeb() {
    // Your existing web-only initialization
    console.log('Initialized web version');
  }
  
  async initializeNative() {
    // Plugin-enhanced initialization
    await this.setupDailyNotification();
    console.log('Initialized native version with plugin');
  }
}

2. Feature Detection

class TimeSafariHomeView {
  private isNative = Capacitor.isNativePlatform();
  private hasPlugin = false;
  
  async initialize() {
    if (this.isNative) {
      try {
        await this.setupDailyNotification();
        this.hasPlugin = true;
        console.log('Plugin initialized successfully');
      } catch (error) {
        console.warn('Plugin initialization failed, falling back to web mode');
        this.hasPlugin = false;
      }
    }
  }
  
  async loadNewStarredProjectChanges() {
    if (this.hasPlugin) {
      // Use plugin-enhanced method
      await this.loadNewStarredProjectChangesNative();
    } else {
      // Use existing web method
      await this.loadNewStarredProjectChangesWeb();
    }
  }
}

3. Graceful Degradation

class TimeSafariHomeView {
  async loadNewStarredProjectChanges() {
    try {
      if (this.hasPlugin) {
        // Try plugin-enhanced method first
        await this.loadNewStarredProjectChangesNative();
      } else {
        // Fall back to web method
        await this.loadNewStarredProjectChangesWeb();
      }
    } catch (error) {
      // If plugin fails, fall back to web method
      console.warn('Plugin method failed, falling back to web method');
      await this.loadNewStarredProjectChangesWeb();
    }
  }
}

Build Configuration

1. Package.json Scripts

{
  "scripts": {
    "build": "vite build",
    "build:web": "vite build",
    "build:android": "vite build && npx cap sync android",
    "build:ios": "vite build && npx cap sync ios",
    "dev:web": "vite",
    "dev:android": "vite && npx cap run android",
    "dev:ios": "vite && npx cap run ios"
  }
}

2. Environment Variables

# .env
VITE_CAPACITOR_ENABLED=true
VITE_PLUGIN_ENABLED=true

# .env.web (web-only build)
VITE_CAPACITOR_ENABLED=false
VITE_PLUGIN_ENABLED=false

3. Conditional Imports

// Only import plugin when needed
const loadPlugin = async () => {
  if (import.meta.env.VITE_PLUGIN_ENABLED === 'true') {
    return await import('@timesafari/daily-notification-plugin');
  }
  return null;
};

const plugin = await loadPlugin();
if (plugin) {
  await plugin.DailyNotification.configure({...});
}

Testing Strategy

1. Web Testing

# Test web-only version
npm run dev:web
# Test in browser - should use existing code

2. Native Testing

# Test Android version
npm run dev:android
# Test on Android device/emulator - should use plugin

# Test iOS version
npm run dev:ios
# Test on iOS device/simulator - should use plugin

3. Cross-Platform Testing

// Test both implementations
const testBothImplementations = async () => {
  // Test web implementation
  const webResult = await this.loadNewStarredProjectChangesWeb();
  
  // Test native implementation (if available)
  if (this.hasPlugin) {
    const nativeResult = await this.loadNewStarredProjectChangesNative();
    
    // Compare results
    console.log('Web result:', webResult);
    console.log('Native result:', nativeResult);
  }
};

Common Questions

Q: Do I need to install the plugin for web-only PWAs?

A: No, the plugin is only needed for Capacitor-based mobile apps. Web-only PWAs continue using your existing code.

Q: What happens if I install the plugin but don't use Capacitor?

A: The plugin will not work in web browsers. You should use platform detection to only initialize the plugin on native platforms.

Q: Can I use the plugin in Electron?

A: Yes, the plugin supports Electron, but you need to configure it specifically for Electron.

Q: How do I handle different platforms?

A: Use Capacitor.getPlatform() to detect the platform and configure the plugin accordingly.

Q: What if the plugin fails to initialize?

A: Implement graceful degradation to fall back to your existing web-only code.

Conclusion

The DailyNotification plugin is only needed when using Capacitor for mobile app development. For web-only PWAs, you continue using your existing TimeSafari code. The plugin provides native mobile features like background notifications, exact alarm scheduling, and platform-specific optimizations that are not available in web browsers.

Key Points:

  • Use plugin with Capacitor for mobile apps (Android, iOS)
  • Don't use plugin for web-only PWAs
  • 🔄 Use platform detection to conditionally load the plugin
  • 🛡️ Implement graceful degradation to fall back to web code
  • 🧪 Test both implementations to ensure compatibility

Next Steps:

  1. Check if your TimeSafari PWA uses Capacitor
  2. If yes, integrate the plugin with platform detection
  3. If no, continue using your existing web-only code
  4. Test both web and native implementations