feat: implement core notification functionality for iOS and Android - Add settings management, proper error handling, and platform-specific implementations
This commit is contained in:
537
README.md
537
README.md
@@ -1,510 +1,143 @@
|
|||||||
# Daily Notification Plugin for Capacitor
|
# Daily Notification Plugin for Capacitor
|
||||||
|
|
||||||
A powerful Capacitor plugin for scheduling and managing daily notifications with advanced features like timezone support, offline capabilities, and retry logic.
|
A Capacitor plugin for scheduling and managing daily notifications with advanced features and robust error handling.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Schedule daily notifications at specific times
|
- Schedule daily notifications with custom time and content
|
||||||
- Support for multiple notification schedules
|
- Support for different priority levels
|
||||||
- Timezone-aware scheduling
|
- Timezone-aware scheduling
|
||||||
- Offline support with content caching
|
- Offline support with caching
|
||||||
- Retry logic with exponential backoff
|
- Comprehensive permission handling
|
||||||
- Custom notification content handlers
|
- Automatic retry logic
|
||||||
- Event-based notification handling
|
- Detailed notification status tracking
|
||||||
- Comprehensive settings management
|
- Configurable settings management
|
||||||
- TypeScript support with full type definitions
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm install @timesafari/daily-notification-plugin
|
npm install daily-notification-plugin
|
||||||
|
npx cap sync
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## iOS Setup
|
||||||
|
|
||||||
|
No additional setup required for iOS. The plugin automatically handles all necessary configurations.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### Basic Usage
|
### Basic Usage
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { DailyNotification } from '@timesafari/daily-notification-plugin';
|
import { DailyNotification } from 'daily-notification-plugin';
|
||||||
|
|
||||||
const plugin = new DailyNotification();
|
|
||||||
|
|
||||||
// Schedule a daily notification
|
// Schedule a daily notification
|
||||||
await plugin.scheduleDailyNotification({
|
await DailyNotification.scheduleDailyNotification({
|
||||||
url: 'https://api.example.com/updates',
|
url: 'https://api.example.com/updates',
|
||||||
time: '09:00',
|
time: '09:00',
|
||||||
title: 'Daily Update',
|
title: 'Daily Update',
|
||||||
body: 'Your daily content is ready!',
|
body: 'Your daily update is ready'
|
||||||
sound: true,
|
|
||||||
priority: 'high'
|
|
||||||
});
|
|
||||||
|
|
||||||
// Get notification status
|
|
||||||
const status = await plugin.getNotificationStatus();
|
|
||||||
console.log('Next notification:', status.nextNotificationTime);
|
|
||||||
|
|
||||||
// Handle notification events
|
|
||||||
plugin.on('notification', (event) => {
|
|
||||||
console.log('Notification received:', event.detail);
|
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### Advanced Usage
|
### Advanced Features
|
||||||
|
|
||||||
|
#### Custom Priority
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Multiple schedules with different timezones
|
await DailyNotification.scheduleDailyNotification({
|
||||||
const schedules = [
|
|
||||||
{
|
|
||||||
url: 'https://api.example.com/morning',
|
|
||||||
time: '09:00',
|
|
||||||
timezone: 'America/New_York',
|
|
||||||
title: 'Morning Update'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url: 'https://api.example.com/evening',
|
|
||||||
time: '18:00',
|
|
||||||
timezone: 'Europe/London',
|
|
||||||
title: 'Evening Update'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const schedule of schedules) {
|
|
||||||
await plugin.scheduleDailyNotification(schedule);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Offline support with caching
|
|
||||||
await plugin.scheduleDailyNotification({
|
|
||||||
url: 'https://api.example.com/updates',
|
url: 'https://api.example.com/updates',
|
||||||
time: '10:00',
|
time: '09:00',
|
||||||
offlineFallback: true,
|
priority: 'high'
|
||||||
cacheDuration: 3600, // 1 hour
|
|
||||||
contentHandler: async (response) => {
|
|
||||||
const data = await response.json();
|
|
||||||
return {
|
|
||||||
title: data.title,
|
|
||||||
body: data.content,
|
|
||||||
data: data.metadata
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update settings
|
|
||||||
await plugin.updateSettings({
|
|
||||||
time: '11:00',
|
|
||||||
sound: true,
|
|
||||||
priority: 'high',
|
|
||||||
timezone: 'America/Chicago'
|
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
## API Reference
|
#### Timezone Support
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
await DailyNotification.scheduleDailyNotification({
|
||||||
|
url: 'https://api.example.com/updates',
|
||||||
|
time: '09:00',
|
||||||
|
timezone: 'America/New_York'
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Check Notification Status
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const status = await DailyNotification.getNotificationStatus();
|
||||||
|
console.log('Notification status:', status);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Update Settings
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
await DailyNotification.updateSettings({
|
||||||
|
sound: true,
|
||||||
|
priority: 'high',
|
||||||
|
timezone: 'America/Los_Angeles'
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Documentation
|
||||||
|
|
||||||
### Methods
|
### Methods
|
||||||
|
|
||||||
#### `scheduleDailyNotification(options: NotificationOptions): Promise<void>`
|
#### scheduleDailyNotification(options: ScheduleOptions)
|
||||||
|
Schedule a new daily notification.
|
||||||
|
|
||||||
Schedules a daily notification with the specified options.
|
#### getLastNotification()
|
||||||
|
Get information about the last delivered notification.
|
||||||
|
|
||||||
|
#### cancelAllNotifications()
|
||||||
|
Cancel all pending notifications.
|
||||||
|
|
||||||
|
#### getNotificationStatus()
|
||||||
|
Get current notification status and settings.
|
||||||
|
|
||||||
|
#### updateSettings(settings: NotificationSettings)
|
||||||
|
Update notification settings.
|
||||||
|
|
||||||
|
#### checkPermissions()
|
||||||
|
Check current notification permissions.
|
||||||
|
|
||||||
|
#### requestPermissions()
|
||||||
|
Request notification permissions.
|
||||||
|
|
||||||
|
### Types
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
interface NotificationOptions {
|
interface ScheduleOptions {
|
||||||
url: string;
|
url: string;
|
||||||
time: string; // "HH:mm" format
|
time: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
body?: string;
|
body?: string;
|
||||||
sound?: boolean;
|
sound?: boolean;
|
||||||
vibrate?: boolean;
|
priority?: 'high' | 'default' | 'low';
|
||||||
priority?: 'low' | 'normal' | 'high';
|
|
||||||
retryCount?: number;
|
|
||||||
retryInterval?: number;
|
|
||||||
cacheDuration?: number;
|
|
||||||
headers?: Record<string, string>;
|
|
||||||
offlineFallback?: boolean;
|
|
||||||
timezone?: string;
|
timezone?: string;
|
||||||
contentHandler?: (response: Response) => Promise<{
|
|
||||||
title: string;
|
|
||||||
body: string;
|
|
||||||
data?: any;
|
|
||||||
}>;
|
|
||||||
}
|
}
|
||||||
```
|
|
||||||
|
|
||||||
#### `getLastNotification(): Promise<NotificationResponse | null>`
|
|
||||||
|
|
||||||
Retrieves the last notification that was delivered.
|
|
||||||
|
|
||||||
#### `cancelAllNotifications(): Promise<void>`
|
|
||||||
|
|
||||||
Cancels all scheduled notifications.
|
|
||||||
|
|
||||||
#### `getNotificationStatus(): Promise<NotificationStatus>`
|
|
||||||
|
|
||||||
Gets the current status of notifications.
|
|
||||||
|
|
||||||
#### `updateSettings(settings: NotificationSettings): Promise<void>`
|
|
||||||
|
|
||||||
Updates notification settings.
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
interface NotificationSettings {
|
interface NotificationSettings {
|
||||||
time?: string;
|
|
||||||
sound?: boolean;
|
sound?: boolean;
|
||||||
vibrate?: boolean;
|
priority?: string;
|
||||||
priority?: 'low' | 'normal' | 'high';
|
|
||||||
timezone?: string;
|
timezone?: string;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Events
|
|
||||||
|
|
||||||
The plugin emits the following events:
|
|
||||||
|
|
||||||
- `notification`: Fired when a notification is received or interacted with
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
interface NotificationEvent extends Event {
|
|
||||||
detail: {
|
|
||||||
id: string;
|
|
||||||
action: string;
|
|
||||||
data?: any;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
The plugin includes comprehensive tests covering:
|
|
||||||
|
|
||||||
- Basic functionality
|
|
||||||
- Multiple schedules
|
|
||||||
- Timezone handling
|
|
||||||
- Offline support
|
|
||||||
- Retry logic
|
|
||||||
- Event handling
|
|
||||||
- Settings management
|
|
||||||
|
|
||||||
Run tests with:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm test
|
|
||||||
```
|
|
||||||
|
|
||||||
## Security Considerations
|
|
||||||
|
|
||||||
- All network requests use HTTPS
|
|
||||||
- Content is validated before display
|
|
||||||
- Sensitive data is not stored in logs
|
|
||||||
- Permissions are properly managed
|
|
||||||
- Input validation is performed on all methods
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
1. Fork the repository
|
|
||||||
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
||||||
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
||||||
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
||||||
5. Open a Pull Request
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
||||||
|
|
||||||
## Author
|
|
||||||
|
|
||||||
Matthew Raymer
|
|
||||||
|
|
||||||
## Platform-Specific Implementation
|
|
||||||
|
|
||||||
### Android Implementation
|
|
||||||
|
|
||||||
- Uses `WorkManager` for periodic data fetching
|
|
||||||
- Implements `AlarmManager` for precise notification scheduling
|
|
||||||
- Stores data in `SharedPreferences`
|
|
||||||
- Handles Doze mode and battery optimizations
|
|
||||||
|
|
||||||
### iOS
|
|
||||||
|
|
||||||
- Utilizes `BGTaskScheduler` for background fetches
|
|
||||||
- Implements `UNUserNotificationCenter` for notifications
|
|
||||||
- Stores data in `UserDefaults`
|
|
||||||
- Respects system background execution limits
|
|
||||||
|
|
||||||
## Permissions
|
|
||||||
|
|
||||||
### Android Permissions
|
|
||||||
|
|
||||||
Required permissions in `AndroidManifest.xml`:
|
|
||||||
|
|
||||||
```xml
|
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
|
||||||
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
|
|
||||||
```
|
|
||||||
|
|
||||||
### iOS Implementation
|
|
||||||
|
|
||||||
- Notification permissions (requested at runtime)
|
|
||||||
- Background App Refresh capability (enabled in Xcode)
|
|
||||||
|
|
||||||
## Error Handling
|
## Error Handling
|
||||||
|
|
||||||
The plugin implements comprehensive error handling:
|
The plugin provides detailed error messages for various scenarios:
|
||||||
|
- Invalid parameters
|
||||||
- Network failure retry logic with exponential backoff
|
- Permission issues
|
||||||
- Fallback to cached content when fetching fails
|
- Scheduling failures
|
||||||
- Detailed error logging and reporting
|
- Invalid time formats
|
||||||
- Graceful degradation when permissions are denied
|
- Invalid timezone identifiers
|
||||||
|
- Invalid priority values
|
||||||
## Best Practices
|
|
||||||
|
|
||||||
### Content Management
|
|
||||||
|
|
||||||
- Keep notification content concise and actionable
|
|
||||||
- Use clear, engaging titles under 50 characters
|
|
||||||
- Limit notification body to 2-3 lines
|
|
||||||
- Include a clear call-to-action when appropriate
|
|
||||||
|
|
||||||
### Network Optimization
|
|
||||||
|
|
||||||
- Implement proper caching headers on your API
|
|
||||||
- Use compression for network responses
|
|
||||||
- Keep payload size under 4KB for optimal performance
|
|
||||||
- Implement rate limiting on your API endpoints
|
|
||||||
|
|
||||||
### Battery Considerations
|
|
||||||
|
|
||||||
- Schedule notifications during active hours
|
|
||||||
- Avoid excessive background fetches
|
|
||||||
- Use appropriate fetch intervals (minimum 15 minutes)
|
|
||||||
- Implement smart retry strategies
|
|
||||||
|
|
||||||
### User Experience
|
|
||||||
|
|
||||||
- Request notification permissions at an appropriate time
|
|
||||||
- Provide clear value proposition for notifications
|
|
||||||
- Allow users to customize notification timing
|
|
||||||
- Implement proper error messaging for users
|
|
||||||
|
|
||||||
### Security
|
|
||||||
|
|
||||||
- Always use HTTPS for API endpoints
|
|
||||||
- Implement proper API authentication
|
|
||||||
- Sanitize notification content
|
|
||||||
- Follow platform-specific security guidelines
|
|
||||||
|
|
||||||
### Testing
|
|
||||||
|
|
||||||
- Test notifications in various app states
|
|
||||||
- Verify behavior with different network conditions
|
|
||||||
- Test on multiple device types and OS versions
|
|
||||||
- Implement proper error logging for debugging
|
|
||||||
|
|
||||||
## Development Setup
|
|
||||||
|
|
||||||
### Prerequisites
|
|
||||||
|
|
||||||
1. Node.js 14 or higher
|
|
||||||
2. Java 11 or higher
|
|
||||||
3. Android Studio and Android SDK
|
|
||||||
4. Xcode (for iOS development, macOS only)
|
|
||||||
5. CocoaPods (for iOS development)
|
|
||||||
|
|
||||||
### Environment Setup
|
|
||||||
|
|
||||||
1. Clone the repository:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/yourusername/capacitor-daily-notification.git
|
|
||||||
cd capacitor-daily-notification
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Install dependencies:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install
|
|
||||||
```
|
|
||||||
|
|
||||||
This will:
|
|
||||||
|
|
||||||
- Install Node.js dependencies
|
|
||||||
- Check your development environment
|
|
||||||
- Set up native build environments
|
|
||||||
- Install platform-specific dependencies
|
|
||||||
|
|
||||||
### Building the Plugin
|
|
||||||
|
|
||||||
#### TypeScript Build
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Build TypeScript code
|
|
||||||
npm run build
|
|
||||||
|
|
||||||
# Watch mode for development
|
|
||||||
npm run watch
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Android Build
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Build Android library
|
|
||||||
npm run build:android
|
|
||||||
|
|
||||||
# Run Android tests
|
|
||||||
npm run test:android
|
|
||||||
```
|
|
||||||
|
|
||||||
The Android build will:
|
|
||||||
|
|
||||||
1. Compile the TypeScript code
|
|
||||||
2. Build the Android library
|
|
||||||
3. Generate an AAR file in `android/build/outputs/aar/`
|
|
||||||
|
|
||||||
#### iOS Build
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Build iOS library
|
|
||||||
npm run build:ios
|
|
||||||
|
|
||||||
# Run iOS tests
|
|
||||||
npm run test:ios
|
|
||||||
```
|
|
||||||
|
|
||||||
The iOS build will:
|
|
||||||
|
|
||||||
1. Compile the TypeScript code
|
|
||||||
2. Install CocoaPods dependencies
|
|
||||||
3. Build the iOS framework
|
|
||||||
|
|
||||||
### Using in a Capacitor App
|
|
||||||
|
|
||||||
1. Install the plugin in your Capacitor app:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install capacitor-daily-notification
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Add to your Android app's `android/app/build.gradle`:
|
|
||||||
|
|
||||||
```gradle
|
|
||||||
dependencies {
|
|
||||||
implementation project(':daily-notification')
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Add to your iOS app's `ios/App/Podfile`:
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
pod 'CapacitorDailyNotification', :path => '../node_modules/capacitor-daily-notification'
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Sync native projects:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npx cap sync
|
|
||||||
```
|
|
||||||
|
|
||||||
### Troubleshooting
|
|
||||||
|
|
||||||
#### Android Issues
|
|
||||||
|
|
||||||
1. Gradle Sync Failed
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd android
|
|
||||||
./gradlew clean
|
|
||||||
./gradlew --refresh-dependencies
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Missing Android SDK
|
|
||||||
|
|
||||||
- Set ANDROID_HOME environment variable
|
|
||||||
- Install required SDK components via Android Studio
|
|
||||||
|
|
||||||
3. Build Errors
|
|
||||||
|
|
||||||
- Check Android Studio for detailed error messages
|
|
||||||
- Ensure all required SDK components are installed
|
|
||||||
- Verify Gradle version compatibility
|
|
||||||
|
|
||||||
#### iOS Issues
|
|
||||||
|
|
||||||
1. Pod Install Failed
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd ios
|
|
||||||
pod deintegrate
|
|
||||||
pod cache clean --all
|
|
||||||
pod install
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Xcode Build Errors
|
|
||||||
|
|
||||||
- Open Xcode project in Xcode
|
|
||||||
- Check build settings
|
|
||||||
- Verify deployment target matches requirements
|
|
||||||
|
|
||||||
3. Missing Dependencies
|
|
||||||
|
|
||||||
- Ensure CocoaPods is installed
|
|
||||||
- Run `pod setup` to update CocoaPods repos
|
|
||||||
|
|
||||||
### Development Workflow
|
|
||||||
|
|
||||||
1. Make changes to TypeScript code
|
|
||||||
2. Run `npm run build` to compile
|
|
||||||
3. Run `npm run build:native` to build native code
|
|
||||||
4. Test changes:
|
|
||||||
- Android: `npm run test:android`
|
|
||||||
- iOS: `npm run test:ios`
|
|
||||||
5. Run full validation:
|
|
||||||
- Android: `npm run validate`
|
|
||||||
- iOS: `npm run validate:ios`
|
|
||||||
|
|
||||||
### Continuous Integration
|
|
||||||
|
|
||||||
The plugin includes pre-commit hooks and CI configurations:
|
|
||||||
|
|
||||||
1. Pre-commit checks:
|
|
||||||
- TypeScript compilation
|
|
||||||
- Linting
|
|
||||||
- Native build verification
|
|
||||||
|
|
||||||
2. CI pipeline:
|
|
||||||
- Environment validation
|
|
||||||
- TypeScript build
|
|
||||||
- Native builds
|
|
||||||
- Unit tests
|
|
||||||
- Integration tests
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
1. Fork the repository
|
Contributions are welcome! Please read our contributing guidelines and submit pull requests to our GitHub repository.
|
||||||
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
||||||
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
||||||
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
||||||
5. Open a Pull Request
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
MIT License - see LICENSE file for details
|
||||||
|
|
||||||
## Author
|
|
||||||
|
|
||||||
Matthew Raymer
|
|
||||||
|
|
||||||
## Plugin Security
|
|
||||||
|
|
||||||
This plugin follows security best practices:
|
|
||||||
|
|
||||||
- Secure storage of sensitive data
|
|
||||||
- HTTPS-only network requests
|
|
||||||
- Permission-based access control
|
|
||||||
- Regular security audits
|
|
||||||
- No sensitive data in logs
|
|
||||||
|
|
||||||
## Support
|
|
||||||
|
|
||||||
For support, please open an issue in the GitHub repository or contact the maintainers.
|
|
||||||
|
|
||||||
## Changelog
|
|
||||||
|
|
||||||
See [CHANGELOG.md](CHANGELOG.md) for a list of changes and version history.
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import android.app.NotificationManager;
|
|||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
@@ -35,6 +36,8 @@ public class DailyNotificationPlugin extends Plugin {
|
|||||||
private NotificationManager notificationManager;
|
private NotificationManager notificationManager;
|
||||||
private AlarmManager alarmManager;
|
private AlarmManager alarmManager;
|
||||||
private Context context;
|
private Context context;
|
||||||
|
private SharedPreferences settings;
|
||||||
|
private static final String SETTINGS_KEY = "daily_notification_settings";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void load() {
|
public void load() {
|
||||||
@@ -42,6 +45,7 @@ public class DailyNotificationPlugin extends Plugin {
|
|||||||
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||||
createNotificationChannel();
|
createNotificationChannel();
|
||||||
|
settings = context.getSharedPreferences(SETTINGS_KEY, Context.MODE_PRIVATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createNotificationChannel() {
|
private void createNotificationChannel() {
|
||||||
@@ -154,7 +158,18 @@ public class DailyNotificationPlugin extends Plugin {
|
|||||||
|
|
||||||
@PluginMethod
|
@PluginMethod
|
||||||
public void updateSettings(PluginCall call) {
|
public void updateSettings(PluginCall call) {
|
||||||
// TODO: Implement settings update
|
SharedPreferences.Editor editor = settings.edit();
|
||||||
|
if (call.hasOption("timezone")) {
|
||||||
|
String timezone = call.getString("timezone");
|
||||||
|
if (TimeZone.getTimeZone(timezone) != null) {
|
||||||
|
editor.putString("timezone", timezone);
|
||||||
|
} else {
|
||||||
|
call.reject("Invalid timezone");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add other settings...
|
||||||
|
editor.apply();
|
||||||
call.resolve();
|
call.resolve();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
16
ios/DailyNotificationPlugin.podspec
Normal file
16
ios/DailyNotificationPlugin.podspec
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
Pod::Spec.new do |s|
|
||||||
|
s.name = 'DailyNotificationPlugin'
|
||||||
|
s.version = '1.0.0'
|
||||||
|
s.summary = 'Daily notification plugin for Capacitor'
|
||||||
|
s.license = 'MIT'
|
||||||
|
s.homepage = 'https://github.com/timesafari/daily-notification-plugin'
|
||||||
|
s.author = 'TimeSafari'
|
||||||
|
s.source = { :git => 'https://github.com/timesafari/daily-notification-plugin.git', :tag => s.version.to_s }
|
||||||
|
s.source_files = 'Plugin/**/*.{swift,h,m,c,cc,mm,cpp}'
|
||||||
|
s.ios.deployment_target = '13.0'
|
||||||
|
s.dependency 'Capacitor'
|
||||||
|
s.dependency 'CapacitorCordova'
|
||||||
|
s.swift_version = '5.1'
|
||||||
|
s.module_name = 'DailyNotificationPlugin'
|
||||||
|
s.static_framework = true
|
||||||
|
end
|
||||||
570
ios/DailyNotificationPlugin.xcodeproj/project.pbxproj
Normal file
570
ios/DailyNotificationPlugin.xcodeproj/project.pbxproj
Normal file
@@ -0,0 +1,570 @@
|
|||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 54;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
0C773ACB32780E104F9F24C8 /* DailyNotificationPlugin.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3323D7F1B3ED08FAA559D317 /* DailyNotificationPlugin.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||||
|
2B7E978FB6B43664754FC9BB /* DailyNotificationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6495D32429F76744DC98B457 /* DailyNotificationTests.swift */; };
|
||||||
|
3C8161B717E367A8B88111BF /* DailyNotificationConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFC45ABFC1A903AE6233B13F /* DailyNotificationConfig.swift */; };
|
||||||
|
5898E89B868436827E1E06DF /* DailyNotificationPlugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3323D7F1B3ED08FAA559D317 /* DailyNotificationPlugin.framework */; };
|
||||||
|
6C1E173CC70849A66F85B12C /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 2DDEB96E881144AB9DBCDF17 /* README.md */; };
|
||||||
|
74067B7FB473F9455DABAA30 /* Pods_DailyNotificationPlugin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BD2A2F1CA91755E648A5D57 /* Pods_DailyNotificationPlugin.framework */; };
|
||||||
|
8640E8860A5334043F24DC54 /* Pods_DailyNotificationPluginTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0A49F9F065B6559C77DE3BD5 /* Pods_DailyNotificationPluginTests.framework */; };
|
||||||
|
92CCC02492ECD5CADABE7BC4 /* DailyNotificationError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC43315277A65E01BD1B352F /* DailyNotificationError.swift */; };
|
||||||
|
C194055B816EA1C2DCF17BD2 /* DailyNotificationPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = A645658475F4138A9256D485 /* DailyNotificationPlugin.swift */; };
|
||||||
|
DBCD22D6FACC2C730D7C2911 /* DailyNotificationLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 467AB34F611231718368D768 /* DailyNotificationLogger.swift */; };
|
||||||
|
F86B65B48D5B072F30F76479 /* index.ts in Resources */ = {isa = PBXBuildFile; fileRef = A73A4B8720F98987381BAECF /* index.ts */; };
|
||||||
|
FB9C99C0B426E0109ED1218C /* DailyNotificationConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9237F98BBE39C5667CCCF78C /* DailyNotificationConstants.swift */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
AE616C66C793C36141ED183E /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 006593AF8D5F74184E8E7C52 /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 257C4D3AD8FBFC25B796808A;
|
||||||
|
remoteInfo = DailyNotificationPlugin;
|
||||||
|
};
|
||||||
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
|
4943F65747C3ABB97AEBDDB9 /* Embed Frameworks */ = {
|
||||||
|
isa = PBXCopyFilesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
dstPath = "";
|
||||||
|
dstSubfolderSpec = 10;
|
||||||
|
files = (
|
||||||
|
0C773ACB32780E104F9F24C8 /* DailyNotificationPlugin.framework in Embed Frameworks */,
|
||||||
|
);
|
||||||
|
name = "Embed Frameworks";
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
0A49F9F065B6559C77DE3BD5 /* Pods_DailyNotificationPluginTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DailyNotificationPluginTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
2DDEB96E881144AB9DBCDF17 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||||
|
3323D7F1B3ED08FAA559D317 /* DailyNotificationPlugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DailyNotificationPlugin.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
3BD2A2F1CA91755E648A5D57 /* Pods_DailyNotificationPlugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DailyNotificationPlugin.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
40B0BB9ACA2D2A1BEB4DF9A2 /* Pods-DailyNotificationPluginTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DailyNotificationPluginTests.debug.xcconfig"; path = "Target Support Files/Pods-DailyNotificationPluginTests/Pods-DailyNotificationPluginTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
4494D62E3E3D3A7EFAE5270C /* Pods-DailyNotificationPlugin.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DailyNotificationPlugin.debug.xcconfig"; path = "Target Support Files/Pods-DailyNotificationPlugin/Pods-DailyNotificationPlugin.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
467AB34F611231718368D768 /* DailyNotificationLogger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailyNotificationLogger.swift; sourceTree = "<group>"; };
|
||||||
|
6495D32429F76744DC98B457 /* DailyNotificationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailyNotificationTests.swift; sourceTree = "<group>"; };
|
||||||
|
77711E259A9C3D73936E2780 /* Pods-DailyNotificationPlugin.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DailyNotificationPlugin.release.xcconfig"; path = "Target Support Files/Pods-DailyNotificationPlugin/Pods-DailyNotificationPlugin.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
7DA0C384AE2BD3E27E1CA95A /* Pods-DailyNotificationPluginTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DailyNotificationPluginTests.release.xcconfig"; path = "Target Support Files/Pods-DailyNotificationPluginTests/Pods-DailyNotificationPluginTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
9237F98BBE39C5667CCCF78C /* DailyNotificationConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailyNotificationConstants.swift; sourceTree = "<group>"; };
|
||||||
|
A645658475F4138A9256D485 /* DailyNotificationPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailyNotificationPlugin.swift; sourceTree = "<group>"; };
|
||||||
|
A73A4B8720F98987381BAECF /* index.ts */ = {isa = PBXFileReference; path = index.ts; sourceTree = "<group>"; };
|
||||||
|
AA32A2FDCE5869E99D5888F0 /* DailyNotificationPluginTests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = DailyNotificationPluginTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
DC43315277A65E01BD1B352F /* DailyNotificationError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailyNotificationError.swift; sourceTree = "<group>"; };
|
||||||
|
FFC45ABFC1A903AE6233B13F /* DailyNotificationConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DailyNotificationConfig.swift; sourceTree = "<group>"; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
55585DA18B4D813764BADC93 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
74067B7FB473F9455DABAA30 /* Pods_DailyNotificationPlugin.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
8D6E11ADD3F7437A18DDD332 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
5898E89B868436827E1E06DF /* DailyNotificationPlugin.framework in Frameworks */,
|
||||||
|
8640E8860A5334043F24DC54 /* Pods_DailyNotificationPluginTests.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
1E538212868D96F5FE5949D3 /* Plugin */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
FFC45ABFC1A903AE6233B13F /* DailyNotificationConfig.swift */,
|
||||||
|
9237F98BBE39C5667CCCF78C /* DailyNotificationConstants.swift */,
|
||||||
|
DC43315277A65E01BD1B352F /* DailyNotificationError.swift */,
|
||||||
|
467AB34F611231718368D768 /* DailyNotificationLogger.swift */,
|
||||||
|
A645658475F4138A9256D485 /* DailyNotificationPlugin.swift */,
|
||||||
|
A73A4B8720F98987381BAECF /* index.ts */,
|
||||||
|
2DDEB96E881144AB9DBCDF17 /* README.md */,
|
||||||
|
);
|
||||||
|
path = Plugin;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
28D6F94971201D3DB74C25C2 = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
1E538212868D96F5FE5949D3 /* Plugin */,
|
||||||
|
3233C506859453B03BDE86D8 /* Tests */,
|
||||||
|
E84F19FCBB1C18FE94E42EC8 /* Products */,
|
||||||
|
FA2E2F2AFEF5A51D9DCAFC04 /* Pods */,
|
||||||
|
ADB432E27D513A3C69B9A1A3 /* Frameworks */,
|
||||||
|
);
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
3233C506859453B03BDE86D8 /* Tests */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
6495D32429F76744DC98B457 /* DailyNotificationTests.swift */,
|
||||||
|
);
|
||||||
|
path = Tests;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
ADB432E27D513A3C69B9A1A3 /* Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
3BD2A2F1CA91755E648A5D57 /* Pods_DailyNotificationPlugin.framework */,
|
||||||
|
0A49F9F065B6559C77DE3BD5 /* Pods_DailyNotificationPluginTests.framework */,
|
||||||
|
);
|
||||||
|
name = Frameworks;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
E84F19FCBB1C18FE94E42EC8 /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
3323D7F1B3ED08FAA559D317 /* DailyNotificationPlugin.framework */,
|
||||||
|
AA32A2FDCE5869E99D5888F0 /* DailyNotificationPluginTests.xctest */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
FA2E2F2AFEF5A51D9DCAFC04 /* Pods */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
4494D62E3E3D3A7EFAE5270C /* Pods-DailyNotificationPlugin.debug.xcconfig */,
|
||||||
|
77711E259A9C3D73936E2780 /* Pods-DailyNotificationPlugin.release.xcconfig */,
|
||||||
|
40B0BB9ACA2D2A1BEB4DF9A2 /* Pods-DailyNotificationPluginTests.debug.xcconfig */,
|
||||||
|
7DA0C384AE2BD3E27E1CA95A /* Pods-DailyNotificationPluginTests.release.xcconfig */,
|
||||||
|
);
|
||||||
|
name = Pods;
|
||||||
|
path = Pods;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
257C4D3AD8FBFC25B796808A /* DailyNotificationPlugin */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = A48909A0B23F2E1853CA7243 /* Build configuration list for PBXNativeTarget "DailyNotificationPlugin" */;
|
||||||
|
buildPhases = (
|
||||||
|
EFC33670012401F59F542C6C /* [CP] Check Pods Manifest.lock */,
|
||||||
|
B64C03AB42C5F59F0C2AC34C /* Sources */,
|
||||||
|
F64E92967F4F9B8AB5FB3FF0 /* Resources */,
|
||||||
|
55585DA18B4D813764BADC93 /* Frameworks */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = DailyNotificationPlugin;
|
||||||
|
productName = DailyNotificationPlugin;
|
||||||
|
productReference = 3323D7F1B3ED08FAA559D317 /* DailyNotificationPlugin.framework */;
|
||||||
|
productType = "com.apple.product-type.framework";
|
||||||
|
};
|
||||||
|
D5D84A92030AF309D12F0C04 /* DailyNotificationPluginTests */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 29C4C700B6D1011122DEB3D1 /* Build configuration list for PBXNativeTarget "DailyNotificationPluginTests" */;
|
||||||
|
buildPhases = (
|
||||||
|
2A3C79169070A704F233230B /* [CP] Check Pods Manifest.lock */,
|
||||||
|
55FB7A11B0C278223BAC8576 /* Sources */,
|
||||||
|
8D6E11ADD3F7437A18DDD332 /* Frameworks */,
|
||||||
|
4943F65747C3ABB97AEBDDB9 /* Embed Frameworks */,
|
||||||
|
7B305C495763B32DED093F95 /* [CP] Embed Pods Frameworks */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
E48942294A3D346D124D468C /* PBXTargetDependency */,
|
||||||
|
);
|
||||||
|
name = DailyNotificationPluginTests;
|
||||||
|
productName = DailyNotificationPluginTests;
|
||||||
|
productReference = AA32A2FDCE5869E99D5888F0 /* DailyNotificationPluginTests.xctest */;
|
||||||
|
productType = "com.apple.product-type.bundle.unit-test";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
006593AF8D5F74184E8E7C52 /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
BuildIndependentTargetsInParallel = YES;
|
||||||
|
LastUpgradeCheck = 1430;
|
||||||
|
TargetAttributes = {
|
||||||
|
257C4D3AD8FBFC25B796808A = {
|
||||||
|
DevelopmentTeam = "";
|
||||||
|
};
|
||||||
|
D5D84A92030AF309D12F0C04 = {
|
||||||
|
DevelopmentTeam = "";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
buildConfigurationList = E3A89DF03E1CDA836997EEC6 /* Build configuration list for PBXProject "DailyNotificationPlugin" */;
|
||||||
|
compatibilityVersion = "Xcode 14.0";
|
||||||
|
developmentRegion = en;
|
||||||
|
hasScannedForEncodings = 0;
|
||||||
|
knownRegions = (
|
||||||
|
Base,
|
||||||
|
en,
|
||||||
|
);
|
||||||
|
mainGroup = 28D6F94971201D3DB74C25C2;
|
||||||
|
productRefGroup = E84F19FCBB1C18FE94E42EC8 /* Products */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
257C4D3AD8FBFC25B796808A /* DailyNotificationPlugin */,
|
||||||
|
D5D84A92030AF309D12F0C04 /* DailyNotificationPluginTests */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
F64E92967F4F9B8AB5FB3FF0 /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
6C1E173CC70849A66F85B12C /* README.md in Resources */,
|
||||||
|
F86B65B48D5B072F30F76479 /* index.ts in Resources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXShellScriptBuildPhase section */
|
||||||
|
2A3C79169070A704F233230B /* [CP] Check Pods Manifest.lock */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||||
|
"${PODS_ROOT}/Manifest.lock",
|
||||||
|
);
|
||||||
|
name = "[CP] Check Pods Manifest.lock";
|
||||||
|
outputFileListPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
"$(DERIVED_FILE_DIR)/Pods-DailyNotificationPluginTests-checkManifestLockResult.txt",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
|
7B305C495763B32DED093F95 /* [CP] Embed Pods Frameworks */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-DailyNotificationPluginTests/Pods-DailyNotificationPluginTests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
|
);
|
||||||
|
name = "[CP] Embed Pods Frameworks";
|
||||||
|
outputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-DailyNotificationPluginTests/Pods-DailyNotificationPluginTests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-DailyNotificationPluginTests/Pods-DailyNotificationPluginTests-frameworks.sh\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
|
EFC33670012401F59F542C6C /* [CP] Check Pods Manifest.lock */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||||
|
"${PODS_ROOT}/Manifest.lock",
|
||||||
|
);
|
||||||
|
name = "[CP] Check Pods Manifest.lock";
|
||||||
|
outputFileListPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
"$(DERIVED_FILE_DIR)/Pods-DailyNotificationPlugin-checkManifestLockResult.txt",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
55FB7A11B0C278223BAC8576 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
2B7E978FB6B43664754FC9BB /* DailyNotificationTests.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
B64C03AB42C5F59F0C2AC34C /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
3C8161B717E367A8B88111BF /* DailyNotificationConfig.swift in Sources */,
|
||||||
|
FB9C99C0B426E0109ED1218C /* DailyNotificationConstants.swift in Sources */,
|
||||||
|
92CCC02492ECD5CADABE7BC4 /* DailyNotificationError.swift in Sources */,
|
||||||
|
DBCD22D6FACC2C730D7C2911 /* DailyNotificationLogger.swift in Sources */,
|
||||||
|
C194055B816EA1C2DCF17BD2 /* DailyNotificationPlugin.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXTargetDependency section */
|
||||||
|
E48942294A3D346D124D468C /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = 257C4D3AD8FBFC25B796808A /* DailyNotificationPlugin */;
|
||||||
|
targetProxy = AE616C66C793C36141ED183E /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
1B945D5C7C74FADDDFCFBE5B /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 77711E259A9C3D73936E2780 /* Pods-DailyNotificationPlugin.release.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_IDENTITY = "";
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEFINES_MODULE = YES;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||||
|
DYLIB_CURRENT_VERSION = 1;
|
||||||
|
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||||
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.timesafari.dailynotification;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
34E9AA395681C624E34D67AC /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 4494D62E3E3D3A7EFAE5270C /* Pods-DailyNotificationPlugin.debug.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_IDENTITY = "";
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEFINES_MODULE = YES;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||||
|
DYLIB_CURRENT_VERSION = 1;
|
||||||
|
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||||
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.timesafari.dailynotification;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
67AF4EA7655D29A052EF8B83 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"DEBUG=1",
|
||||||
|
);
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
8C3734FD07E9594E1FAA5E80 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 7DA0C384AE2BD3E27E1CA95A /* Pods-DailyNotificationPluginTests.release.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@loader_path/Frameworks",
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.timesafari.dailynotification.tests;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
9A90FB54CF53D768F76987E3 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 40B0BB9ACA2D2A1BEB4DF9A2 /* Pods-DailyNotificationPluginTests.debug.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@loader_path/Frameworks",
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.timesafari.dailynotification.tests;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
E64E663501BF0EF5E09805E2 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SWIFT_COMPILATION_MODE = wholemodule;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
29C4C700B6D1011122DEB3D1 /* Build configuration list for PBXNativeTarget "DailyNotificationPluginTests" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
9A90FB54CF53D768F76987E3 /* Debug */,
|
||||||
|
8C3734FD07E9594E1FAA5E80 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Debug;
|
||||||
|
};
|
||||||
|
A48909A0B23F2E1853CA7243 /* Build configuration list for PBXNativeTarget "DailyNotificationPlugin" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
34E9AA395681C624E34D67AC /* Debug */,
|
||||||
|
1B945D5C7C74FADDDFCFBE5B /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Debug;
|
||||||
|
};
|
||||||
|
E3A89DF03E1CDA836997EEC6 /* Build configuration list for PBXProject "DailyNotificationPlugin" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
67AF4EA7655D29A052EF8B83 /* Debug */,
|
||||||
|
E64E663501BF0EF5E09805E2 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Debug;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
};
|
||||||
|
rootObject = 006593AF8D5F74184E8E7C52 /* Project object */;
|
||||||
|
}
|
||||||
7
ios/DailyNotificationPlugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
ios/DailyNotificationPlugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "self:">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "1430"
|
||||||
|
version = "1.7">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES"
|
||||||
|
runPostActionsOnFailure = "NO">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "257C4D3AD8FBFC25B796808A"
|
||||||
|
BuildableName = "DailyNotificationPlugin.framework"
|
||||||
|
BlueprintName = "DailyNotificationPlugin"
|
||||||
|
ReferencedContainer = "container:DailyNotificationPlugin.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
onlyGenerateCoverageForSpecifiedTargets = "NO">
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "257C4D3AD8FBFC25B796808A"
|
||||||
|
BuildableName = "DailyNotificationPlugin.framework"
|
||||||
|
BlueprintName = "DailyNotificationPlugin"
|
||||||
|
ReferencedContainer = "container:DailyNotificationPlugin.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
<Testables>
|
||||||
|
<TestableReference
|
||||||
|
skipped = "NO">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "D5D84A92030AF309D12F0C04"
|
||||||
|
BuildableName = "DailyNotificationPluginTests.xctest"
|
||||||
|
BlueprintName = "DailyNotificationPluginTests"
|
||||||
|
ReferencedContainer = "container:DailyNotificationPlugin.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</TestableReference>
|
||||||
|
</Testables>
|
||||||
|
<CommandLineArguments>
|
||||||
|
</CommandLineArguments>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES">
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "257C4D3AD8FBFC25B796808A"
|
||||||
|
BuildableName = "DailyNotificationPlugin.framework"
|
||||||
|
BlueprintName = "DailyNotificationPlugin"
|
||||||
|
ReferencedContainer = "container:DailyNotificationPlugin.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
<CommandLineArguments>
|
||||||
|
</CommandLineArguments>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES">
|
||||||
|
<CommandLineArguments>
|
||||||
|
</CommandLineArguments>
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "257C4D3AD8FBFC25B796808A"
|
||||||
|
BuildableName = "DailyNotificationPlugin.framework"
|
||||||
|
BlueprintName = "DailyNotificationPlugin"
|
||||||
|
ReferencedContainer = "container:DailyNotificationPlugin.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "1430"
|
||||||
|
version = "1.7">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES"
|
||||||
|
runPostActionsOnFailure = "NO">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "D5D84A92030AF309D12F0C04"
|
||||||
|
BuildableName = "DailyNotificationPluginTests.xctest"
|
||||||
|
BlueprintName = "DailyNotificationPluginTests"
|
||||||
|
ReferencedContainer = "container:DailyNotificationPlugin.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
onlyGenerateCoverageForSpecifiedTargets = "NO">
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "D5D84A92030AF309D12F0C04"
|
||||||
|
BuildableName = "DailyNotificationPluginTests.xctest"
|
||||||
|
BlueprintName = "DailyNotificationPluginTests"
|
||||||
|
ReferencedContainer = "container:DailyNotificationPlugin.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
<Testables>
|
||||||
|
<TestableReference
|
||||||
|
skipped = "NO">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "D5D84A92030AF309D12F0C04"
|
||||||
|
BuildableName = "DailyNotificationPluginTests.xctest"
|
||||||
|
BlueprintName = "DailyNotificationPluginTests"
|
||||||
|
ReferencedContainer = "container:DailyNotificationPlugin.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</TestableReference>
|
||||||
|
</Testables>
|
||||||
|
<CommandLineArguments>
|
||||||
|
</CommandLineArguments>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES">
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "D5D84A92030AF309D12F0C04"
|
||||||
|
BuildableName = "DailyNotificationPluginTests.xctest"
|
||||||
|
BlueprintName = "DailyNotificationPluginTests"
|
||||||
|
ReferencedContainer = "container:DailyNotificationPlugin.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES">
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "D5D84A92030AF309D12F0C04"
|
||||||
|
BuildableName = "DailyNotificationPluginTests.xctest"
|
||||||
|
BlueprintName = "DailyNotificationPluginTests"
|
||||||
|
ReferencedContainer = "container:DailyNotificationPlugin.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
10
ios/DailyNotificationPlugin.xcworkspace/contents.xcworkspacedata
generated
Normal file
10
ios/DailyNotificationPlugin.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "group:DailyNotificationPlugin.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
<FileRef
|
||||||
|
location = "group:Pods/Pods.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
||||||
BIN
ios/DailyNotificationPlugin.xcworkspace/xcuserdata/cloud.xcuserdatad/UserInterfaceState.xcuserstate
generated
Normal file
BIN
ios/DailyNotificationPlugin.xcworkspace/xcuserdata/cloud.xcuserdatad/UserInterfaceState.xcuserstate
generated
Normal file
Binary file not shown.
31
ios/Plugin/DailyNotificationConfig.swift
Normal file
31
ios/Plugin/DailyNotificationConfig.swift
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* DailyNotificationConfig.swift
|
||||||
|
* Daily Notification Plugin for Capacitor
|
||||||
|
*
|
||||||
|
* Provides configuration options for the notification plugin
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// Configuration options for the DailyNotification plugin
|
||||||
|
///
|
||||||
|
/// This singleton structure provides configurable options that can be modified
|
||||||
|
/// to customize the plugin's behavior.
|
||||||
|
public struct DailyNotificationConfig {
|
||||||
|
/// Shared instance for singleton access
|
||||||
|
public static var shared = DailyNotificationConfig()
|
||||||
|
|
||||||
|
/// Maximum number of notifications that can be scheduled per day
|
||||||
|
public var maxNotificationsPerDay = 10
|
||||||
|
|
||||||
|
/// Default timezone for notifications when none is specified
|
||||||
|
public var defaultTimeZone = TimeZone.current
|
||||||
|
|
||||||
|
/// Whether debug logging is enabled
|
||||||
|
public var loggingEnabled = true
|
||||||
|
|
||||||
|
/// Number of days to retain delivered notifications
|
||||||
|
public var retentionDays = 7
|
||||||
|
|
||||||
|
private init() {}
|
||||||
|
}
|
||||||
52
ios/Plugin/DailyNotificationConstants.swift
Normal file
52
ios/Plugin/DailyNotificationConstants.swift
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/**
|
||||||
|
* DailyNotificationConstants.swift
|
||||||
|
* Daily Notification Plugin for Capacitor
|
||||||
|
*
|
||||||
|
* Defines constant values used throughout the notification plugin
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// Constants used throughout the DailyNotification plugin
|
||||||
|
///
|
||||||
|
/// This structure provides centralized access to all constant values used in the plugin,
|
||||||
|
/// making it easier to maintain and update common values.
|
||||||
|
public struct DailyNotificationConstants {
|
||||||
|
/// Default notification title when none is provided
|
||||||
|
public static let defaultTitle = "Daily Notification"
|
||||||
|
|
||||||
|
/// Default notification body when none is provided
|
||||||
|
public static let defaultBody = "Your daily update is ready"
|
||||||
|
|
||||||
|
/// Prefix used for notification identifiers
|
||||||
|
public static let notificationIdentifierPrefix = "daily-notification-"
|
||||||
|
|
||||||
|
/// Name of the event emitted for notification interactions
|
||||||
|
public static let eventName = "notification"
|
||||||
|
|
||||||
|
/// Default settings for notifications
|
||||||
|
public struct Settings {
|
||||||
|
/// Whether sound is enabled by default
|
||||||
|
public static let defaultSound = true
|
||||||
|
|
||||||
|
/// Default priority level for notifications
|
||||||
|
public static let defaultPriority = "default"
|
||||||
|
|
||||||
|
/// Default number of retry attempts
|
||||||
|
public static let defaultRetryCount = 3
|
||||||
|
|
||||||
|
/// Default interval between retries (in milliseconds)
|
||||||
|
public static let defaultRetryInterval = 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Keys used in plugin method calls
|
||||||
|
public struct Keys {
|
||||||
|
public static let url = "url"
|
||||||
|
public static let time = "time"
|
||||||
|
public static let title = "title"
|
||||||
|
public static let body = "body"
|
||||||
|
public static let sound = "sound"
|
||||||
|
public static let priority = "priority"
|
||||||
|
public static let timezone = "timezone"
|
||||||
|
}
|
||||||
|
}
|
||||||
50
ios/Plugin/DailyNotificationError.swift
Normal file
50
ios/Plugin/DailyNotificationError.swift
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* DailyNotificationError.swift
|
||||||
|
* Daily Notification Plugin for Capacitor
|
||||||
|
*
|
||||||
|
* Defines error types and handling for the notification plugin
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// Represents possible errors that can occur within the DailyNotification plugin
|
||||||
|
///
|
||||||
|
/// These errors provide specific failure cases and associated messages for better
|
||||||
|
/// error handling and debugging in the notification scheduling process.
|
||||||
|
public enum DailyNotificationError: Error {
|
||||||
|
/// Thrown when required parameters are missing or invalid
|
||||||
|
case invalidParameters(String)
|
||||||
|
|
||||||
|
/// Thrown when notification permissions have not been granted
|
||||||
|
case permissionDenied
|
||||||
|
|
||||||
|
/// Thrown when notification scheduling fails
|
||||||
|
case schedulingFailed(String)
|
||||||
|
|
||||||
|
/// Thrown when time format is invalid (should be HH:mm)
|
||||||
|
case invalidTimeFormat
|
||||||
|
|
||||||
|
/// Thrown when provided timezone identifier is invalid
|
||||||
|
case invalidTimezone
|
||||||
|
|
||||||
|
/// Thrown when priority value is not one of: high, default, low
|
||||||
|
case invalidPriority
|
||||||
|
|
||||||
|
/// Human-readable error messages for each error case
|
||||||
|
public var message: String {
|
||||||
|
switch self {
|
||||||
|
case .invalidParameters(let detail):
|
||||||
|
return "Invalid parameters: \(detail)"
|
||||||
|
case .permissionDenied:
|
||||||
|
return "Notification permissions not granted"
|
||||||
|
case .schedulingFailed(let reason):
|
||||||
|
return "Failed to schedule notification: \(reason)"
|
||||||
|
case .invalidTimeFormat:
|
||||||
|
return "Invalid time format. Expected HH:mm"
|
||||||
|
case .invalidTimezone:
|
||||||
|
return "Invalid timezone identifier"
|
||||||
|
case .invalidPriority:
|
||||||
|
return "Invalid priority value. Expected 'high', 'default', or 'low'"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
44
ios/Plugin/DailyNotificationLogger.swift
Normal file
44
ios/Plugin/DailyNotificationLogger.swift
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* DailyNotificationLogger.swift
|
||||||
|
* Daily Notification Plugin for Capacitor
|
||||||
|
*
|
||||||
|
* Provides logging functionality for the notification plugin
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// Logger utility for the DailyNotification plugin
|
||||||
|
///
|
||||||
|
/// Provides structured logging capabilities with different severity levels
|
||||||
|
/// and automatic file/line/function information.
|
||||||
|
public class DailyNotificationLogger {
|
||||||
|
/// Shared instance for singleton access
|
||||||
|
public static let shared = DailyNotificationLogger()
|
||||||
|
|
||||||
|
/// Available logging levels
|
||||||
|
public enum Level: String {
|
||||||
|
case debug, info, warning, error
|
||||||
|
}
|
||||||
|
|
||||||
|
private init() {}
|
||||||
|
|
||||||
|
/// Log a message with the specified severity level
|
||||||
|
/// - Parameters:
|
||||||
|
/// - level: The severity level of the log
|
||||||
|
/// - message: The message to log
|
||||||
|
/// - file: The file where the log was called (automatic)
|
||||||
|
/// - function: The function where the log was called (automatic)
|
||||||
|
/// - line: The line number where the log was called (automatic)
|
||||||
|
public func log(
|
||||||
|
_ level: Level,
|
||||||
|
_ message: String,
|
||||||
|
file: String = #file,
|
||||||
|
function: String = #function,
|
||||||
|
line: Int = #line
|
||||||
|
) {
|
||||||
|
#if DEBUG
|
||||||
|
let fileName = (file as NSString).lastPathComponent
|
||||||
|
print("[\(level.rawValue.uppercased())] [\(fileName):\(line)] \(function): \(message)")
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,10 +9,29 @@ import Foundation
|
|||||||
import Capacitor
|
import Capacitor
|
||||||
import UserNotifications
|
import UserNotifications
|
||||||
|
|
||||||
|
/// Represents the main plugin class for handling daily notifications
|
||||||
|
///
|
||||||
|
/// This plugin provides functionality for scheduling and managing daily notifications
|
||||||
|
/// on iOS devices using the UserNotifications framework.
|
||||||
@objc(DailyNotificationPlugin)
|
@objc(DailyNotificationPlugin)
|
||||||
public class DailyNotificationPlugin: CAPPlugin {
|
public class DailyNotificationPlugin: CAPPlugin {
|
||||||
private let notificationCenter = UNUserNotificationCenter.current()
|
private let notificationCenter = UNUserNotificationCenter.current()
|
||||||
|
|
||||||
|
private var settings: [String: Any] = [
|
||||||
|
"sound": true,
|
||||||
|
"priority": "default",
|
||||||
|
"retryCount": 3,
|
||||||
|
"retryInterval": 1000
|
||||||
|
]
|
||||||
|
|
||||||
|
private static let CHANNEL_ID = "daily_notification_channel"
|
||||||
|
private static let CHANNEL_NAME = "Daily Notifications"
|
||||||
|
private static let CHANNEL_DESCRIPTION = "Daily notification updates"
|
||||||
|
|
||||||
|
/// Schedules a new daily notification
|
||||||
|
/// - Parameter call: The plugin call containing notification parameters
|
||||||
|
/// - Returns: Void
|
||||||
|
/// - Throws: DailyNotificationError
|
||||||
@objc func scheduleDailyNotification(_ call: CAPPluginCall) {
|
@objc func scheduleDailyNotification(_ call: CAPPluginCall) {
|
||||||
guard let url = call.getString("url"),
|
guard let url = call.getString("url"),
|
||||||
let time = call.getString("time") else {
|
let time = call.getString("time") else {
|
||||||
@@ -39,6 +58,7 @@ public class DailyNotificationPlugin: CAPPlugin {
|
|||||||
|
|
||||||
// Set priority
|
// Set priority
|
||||||
if let priority = call.getString("priority") {
|
if let priority = call.getString("priority") {
|
||||||
|
if #available(iOS 15.0, *) {
|
||||||
switch priority {
|
switch priority {
|
||||||
case "high":
|
case "high":
|
||||||
content.interruptionLevel = .timeSensitive
|
content.interruptionLevel = .timeSensitive
|
||||||
@@ -48,6 +68,17 @@ public class DailyNotificationPlugin: CAPPlugin {
|
|||||||
content.interruptionLevel = .active
|
content.interruptionLevel = .active
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to notification content setup
|
||||||
|
content.categoryIdentifier = "DAILY_NOTIFICATION"
|
||||||
|
let category = UNNotificationCategory(
|
||||||
|
identifier: "DAILY_NOTIFICATION",
|
||||||
|
actions: [],
|
||||||
|
intentIdentifiers: [],
|
||||||
|
options: .customDismissAction
|
||||||
|
)
|
||||||
|
notificationCenter.setNotificationCategories([category])
|
||||||
|
|
||||||
// Create trigger for daily notification
|
// Create trigger for daily notification
|
||||||
var dateComponents = DateComponents()
|
var dateComponents = DateComponents()
|
||||||
@@ -55,9 +86,23 @@ public class DailyNotificationPlugin: CAPPlugin {
|
|||||||
dateComponents.minute = minute
|
dateComponents.minute = minute
|
||||||
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
|
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
|
||||||
|
|
||||||
|
// Add check for past time and adjust to next day
|
||||||
|
let calendar = Calendar.current
|
||||||
|
var components = DateComponents()
|
||||||
|
components.hour = hour
|
||||||
|
components.minute = minute
|
||||||
|
components.second = 0
|
||||||
|
|
||||||
|
if let date = calendar.date(from: components),
|
||||||
|
date.timeIntervalSinceNow <= 0 {
|
||||||
|
components.day = calendar.component(.day, from: Date()) + 1
|
||||||
|
}
|
||||||
|
|
||||||
// Create request
|
// Create request
|
||||||
|
let identifier = String(format: "daily-notification-%d", (url as NSString).hash)
|
||||||
|
content.userInfo = ["url": url]
|
||||||
let request = UNNotificationRequest(
|
let request = UNNotificationRequest(
|
||||||
identifier: "daily-notification-\(url)",
|
identifier: identifier,
|
||||||
content: content,
|
content: content,
|
||||||
trigger: trigger
|
trigger: trigger
|
||||||
)
|
)
|
||||||
@@ -92,18 +137,192 @@ public class DailyNotificationPlugin: CAPPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc func getNotificationStatus(_ call: CAPPluginCall) {
|
@objc func getNotificationStatus(_ call: CAPPluginCall) {
|
||||||
notificationCenter.getPendingNotificationRequests { requests in
|
notificationCenter.getNotificationSettings { settings in
|
||||||
let nextNotification = requests.first
|
self.notificationCenter.getPendingNotificationRequests { requests in
|
||||||
let result: [String: Any] = [
|
var result: [String: Any] = [
|
||||||
"nextNotificationTime": nextNotification?.trigger?.nextTriggerDate?.timeIntervalSince1970 ?? 0,
|
"isEnabled": settings.authorizationStatus == .authorized,
|
||||||
"isEnabled": true // TODO: Check system notification settings
|
"pending": requests.count
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if let nextRequest = requests.first,
|
||||||
|
let trigger = nextRequest.trigger as? UNCalendarNotificationTrigger {
|
||||||
|
result["nextNotificationTime"] = trigger.nextTriggerDate()?.timeIntervalSince1970 ?? 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add current settings
|
||||||
|
result["settings"] = self.settings
|
||||||
|
|
||||||
call.resolve(result)
|
call.resolve(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@objc func updateSettings(_ call: CAPPluginCall) {
|
@objc func updateSettings(_ call: CAPPluginCall) {
|
||||||
// TODO: Implement settings update
|
if let sound = call.getBool("sound") {
|
||||||
call.resolve()
|
settings["sound"] = sound
|
||||||
|
}
|
||||||
|
|
||||||
|
if let priority = call.getString("priority") {
|
||||||
|
guard ["high", "default", "low"].contains(priority) else {
|
||||||
|
call.reject("Invalid priority value")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
settings["priority"] = priority
|
||||||
|
}
|
||||||
|
|
||||||
|
if let timezone = call.getString("timezone") {
|
||||||
|
guard TimeZone(identifier: timezone) != nil else {
|
||||||
|
call.reject("Invalid timezone")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
settings["timezone"] = timezone
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update any existing notifications with new settings
|
||||||
|
notificationCenter.getPendingNotificationRequests { [weak self] requests in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
for request in requests {
|
||||||
|
let content = request.content.mutableCopy() as! UNMutableNotificationContent
|
||||||
|
|
||||||
|
// Update notification content based on new settings
|
||||||
|
content.sound = self.settings["sound"] as! Bool ? .default : nil
|
||||||
|
|
||||||
|
if let priority = self.settings["priority"] as? String {
|
||||||
|
if #available(iOS 15.0, *) {
|
||||||
|
switch priority {
|
||||||
|
case "high": content.interruptionLevel = .timeSensitive
|
||||||
|
case "low": content.interruptionLevel = .passive
|
||||||
|
default: content.interruptionLevel = .active
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let newRequest = UNNotificationRequest(
|
||||||
|
identifier: request.identifier,
|
||||||
|
content: content,
|
||||||
|
trigger: request.trigger
|
||||||
|
)
|
||||||
|
|
||||||
|
self.notificationCenter.add(newRequest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
call.resolve(settings)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public override func checkPermissions(_ call: CAPPluginCall) {
|
||||||
|
notificationCenter.getNotificationSettings { settings in
|
||||||
|
var result: [String: Any] = [:]
|
||||||
|
|
||||||
|
// Convert authorization status
|
||||||
|
switch settings.authorizationStatus {
|
||||||
|
case .authorized:
|
||||||
|
result["status"] = "granted"
|
||||||
|
case .denied:
|
||||||
|
result["status"] = "denied"
|
||||||
|
case .provisional:
|
||||||
|
result["status"] = "provisional"
|
||||||
|
case .ephemeral:
|
||||||
|
result["status"] = "ephemeral"
|
||||||
|
default:
|
||||||
|
result["status"] = "unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add detailed settings
|
||||||
|
result["alert"] = settings.alertSetting == .enabled
|
||||||
|
result["badge"] = settings.badgeSetting == .enabled
|
||||||
|
result["sound"] = settings.soundSetting == .enabled
|
||||||
|
result["lockScreen"] = settings.lockScreenSetting == .enabled
|
||||||
|
result["carPlay"] = settings.carPlaySetting == .enabled
|
||||||
|
|
||||||
|
call.resolve(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public override func requestPermissions(_ call: CAPPluginCall) {
|
||||||
|
let options: UNAuthorizationOptions = [.alert, .sound, .badge]
|
||||||
|
|
||||||
|
notificationCenter.requestAuthorization(options: options) { granted, error in
|
||||||
|
if let error = error {
|
||||||
|
call.reject("Failed to request permissions: \(error.localizedDescription)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
call.resolve([
|
||||||
|
"granted": granted
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override func load() {
|
||||||
|
notificationCenter.delegate = self
|
||||||
|
}
|
||||||
|
|
||||||
|
private func isValidTime(_ time: String) -> Bool {
|
||||||
|
let timeComponents = time.split(separator: ":")
|
||||||
|
guard timeComponents.count == 2,
|
||||||
|
let hour = Int(timeComponents[0]),
|
||||||
|
let minute = Int(timeComponents[1]) else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return hour >= 0 && hour < 24 && minute >= 0 && minute < 60
|
||||||
|
}
|
||||||
|
|
||||||
|
private func isValidTimezone(_ identifier: String) -> Bool {
|
||||||
|
return TimeZone(identifier: identifier) != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
private func cleanupOldNotifications() {
|
||||||
|
let cutoffDate = Date().addingTimeInterval(-Double(DailyNotificationConfig.shared.retentionDays * 24 * 60 * 60))
|
||||||
|
notificationCenter.getDeliveredNotifications { notifications in
|
||||||
|
let oldNotifications = notifications.filter { $0.date < cutoffDate }
|
||||||
|
self.notificationCenter.removeDeliveredNotifications(withIdentifiers: oldNotifications.map { $0.request.identifier })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func setupNotificationChannel() {
|
||||||
|
// iOS doesn't use notification channels like Android
|
||||||
|
// This method is kept for API compatibility
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DailyNotificationPlugin: UNUserNotificationCenterDelegate {
|
||||||
|
public func userNotificationCenter(
|
||||||
|
_ center: UNUserNotificationCenter,
|
||||||
|
didReceive response: UNNotificationResponse,
|
||||||
|
withCompletionHandler completionHandler: @escaping () -> Void
|
||||||
|
) {
|
||||||
|
let notification = response.notification
|
||||||
|
let userInfo = notification.request.content.userInfo
|
||||||
|
|
||||||
|
// Create notification event data
|
||||||
|
let eventData: [String: Any] = [
|
||||||
|
"id": notification.request.identifier,
|
||||||
|
"title": notification.request.content.title,
|
||||||
|
"body": notification.request.content.body,
|
||||||
|
"action": response.actionIdentifier,
|
||||||
|
"data": userInfo
|
||||||
|
]
|
||||||
|
|
||||||
|
// Notify JavaScript
|
||||||
|
notifyListeners("notification", data: eventData)
|
||||||
|
|
||||||
|
completionHandler()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle notifications when app is in foreground
|
||||||
|
public func userNotificationCenter(
|
||||||
|
_ center: UNUserNotificationCenter,
|
||||||
|
willPresent notification: UNNotification,
|
||||||
|
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
|
||||||
|
) {
|
||||||
|
var presentationOptions: UNNotificationPresentationOptions = []
|
||||||
|
if #available(iOS 14.0, *) {
|
||||||
|
presentationOptions = [.banner, .sound, .badge]
|
||||||
|
} else {
|
||||||
|
presentationOptions = [.alert, .sound, .badge]
|
||||||
|
}
|
||||||
|
completionHandler(presentationOptions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
19
ios/Podfile
Normal file
19
ios/Podfile
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
platform :ios, '13.0'
|
||||||
|
use_frameworks!
|
||||||
|
|
||||||
|
source 'https://cdn.cocoapods.org/'
|
||||||
|
|
||||||
|
def capacitor_pods
|
||||||
|
pod 'Capacitor', :path => '../node_modules/@capacitor/ios'
|
||||||
|
pod 'CapacitorCordova', :path => '../node_modules/@capacitor/ios'
|
||||||
|
end
|
||||||
|
|
||||||
|
target 'DailyNotificationPlugin' do
|
||||||
|
capacitor_pods
|
||||||
|
pod 'DailyNotificationPlugin', :path => '.'
|
||||||
|
end
|
||||||
|
|
||||||
|
target 'DailyNotificationPluginTests' do
|
||||||
|
capacitor_pods
|
||||||
|
pod 'DailyNotificationPlugin', :path => '.'
|
||||||
|
end
|
||||||
29
ios/Podfile.lock
Normal file
29
ios/Podfile.lock
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
PODS:
|
||||||
|
- Capacitor (5.0.0):
|
||||||
|
- CapacitorCordova
|
||||||
|
- CapacitorCordova (5.0.0)
|
||||||
|
- DailyNotificationPlugin (1.0.0):
|
||||||
|
- Capacitor
|
||||||
|
- CapacitorCordova
|
||||||
|
|
||||||
|
DEPENDENCIES:
|
||||||
|
- "Capacitor (from `../node_modules/@capacitor/ios`)"
|
||||||
|
- "CapacitorCordova (from `../node_modules/@capacitor/ios`)"
|
||||||
|
- DailyNotificationPlugin (from `.`)
|
||||||
|
|
||||||
|
EXTERNAL SOURCES:
|
||||||
|
Capacitor:
|
||||||
|
:path: "../node_modules/@capacitor/ios"
|
||||||
|
CapacitorCordova:
|
||||||
|
:path: "../node_modules/@capacitor/ios"
|
||||||
|
DailyNotificationPlugin:
|
||||||
|
:path: "."
|
||||||
|
|
||||||
|
SPEC CHECKSUMS:
|
||||||
|
Capacitor: ba8cd5cce13c6ab3c4faf7ef98487be481c9c1c8
|
||||||
|
CapacitorCordova: 4ea17670ee562680988a7ce9db68dee5160fe564
|
||||||
|
DailyNotificationPlugin: 59b7578061086ff48fd72151c36cdbd90f004bf5
|
||||||
|
|
||||||
|
PODFILE CHECKSUM: ac8c229d24347f6f83e67e6b95458e0b81e68f7c
|
||||||
|
|
||||||
|
COCOAPODS: 1.16.2
|
||||||
29
ios/Tests/DailyNotificationTests.swift
Normal file
29
ios/Tests/DailyNotificationTests.swift
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import XCTest
|
||||||
|
@testable import Plugin
|
||||||
|
|
||||||
|
class DailyNotificationTests: XCTestCase {
|
||||||
|
var plugin: DailyNotificationPlugin!
|
||||||
|
|
||||||
|
override func setUp() {
|
||||||
|
super.setUp()
|
||||||
|
plugin = DailyNotificationPlugin()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testTimeValidation() {
|
||||||
|
// Valid time
|
||||||
|
XCTAssertTrue(plugin.isValidTime("09:00"))
|
||||||
|
|
||||||
|
// Invalid times
|
||||||
|
XCTAssertFalse(plugin.isValidTime("25:00"))
|
||||||
|
XCTAssertFalse(plugin.isValidTime("09:60"))
|
||||||
|
XCTAssertFalse(plugin.isValidTime("9:00"))
|
||||||
|
XCTAssertFalse(plugin.isValidTime("0900"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func testTimezoneValidation() {
|
||||||
|
XCTAssertTrue(plugin.isValidTimezone("America/New_York"))
|
||||||
|
XCTAssertFalse(plugin.isValidTimezone("Invalid/Timezone"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add more tests...
|
||||||
|
}
|
||||||
52
ios/project.yml
Normal file
52
ios/project.yml
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
name: DailyNotificationPlugin
|
||||||
|
options:
|
||||||
|
bundleIdPrefix: com.timesafari
|
||||||
|
deploymentTarget:
|
||||||
|
iOS: 13.0
|
||||||
|
schemes:
|
||||||
|
DailyNotificationPlugin:
|
||||||
|
build:
|
||||||
|
targets:
|
||||||
|
DailyNotificationPlugin: all
|
||||||
|
run:
|
||||||
|
config: Debug
|
||||||
|
test:
|
||||||
|
targets:
|
||||||
|
- DailyNotificationPluginTests
|
||||||
|
config: Debug
|
||||||
|
profile:
|
||||||
|
config: Release
|
||||||
|
analyze:
|
||||||
|
config: Debug
|
||||||
|
archive:
|
||||||
|
config: Release
|
||||||
|
DailyNotificationPluginTests:
|
||||||
|
build:
|
||||||
|
targets:
|
||||||
|
DailyNotificationPluginTests: all
|
||||||
|
test:
|
||||||
|
targets:
|
||||||
|
- DailyNotificationPluginTests
|
||||||
|
config: Debug
|
||||||
|
targets:
|
||||||
|
DailyNotificationPlugin:
|
||||||
|
type: framework
|
||||||
|
platform: iOS
|
||||||
|
sources:
|
||||||
|
- path: Plugin
|
||||||
|
settings:
|
||||||
|
base:
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER: com.timesafari.dailynotification
|
||||||
|
DEVELOPMENT_TEAM: "" # Add your team ID here
|
||||||
|
dependencies: []
|
||||||
|
DailyNotificationPluginTests:
|
||||||
|
type: bundle.unit-test
|
||||||
|
platform: iOS
|
||||||
|
sources:
|
||||||
|
- path: Tests
|
||||||
|
dependencies:
|
||||||
|
- target: DailyNotificationPlugin
|
||||||
|
settings:
|
||||||
|
base:
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER: com.timesafari.dailynotification.tests
|
||||||
|
DEVELOPMENT_TEAM: "" # Add your team ID here
|
||||||
12
package-lock.json
generated
12
package-lock.json
generated
@@ -11,7 +11,8 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@capacitor/android": "^5.0.0",
|
"@capacitor/android": "^5.0.0",
|
||||||
"@capacitor/core": "^5.0.0"
|
"@capacitor/core": "^5.0.0",
|
||||||
|
"@capacitor/ios": "^5.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@capacitor/cli": "^5.0.0",
|
"@capacitor/cli": "^5.0.0",
|
||||||
@@ -702,6 +703,15 @@
|
|||||||
"tslib": "^2.1.0"
|
"tslib": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@capacitor/ios": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-b1edQNe1cKiqnxoIR5WxbVjDlf3RWr2ZjaDxwEuBzwBAvvrFcweKdbw1ij45DWHKODaIymWoyAlAUN+vFOF5sw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@capacitor/core": "^5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@eslint-community/eslint-utils": {
|
"node_modules/@eslint-community/eslint-utils": {
|
||||||
"version": "4.5.1",
|
"version": "4.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.5.1.tgz",
|
||||||
|
|||||||
@@ -29,7 +29,8 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@capacitor/android": "^5.0.0",
|
"@capacitor/android": "^5.0.0",
|
||||||
"@capacitor/core": "^5.0.0"
|
"@capacitor/core": "^5.0.0",
|
||||||
|
"@capacitor/ios": "^5.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@capacitor/cli": "^5.0.0",
|
"@capacitor/cli": "^5.0.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user