diff --git a/test-apps/daily-notification-test/README.md b/test-apps/daily-notification-test/README.md
index 481a471..b915fc1 100644
--- a/test-apps/daily-notification-test/README.md
+++ b/test-apps/daily-notification-test/README.md
@@ -31,20 +31,57 @@ npm install
**Note**: The `postinstall` script automatically fixes Capacitor configuration files after installation.
-### Capacitor Sync (Android)
+## Building for Android and iOS
+
+### Quick Build (Recommended)
+
+Use the unified build script for both platforms:
+
+```bash
+# Build and run both platforms on emulator/simulator
+./scripts/build.sh --run
+
+# Build both platforms (no run)
+./scripts/build.sh
+
+# Build Android only
+./scripts/build.sh --android
+
+# Build iOS only
+./scripts/build.sh --ios
+
+# Build and run Android on emulator
+./scripts/build.sh --run-android
+
+# Build and run iOS on simulator
+./scripts/build.sh --run-ios
+```
+
+**See**: `docs/BUILD_QUICK_REFERENCE.md` for detailed build instructions.
+
+### Manual Build Steps
+
+#### Capacitor Sync
**Important**: Use the wrapper script instead of `npx cap sync` directly to automatically fix plugin paths:
```sh
+# Sync both platforms
npm run cap:sync
+
+# Sync Android only
+npm run cap:sync:android
+
+# Sync iOS only
+npm run cap:sync:ios
```
This will:
-1. Run `npx cap sync android`
+1. Run `npx cap sync` (or platform-specific sync)
2. Automatically fix `capacitor.settings.gradle` (corrects plugin path from `android/` to `android/plugin/`)
3. Ensure `capacitor.plugins.json` has the correct plugin registration
-If you run `npx cap sync android` directly, you can manually fix afterward:
+If you run `npx cap sync` directly, you can manually fix afterward:
```sh
node scripts/fix-capacitor-plugins.js
```
diff --git a/test-apps/daily-notification-test/docs/BUILD_QUICK_REFERENCE.md b/test-apps/daily-notification-test/docs/BUILD_QUICK_REFERENCE.md
index ff4d267..ff05319 100644
--- a/test-apps/daily-notification-test/docs/BUILD_QUICK_REFERENCE.md
+++ b/test-apps/daily-notification-test/docs/BUILD_QUICK_REFERENCE.md
@@ -1,48 +1,195 @@
# Build Process Quick Reference
**Author**: Matthew Raymer
-**Date**: October 17, 2025
+**Date**: October 17, 2025
+**Last Updated**: November 19, 2025
+
+## ā” Quick Start
+
+**Easiest way to build and run:**
+
+```bash
+# Build and run both platforms
+./scripts/build.sh --run
+
+# Or build only
+./scripts/build.sh
+```
+
+This script handles everything automatically! See [Unified Build Script](#-unified-build-script-recommended) section for all options.
+
+---
## šØ Critical Build Steps
+### Prerequisites
+
+**Required for All Platforms:**
+- Node.js 20.19.0+ or 22.12.0+
+- npm (comes with Node.js)
+- Plugin must be built (`npm run build` in plugin root directory)
+ - The build script will automatically build the plugin if `dist/` doesn't exist
+
+**For Android:**
+- Java JDK 22.12 or later
+- Android SDK (with `adb` in PATH)
+- Gradle (comes with Android project)
+
+**For iOS:**
+- macOS with Xcode (xcodebuild must be in PATH)
+- CocoaPods (`pod --version` to check)
+ - Can be installed via rbenv (script handles this automatically)
+- iOS deployment target: iOS 13.0+
+
+**Plugin Requirements:**
+- Plugin podspec must exist at: `node_modules/@timesafari/daily-notification-plugin/ios/DailyNotificationPlugin.podspec`
+- Plugin must be installed: `npm install` (uses `file:../../` reference)
+- Plugin must be built: `npm run build` in plugin root (creates `dist/` directory)
+
+### Initial Setup (One-Time)
+
```bash
-# 1. Build web assets
+# 1. Install dependencies (includes @capacitor/ios)
+npm install
+
+# 2. Add iOS platform (if not already added)
+npx cap add ios
+
+# 3. Install iOS dependencies
+cd ios/App
+pod install
+cd ../..
+```
+
+### Build for Both Platforms
+
+```bash
+# 1. Build web assets (required for both platforms)
npm run build
-# 2. Sync with native projects (automatically fixes plugin paths)
+# 2. Sync with native projects (syncs both Android and iOS)
npm run cap:sync
-# 3. Build and deploy Android
+# OR sync platforms individually:
+# npm run cap:sync:android # Android only
+# npm run cap:sync:ios # iOS only
+```
+
+### Android Build
+
+```bash
+# Build Android APK
cd android
./gradlew :app:assembleDebug
+
+# Install on device/emulator
adb install -r app/build/outputs/apk/debug/app-debug.apk
+
+# Launch app
adb shell am start -n com.timesafari.dailynotification.test/.MainActivity
```
+### iOS Build
+
+```bash
+# Open in Xcode
+cd ios/App
+open App.xcworkspace
+
+# Or build from command line
+xcodebuild -workspace App.xcworkspace \
+ -scheme App \
+ -configuration Debug \
+ -sdk iphonesimulator \
+ -destination 'platform=iOS Simulator,name=iPhone 15' \
+ build
+
+# Or use Capacitor CLI
+npx cap run ios
+```
+
## ā ļø Why `npm run cap:sync` is Important
**Problem**: `npx cap sync` overwrites `capacitor.plugins.json` and `capacitor.settings.gradle` with incorrect paths.
**Solution**: The `cap:sync` script automatically:
-1. Runs `npx cap sync android`
+1. Runs `npx cap sync` (syncs both Android and iOS)
2. Fixes `capacitor.settings.gradle` (corrects plugin path from `android/` to `android/plugin/`)
3. Restores the DailyNotification plugin entry in `capacitor.plugins.json`
+**Platform-specific sync:**
+- `npm run cap:sync:android` - Syncs Android only (includes fix script)
+- `npm run cap:sync:ios` - Syncs iOS only (no fix needed for iOS)
+
**Without the fix**: Plugin detection fails, build errors occur, "simplified dialog" appears.
## š Verification Checklist
-After build, verify:
+### Android Verification
-- [ ] `capacitor.plugins.json` contains DailyNotification entry
+After Android build, verify:
+
+- [ ] `android/app/src/main/assets/capacitor.plugins.json` contains DailyNotification entry
- [ ] System Status shows "Plugin: Available" (green)
- [ ] Plugin Diagnostics shows all 4 plugins
- [ ] Click events work on ActionCard components
- [ ] No "simplified dialog" appears
-## š ļø Automated Build Script
+### iOS Verification
-Create `scripts/build-and-deploy.sh`:
+After iOS build, verify:
+
+- [ ] iOS project exists at `ios/App/App.xcworkspace`
+- [ ] CocoaPods installed (`pod install` completed successfully)
+- [ ] Plugin framework linked in Xcode project
+- [ ] App builds without errors in Xcode
+- [ ] Plugin methods accessible from JavaScript
+- [ ] System Status shows "Plugin: Available" (green)
+
+## š ļø Automated Build Scripts
+
+### Unified Build Script (Recommended)
+
+The project includes a comprehensive build script that handles both platforms:
+
+```bash
+# Build both platforms
+./scripts/build.sh
+
+# Build Android only
+./scripts/build.sh --android
+
+# Build iOS only
+./scripts/build.sh --ios
+
+# Build and run Android on emulator
+./scripts/build.sh --run-android
+
+# Build and run iOS on simulator
+./scripts/build.sh --run-ios
+
+# Build and run both platforms
+./scripts/build.sh --run
+
+# Show help
+./scripts/build.sh --help
+```
+
+**Features:**
+- ā
Automatically builds web assets
+- ā
Syncs Capacitor with both platforms
+- ā
Builds Android APK
+- ā
Builds iOS app for simulator
+- ā
Automatically finds and uses available emulator/simulator
+- ā
Installs and launches apps when using `--run` flags
+- ā
Color-coded output for easy reading
+- ā
Comprehensive error handling
+
+### Manual Build Scripts
+
+#### Build for Android
+
+Create `scripts/build-android.sh`:
```bash
#!/bin/bash
@@ -52,7 +199,7 @@ echo "šØ Building web assets..."
npm run build
echo "š Syncing with native projects..."
-npm run cap:sync
+npm run cap:sync:android
# This automatically syncs and fixes plugin paths
echo "šļø Building Android app..."
@@ -63,7 +210,64 @@ echo "š± Installing and launching..."
adb install -r app/build/outputs/apk/debug/app-debug.apk
adb shell am start -n com.timesafari.dailynotification.test/.MainActivity
-echo "ā
Build and deploy complete!"
+echo "ā
Android build and deploy complete!"
+```
+
+### Build for iOS
+
+Create `scripts/build-ios.sh`:
+
+```bash
+#!/bin/bash
+set -e
+
+echo "šØ Building web assets..."
+npm run build
+
+echo "š Syncing with iOS..."
+npm run cap:sync:ios
+
+echo "š Building iOS app..."
+cd ios/App
+pod install
+xcodebuild -workspace App.xcworkspace \
+ -scheme App \
+ -configuration Debug \
+ -sdk iphonesimulator \
+ -destination 'platform=iOS Simulator,name=iPhone 15' \
+ build
+
+echo "ā
iOS build complete!"
+echo "š± Open Xcode to run on simulator: open App.xcworkspace"
+```
+
+### Build for Both Platforms
+
+Create `scripts/build-all.sh`:
+
+```bash
+#!/bin/bash
+set -e
+
+echo "šØ Building web assets..."
+npm run build
+
+echo "š Syncing with all native projects..."
+npm run cap:sync
+
+echo "šļø Building Android..."
+cd android && ./gradlew :app:assembleDebug && cd ..
+
+echo "š Building iOS..."
+cd ios/App && pod install && cd ../..
+xcodebuild -workspace ios/App/App.xcworkspace \
+ -scheme App \
+ -configuration Debug \
+ -sdk iphonesimulator \
+ -destination 'platform=iOS Simulator,name=iPhone 15' \
+ build
+
+echo "ā
All platforms built successfully!"
```
## š Common Issues
@@ -74,9 +278,15 @@ echo "ā
Build and deploy complete!"
| Plugin not detected | "Plugin: Not Available" (red) | Check plugin registry, rebuild |
| Click events not working | Buttons don't respond | Check Vue 3 compatibility, router config |
| Inconsistent status | Different status in different cards | Use consistent detection logic |
+| **No podspec found** | `[!] No podspec found for 'TimesafariDailyNotificationPlugin'` | Run `node scripts/fix-capacitor-plugins.js` to fix Podfile, then `pod install` |
+| **Plugin not built** | Vite build fails: "Failed to resolve entry" | Run `npm run build` in plugin root directory (`../../`) |
+| **CocoaPods not found** | `pod: command not found` | Install CocoaPods: `sudo gem install cocoapods` or via rbenv |
+| **Xcode not found** | `xcodebuild: command not found` | Install Xcode from App Store, run `xcode-select --install` |
## š± Testing Commands
+### Android Testing
+
```bash
# Check plugin registry
cat android/app/src/main/assets/capacitor.plugins.json
@@ -86,8 +296,38 @@ adb logcat | grep -i "dailynotification\|capacitor\|plugin"
# Check app installation
adb shell pm list packages | grep dailynotification
+
+# View app logs
+adb logcat -s DailyNotification
+```
+
+### iOS Testing
+
+```bash
+# Check if iOS project exists
+ls -la ios/App/App.xcworkspace
+
+# Check CocoaPods installation
+cd ios/App && pod install && cd ../..
+
+# Monitor iOS logs (simulator)
+xcrun simctl spawn booted log stream | grep -i "dailynotification\|capacitor\|plugin"
+
+# Check plugin in Xcode
+# Open ios/App/App.xcworkspace in Xcode
+# Check: Project Navigator ā Frameworks ā DailyNotificationPlugin.framework
+
+# View device logs (physical device)
+# Xcode ā Window ā Devices and Simulators ā Select device ā Open Console
```
---
-**Remember**: Use `npm run cap:sync` instead of `npx cap sync android` directly - it automatically fixes the configuration files!
+## š Important Notes
+
+**Remember**:
+- Use `npm run cap:sync` to sync both platforms (automatically fixes Android configuration files)
+- Use `npm run cap:sync:android` for Android-only sync (includes fix script)
+- Use `npm run cap:sync:ios` for iOS-only sync
+- Always run `npm run build` before syncing to ensure latest web assets are copied
+- For iOS: Run `pod install` in `ios/App/` after first sync or when dependencies change
diff --git a/test-apps/daily-notification-test/ios/App/App/Info.plist b/test-apps/daily-notification-test/ios/App/App/Info.plist
new file mode 100644
index 0000000..9978563
--- /dev/null
+++ b/test-apps/daily-notification-test/ios/App/App/Info.plist
@@ -0,0 +1,62 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleDisplayName
+ Daily Notification Test
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ $(MARKETING_VERSION)
+ CFBundleVersion
+ $(CURRENT_PROJECT_VERSION)
+ LSRequiresIPhoneOS
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Main
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UIViewControllerBasedStatusBarAppearance
+
+ BGTaskSchedulerPermittedIdentifiers
+
+ com.timesafari.dailynotification.fetch
+ com.timesafari.dailynotification.notify
+
+ UIBackgroundModes
+
+ background-fetch
+ background-processing
+ remote-notification
+
+ NSUserNotificationsUsageDescription
+ This app uses notifications to deliver daily updates and reminders.
+
+
diff --git a/test-apps/daily-notification-test/package-lock.json b/test-apps/daily-notification-test/package-lock.json
index 575d83e..609c34d 100644
--- a/test-apps/daily-notification-test/package-lock.json
+++ b/test-apps/daily-notification-test/package-lock.json
@@ -45,7 +45,7 @@
},
"../..": {
"name": "@timesafari/daily-notification-plugin",
- "version": "1.0.0",
+ "version": "1.0.11",
"license": "MIT",
"workspaces": [
"packages/*"
diff --git a/test-apps/daily-notification-test/package.json b/test-apps/daily-notification-test/package.json
index 74e4260..8946f48 100644
--- a/test-apps/daily-notification-test/package.json
+++ b/test-apps/daily-notification-test/package.json
@@ -13,11 +13,14 @@
"build-only": "vite build",
"type-check": "vue-tsc --build",
"lint": "eslint . --fix",
- "cap:sync": "npx cap sync android && node scripts/fix-capacitor-plugins.js",
+ "cap:sync": "npx cap sync && node scripts/fix-capacitor-plugins.js",
+ "cap:sync:android": "npx cap sync android && node scripts/fix-capacitor-plugins.js",
+ "cap:sync:ios": "npx cap sync ios",
"postinstall": "node scripts/fix-capacitor-plugins.js"
},
"dependencies": {
"@capacitor/android": "^6.2.1",
+ "@capacitor/ios": "^6.2.1",
"@capacitor/cli": "^6.2.1",
"@capacitor/core": "^6.2.1",
"@timesafari/daily-notification-plugin": "file:../../",
diff --git a/test-apps/daily-notification-test/scripts/build.sh b/test-apps/daily-notification-test/scripts/build.sh
new file mode 100755
index 0000000..23baab9
--- /dev/null
+++ b/test-apps/daily-notification-test/scripts/build.sh
@@ -0,0 +1,569 @@
+#!/bin/bash
+
+# Build script for daily-notification-test Capacitor app
+# Supports both Android and iOS with emulator/simulator deployment
+#
+# Requirements:
+# - Node.js 20.19.0+ or 22.12.0+
+# - npm
+# - Plugin must be built (script will auto-build if needed)
+# - For Android: Java JDK 22.12+, Android SDK (adb)
+# - For iOS: Xcode, CocoaPods (pod)
+#
+# Usage:
+# ./scripts/build.sh # Build both platforms
+# ./scripts/build.sh --android # Build Android only
+# ./scripts/build.sh --ios # Build iOS only
+# ./scripts/build.sh --run # Build and run both
+# ./scripts/build.sh --help # Show help
+
+set -e
+
+# Colors for output
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+BLUE='\033[0;34m'
+NC='\033[0m' # No Color
+
+# Script directory
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
+
+# Logging functions
+log_info() {
+ echo -e "${GREEN}[INFO]${NC} $1"
+}
+
+log_warn() {
+ echo -e "${YELLOW}[WARN]${NC} $1"
+}
+
+log_error() {
+ echo -e "${RED}[ERROR]${NC} $1"
+}
+
+log_step() {
+ echo -e "${BLUE}[STEP]${NC} $1"
+}
+
+# Validation functions
+check_command() {
+ if ! command -v $1 &> /dev/null; then
+ log_error "$1 is not installed. Please install it first."
+ exit 1
+ fi
+}
+
+# Get pod command (handles rbenv)
+get_pod_command() {
+ if command -v pod &> /dev/null; then
+ echo "pod"
+ elif [ -f "$HOME/.rbenv/shims/pod" ]; then
+ echo "$HOME/.rbenv/shims/pod"
+ else
+ log_error "CocoaPods (pod) not found. Please install CocoaPods first."
+ exit 1
+ fi
+}
+
+# Check requirements
+check_requirements() {
+ log_step "Checking build requirements..."
+
+ local missing_requirements=false
+
+ # Check Node.js
+ if ! command -v node &> /dev/null; then
+ log_error "Node.js is not installed. Please install Node.js 20.19.0+ or 22.12.0+"
+ missing_requirements=true
+ else
+ log_info "ā
Node.js: $(node --version)"
+ fi
+
+ # Check npm
+ if ! command -v npm &> /dev/null; then
+ log_error "npm is not installed"
+ missing_requirements=true
+ else
+ log_info "ā
npm: $(npm --version)"
+ fi
+
+ # Check plugin is built
+ PLUGIN_ROOT="$(cd "$PROJECT_DIR/../.." && pwd)"
+ if [ ! -d "$PLUGIN_ROOT/dist" ]; then
+ log_warn "Plugin not built. Building plugin now..."
+ cd "$PLUGIN_ROOT"
+ if npm run build; then
+ log_info "ā
Plugin built successfully"
+ else
+ log_error "Failed to build plugin. Please run 'npm run build' in the plugin root directory."
+ missing_requirements=true
+ fi
+ cd "$PROJECT_DIR"
+ else
+ log_info "ā
Plugin built (dist/ exists)"
+ fi
+
+ # Check Android requirements if building Android
+ if [ "$BUILD_ALL" = true ] || [ "$BUILD_ANDROID" = true ]; then
+ if ! command -v adb &> /dev/null; then
+ log_warn "Android SDK not found (adb not in PATH). Android build will be skipped."
+ else
+ log_info "ā
Android SDK: $(adb version | head -1)"
+ fi
+
+ if ! command -v java &> /dev/null; then
+ log_warn "Java not found. Android build may fail."
+ else
+ log_info "ā
Java: $(java -version 2>&1 | head -1)"
+ fi
+ fi
+
+ # Check iOS requirements if building iOS
+ if [ "$BUILD_ALL" = true ] || [ "$BUILD_IOS" = true ]; then
+ if ! command -v xcodebuild &> /dev/null; then
+ log_warn "Xcode not found (xcodebuild not in PATH). iOS build will be skipped."
+ else
+ log_info "ā
Xcode: $(xcodebuild -version | head -1)"
+ fi
+
+ POD_CMD=$(get_pod_command 2>/dev/null || echo "")
+ if [ -z "$POD_CMD" ]; then
+ log_warn "CocoaPods not found. iOS build will be skipped."
+ else
+ log_info "ā
CocoaPods: $($POD_CMD --version 2>/dev/null || echo 'found')"
+ fi
+ fi
+
+ if [ "$missing_requirements" = true ]; then
+ log_error "Missing required dependencies. Please install them and try again."
+ exit 1
+ fi
+
+ log_info "All requirements satisfied"
+}
+
+# Parse arguments
+BUILD_ANDROID=false
+BUILD_IOS=false
+BUILD_ALL=true
+RUN_ANDROID=false
+RUN_IOS=false
+RUN_ALL=false
+
+while [[ $# -gt 0 ]]; do
+ case $1 in
+ --android)
+ BUILD_ANDROID=true
+ BUILD_ALL=false
+ shift
+ ;;
+ --ios)
+ BUILD_IOS=true
+ BUILD_ALL=false
+ shift
+ ;;
+ --run-android)
+ RUN_ANDROID=true
+ BUILD_ANDROID=true
+ BUILD_ALL=false
+ shift
+ ;;
+ --run-ios)
+ RUN_IOS=true
+ BUILD_IOS=true
+ BUILD_ALL=false
+ shift
+ ;;
+ --run)
+ RUN_ALL=true
+ BUILD_ALL=true
+ shift
+ ;;
+ --help|-h)
+ echo "Usage: $0 [OPTIONS]"
+ echo ""
+ echo "Options:"
+ echo " --android Build Android only"
+ echo " --ios Build iOS only"
+ echo " --run-android Build and run Android on emulator"
+ echo " --run-ios Build and run iOS on simulator"
+ echo " --run Build and run both platforms"
+ echo " --help, -h Show this help message"
+ echo ""
+ echo "Default: Build both platforms (no run)"
+ exit 0
+ ;;
+ *)
+ log_error "Unknown option: $1"
+ echo "Use --help for usage information"
+ exit 1
+ ;;
+ esac
+done
+
+# Change to project directory
+cd "$PROJECT_DIR"
+
+log_info "Building daily-notification-test app"
+log_info "Project directory: $PROJECT_DIR"
+
+# Check requirements
+check_requirements
+
+# Step 1: Build web assets
+log_step "Building web assets..."
+if ! npm run build; then
+ log_error "Web build failed"
+ exit 1
+fi
+log_info "Web assets built successfully"
+
+# Step 2: Sync Capacitor
+log_step "Syncing Capacitor with native projects..."
+if ! npm run cap:sync; then
+ log_error "Capacitor sync failed"
+ exit 1
+fi
+log_info "Capacitor sync completed"
+
+# Step 2.5: Ensure fix script ran (it should have via cap:sync, but verify for iOS)
+if [ "$BUILD_ALL" = true ] || [ "$BUILD_IOS" = true ]; then
+ if [ -d "$PROJECT_DIR/ios" ]; then
+ log_step "Verifying iOS Podfile configuration..."
+ if node "$PROJECT_DIR/scripts/fix-capacitor-plugins.js" 2>/dev/null; then
+ log_info "iOS Podfile verified"
+ fi
+ fi
+fi
+
+# Android build
+if [ "$BUILD_ALL" = true ] || [ "$BUILD_ANDROID" = true ]; then
+ log_step "Building Android app..."
+
+ # Check for Android SDK
+ if ! command -v adb &> /dev/null; then
+ log_warn "adb not found. Android SDK may not be installed."
+ log_warn "Skipping Android build. Install Android SDK to build Android."
+ else
+ cd "$PROJECT_DIR/android"
+
+ # Build APK
+ if ./gradlew :app:assembleDebug; then
+ log_info "Android APK built successfully"
+
+ APK_PATH="$PROJECT_DIR/android/app/build/outputs/apk/debug/app-debug.apk"
+
+ if [ -f "$APK_PATH" ]; then
+ log_info "APK location: $APK_PATH"
+
+ # Run on emulator if requested
+ if [ "$RUN_ALL" = true ] || [ "$RUN_ANDROID" = true ]; then
+ log_step "Installing and launching Android app..."
+
+ # Check for running emulator
+ if ! adb devices | grep -q "device$"; then
+ log_warn "No Android emulator/device found"
+ log_info "Please start an Android emulator and try again"
+ log_info "Or use: adb devices to check connected devices"
+ else
+ # Install APK
+ if adb install -r "$APK_PATH"; then
+ log_info "APK installed successfully"
+
+ # Launch app
+ if adb shell am start -n com.timesafari.dailynotification.test/.MainActivity; then
+ log_info "ā
Android app launched successfully!"
+ else
+ log_warn "Failed to launch app (may already be running)"
+ fi
+ else
+ log_warn "APK installation failed (may already be installed)"
+ fi
+ fi
+ fi
+ else
+ log_error "APK not found at expected location: $APK_PATH"
+ fi
+ else
+ log_error "Android build failed"
+ exit 1
+ fi
+
+ cd "$PROJECT_DIR"
+ fi
+fi
+
+# iOS build
+if [ "$BUILD_ALL" = true ] || [ "$BUILD_IOS" = true ]; then
+ log_step "Building iOS app..."
+
+ # Check for Xcode
+ if ! command -v xcodebuild &> /dev/null; then
+ log_warn "xcodebuild not found. Xcode may not be installed."
+ log_warn "Skipping iOS build. Install Xcode to build iOS."
+ else
+ IOS_DIR="$PROJECT_DIR/ios/App"
+
+ if [ ! -d "$IOS_DIR" ]; then
+ log_warn "iOS directory not found. Adding iOS platform..."
+ cd "$PROJECT_DIR"
+ npx cap add ios
+ fi
+
+ cd "$IOS_DIR"
+
+ # Install CocoaPods dependencies
+ log_step "Installing CocoaPods dependencies..."
+ POD_CMD=$(get_pod_command)
+
+ # Check if Podfile exists and has correct plugin reference
+ if [ -f "$IOS_DIR/Podfile" ]; then
+ # Run fix script to ensure Podfile is correct
+ log_step "Verifying Podfile configuration..."
+ if node "$PROJECT_DIR/scripts/fix-capacitor-plugins.js" 2>/dev/null; then
+ log_info "Podfile verified"
+ fi
+ fi
+
+ if $POD_CMD install; then
+ log_info "CocoaPods dependencies installed"
+ else
+ log_error "CocoaPods install failed"
+ log_info "Troubleshooting:"
+ log_info "1. Check that plugin podspec exists: ls -la $PLUGIN_ROOT/ios/DailyNotificationPlugin.podspec"
+ log_info "2. Verify Podfile references: pod 'DailyNotificationPlugin', :path => '../../node_modules/@timesafari/daily-notification-plugin/ios'"
+ log_info "3. Run fix script: node scripts/fix-capacitor-plugins.js"
+ exit 1
+ fi
+
+ # Find workspace
+ WORKSPACE="$IOS_DIR/App.xcworkspace"
+ if [ ! -d "$WORKSPACE" ]; then
+ WORKSPACE="$IOS_DIR/App.xcodeproj"
+ fi
+
+ if [ ! -d "$WORKSPACE" ]; then
+ log_error "Xcode workspace/project not found at $IOS_DIR"
+ exit 1
+ fi
+
+ # Get simulator
+ log_step "Finding available iOS simulator..."
+
+ # Method 1: Use xcodebuild to get available destinations (most reliable)
+ # This gives us the exact format xcodebuild expects
+ DESTINATION_STRING=$(xcodebuild -workspace "$WORKSPACE" -scheme App -showdestinations 2>/dev/null | \
+ grep "iOS Simulator" | \
+ grep -i "iphone" | \
+ grep -v "iPhone Air" | \
+ head -1)
+
+ if [ -n "$DESTINATION_STRING" ]; then
+ # Extract name from destination string
+ # Format: "platform=iOS Simulator,id=...,name=iPhone 17 Pro,OS=26.0.1"
+ SIMULATOR=$(echo "$DESTINATION_STRING" | \
+ sed -n 's/.*name=\([^,]*\).*/\1/p' | \
+ sed 's/[[:space:]]*$//')
+ log_info "Found simulator via xcodebuild: $SIMULATOR"
+ fi
+
+ # Method 2: Fallback to simctl if xcodebuild didn't work
+ if [ -z "$SIMULATOR" ] || [ "$SIMULATOR" = "Shutdown" ] || [ "$SIMULATOR" = "Booted" ]; then
+ # Use simctl list in JSON format for more reliable parsing
+ # This avoids parsing status words like "Shutdown"
+ SIMULATOR_JSON=$(xcrun simctl list devices available --json 2>/dev/null)
+
+ if [ -n "$SIMULATOR_JSON" ]; then
+ # Extract first iPhone device name using jq if available, or grep/sed
+ if command -v jq &> /dev/null; then
+ SIMULATOR=$(echo "$SIMULATOR_JSON" | \
+ jq -r '.devices | to_entries[] | .value[] | select(.name | test("iPhone"; "i")) | .name' | \
+ grep -v "iPhone Air" | \
+ head -1)
+ else
+ # Fallback: parse text output more carefully
+ # Get line with iPhone, extract name before first parenthesis
+ SIMULATOR_LINE=$(xcrun simctl list devices available 2>/dev/null | \
+ grep -E "iPhone [0-9]" | \
+ grep -v "iPhone Air" | \
+ head -1)
+
+ if [ -n "$SIMULATOR_LINE" ]; then
+ # Extract device name - everything before first "("
+ SIMULATOR=$(echo "$SIMULATOR_LINE" | \
+ sed -E 's/^[[:space:]]*([^(]+).*/\1/' | \
+ sed 's/[[:space:]]*$//')
+ fi
+ fi
+
+ # Validate it's not a status word
+ if [ "$SIMULATOR" = "Shutdown" ] || [ "$SIMULATOR" = "Booted" ] || [ "$SIMULATOR" = "Creating" ] || [ -z "$SIMULATOR" ]; then
+ SIMULATOR=""
+ else
+ log_info "Found simulator via simctl: $SIMULATOR"
+ fi
+ fi
+ fi
+
+ # Method 3: Try to find iPhone 17 Pro specifically (preferred)
+ if [ -z "$SIMULATOR" ] || [ "$SIMULATOR" = "Shutdown" ] || [ "$SIMULATOR" = "Booted" ]; then
+ PRO_LINE=$(xcrun simctl list devices available 2>/dev/null | \
+ grep -i "iPhone 17 Pro" | \
+ head -1)
+
+ if [ -n "$PRO_LINE" ]; then
+ PRO_SIM=$(echo "$PRO_LINE" | \
+ awk -F'(' '{print $1}' | \
+ sed 's/^[[:space:]]*//' | \
+ sed 's/[[:space:]]*$//')
+
+ if [ -n "$PRO_SIM" ] && [ "$PRO_SIM" != "Shutdown" ] && [ "$PRO_SIM" != "Booted" ] && [ "$PRO_SIM" != "Creating" ]; then
+ SIMULATOR="$PRO_SIM"
+ log_info "Using preferred simulator: $SIMULATOR"
+ fi
+ fi
+ fi
+
+ # Final fallback to known good simulator
+ if [ -z "$SIMULATOR" ] || [ "$SIMULATOR" = "Shutdown" ] || [ "$SIMULATOR" = "Booted" ] || [ "$SIMULATOR" = "Creating" ]; then
+ # Try common simulator names that are likely to exist
+ for DEFAULT_SIM in "iPhone 17 Pro" "iPhone 17" "iPhone 16" "iPhone 15 Pro" "iPhone 15"; do
+ if xcrun simctl list devices available 2>/dev/null | grep -q "$DEFAULT_SIM"; then
+ SIMULATOR="$DEFAULT_SIM"
+ log_info "Using fallback simulator: $SIMULATOR"
+ break
+ fi
+ done
+
+ # If still empty, use iPhone 17 Pro as final default
+ if [ -z "$SIMULATOR" ] || [ "$SIMULATOR" = "Shutdown" ] || [ "$SIMULATOR" = "Booted" ]; then
+ log_warn "Could not determine simulator. Using default: iPhone 17 Pro"
+ SIMULATOR="iPhone 17 Pro"
+ fi
+ fi
+
+ log_info "Selected simulator: $SIMULATOR"
+
+ # Extract device ID for more reliable targeting
+ # Format: " iPhone 17 Pro (68D19D08-4701-422C-AF61-2E21ACA1DD4C) (Shutdown)"
+ SIMULATOR_ID=$(xcrun simctl list devices available 2>/dev/null | \
+ grep -i "$SIMULATOR" | \
+ head -1 | \
+ sed -n 's/.*(\([A-F0-9-]\{36\}\)).*/\1/p')
+
+ # Verify simulator exists before building
+ if [ -z "$SIMULATOR_ID" ] && ! xcrun simctl list devices available 2>/dev/null | grep -q "$SIMULATOR"; then
+ log_warn "Simulator '$SIMULATOR' not found in available devices"
+ log_info "Available iPhone simulators:"
+ xcrun simctl list devices available 2>/dev/null | grep -i "iphone" | grep -v "iPhone Air" | head -5
+ log_warn "Attempting build anyway with: $SIMULATOR"
+ fi
+
+ # Build iOS app
+ log_step "Building iOS app for simulator..."
+
+ # Use device ID if available, otherwise use name
+ if [ -n "$SIMULATOR_ID" ]; then
+ DESTINATION="platform=iOS Simulator,id=$SIMULATOR_ID"
+ log_info "Using simulator ID: $SIMULATOR_ID ($SIMULATOR)"
+ else
+ DESTINATION="platform=iOS Simulator,name=$SIMULATOR"
+ log_info "Using simulator name: $SIMULATOR"
+ fi
+
+ if xcodebuild -workspace "$WORKSPACE" \
+ -scheme App \
+ -configuration Debug \
+ -sdk iphonesimulator \
+ -destination "$DESTINATION" \
+ build; then
+ log_info "iOS app built successfully"
+
+ # Find built app
+ DERIVED_DATA="$HOME/Library/Developer/Xcode/DerivedData"
+ APP_PATH=$(find "$DERIVED_DATA" -name "App.app" -path "*/Build/Products/Debug-iphonesimulator/*" -type d 2>/dev/null | head -1)
+
+ if [ -n "$APP_PATH" ]; then
+ log_info "App built at: $APP_PATH"
+
+ # Run on simulator if requested
+ if [ "$RUN_ALL" = true ] || [ "$RUN_IOS" = true ]; then
+ log_step "Installing and launching iOS app on simulator..."
+
+ # Use the device ID we already extracted, or get it again
+ if [ -z "$SIMULATOR_ID" ]; then
+ SIMULATOR_ID=$(xcrun simctl list devices available 2>/dev/null | \
+ grep -i "$SIMULATOR" | \
+ head -1 | \
+ sed -n 's/.*(\([A-F0-9-]\{36\}\)).*/\1/p')
+ fi
+
+ # If we have device ID, use it; otherwise try to boot by name
+ if [ -n "$SIMULATOR_ID" ]; then
+ SIMULATOR_UDID="$SIMULATOR_ID"
+ log_info "Using simulator ID: $SIMULATOR_UDID"
+ else
+ # Try to boot simulator by name and get its ID
+ log_step "Booting simulator: $SIMULATOR..."
+ xcrun simctl boot "$SIMULATOR" 2>/dev/null || true
+ sleep 2
+ SIMULATOR_UDID=$(xcrun simctl list devices 2>/dev/null | \
+ grep -i "$SIMULATOR" | \
+ grep -E "\([A-F0-9-]{36}\)" | \
+ head -1 | \
+ sed -n 's/.*(\([A-F0-9-]\{36\}\)).*/\1/p')
+ fi
+
+ if [ -n "$SIMULATOR_UDID" ]; then
+ # Install app
+ if xcrun simctl install "$SIMULATOR_UDID" "$APP_PATH"; then
+ log_info "App installed on simulator"
+
+ # Launch app
+ APP_BUNDLE_ID="com.timesafari.dailynotification.test"
+ if xcrun simctl launch "$SIMULATOR_UDID" "$APP_BUNDLE_ID"; then
+ log_info "ā
iOS app launched successfully!"
+ else
+ log_warn "Failed to launch app (may already be running)"
+ fi
+ else
+ log_warn "App installation failed (may already be installed)"
+ fi
+ else
+ log_warn "Could not find or boot simulator"
+ log_info "Open Xcode and run manually: open $WORKSPACE"
+ fi
+ fi
+ else
+ log_warn "Could not find built app in DerivedData"
+ log_info "Build succeeded. Open Xcode to run: open $WORKSPACE"
+ fi
+ else
+ log_error "iOS build failed"
+ exit 1
+ fi
+
+ cd "$PROJECT_DIR"
+ fi
+fi
+
+log_info ""
+log_info "ā
Build process complete!"
+log_info ""
+
+# Summary
+if [ "$BUILD_ANDROID" = true ] || [ "$BUILD_ALL" = true ]; then
+ if [ -f "$PROJECT_DIR/android/app/build/outputs/apk/debug/app-debug.apk" ]; then
+ log_info "Android APK: $PROJECT_DIR/android/app/build/outputs/apk/debug/app-debug.apk"
+ fi
+fi
+
+if [ "$BUILD_IOS" = true ] || [ "$BUILD_ALL" = true ]; then
+ if [ -d "$IOS_DIR/App.xcworkspace" ]; then
+ log_info "iOS Workspace: $IOS_DIR/App.xcworkspace"
+ log_info "Open with: open $IOS_DIR/App.xcworkspace"
+ fi
+fi
+
diff --git a/test-apps/daily-notification-test/scripts/fix-capacitor-plugins.js b/test-apps/daily-notification-test/scripts/fix-capacitor-plugins.js
index 27d6d43..28ffe17 100755
--- a/test-apps/daily-notification-test/scripts/fix-capacitor-plugins.js
+++ b/test-apps/daily-notification-test/scripts/fix-capacitor-plugins.js
@@ -22,6 +22,7 @@ const __dirname = path.dirname(__filename);
const PLUGINS_JSON_PATH = path.join(__dirname, '../android/app/src/main/assets/capacitor.plugins.json');
const SETTINGS_GRADLE_PATH = path.join(__dirname, '../android/capacitor.settings.gradle');
+const PODFILE_PATH = path.join(__dirname, '../ios/App/Podfile');
const PLUGIN_ENTRY = {
name: "DailyNotification",
@@ -103,6 +104,98 @@ ${correctPath}`
}
}
+/**
+ * Fix iOS Podfile to use correct plugin pod name and path
+ */
+function fixPodfile() {
+ console.log('š§ Verifying iOS Podfile...');
+
+ if (!fs.existsSync(PODFILE_PATH)) {
+ console.log('ā¹ļø Podfile not found (iOS platform may not be added yet)');
+ return;
+ }
+
+ try {
+ let content = fs.readFileSync(PODFILE_PATH, 'utf8');
+ const originalContent = content;
+
+ // The correct pod reference should be:
+ // pod 'DailyNotificationPlugin', :path => '../../node_modules/@timesafari/daily-notification-plugin/ios'
+ const correctPodLine = "pod 'DailyNotificationPlugin', :path => '../../node_modules/@timesafari/daily-notification-plugin/ios'";
+
+ // Check if Podfile already has the correct reference
+ if (content.includes("pod 'DailyNotificationPlugin'")) {
+ // Check if path is correct
+ if (content.includes('@timesafari/daily-notification-plugin/ios')) {
+ console.log('ā
Podfile has correct DailyNotificationPlugin reference');
+ } else {
+ // Fix the path
+ console.log('ā ļø Podfile has DailyNotificationPlugin but wrong path - fixing...');
+ content = content.replace(
+ /pod ['"]DailyNotificationPlugin['"].*:path.*/,
+ correctPodLine
+ );
+
+ // Also fix if it's using the wrong name (TimesafariDailyNotificationPlugin)
+ content = content.replace(
+ /pod ['"]TimesafariDailyNotificationPlugin['"].*:path.*/,
+ correctPodLine
+ );
+
+ if (content !== originalContent) {
+ fs.writeFileSync(PODFILE_PATH, content);
+ console.log('ā
Fixed DailyNotificationPlugin path in Podfile');
+ }
+ }
+ } else if (content.includes("TimesafariDailyNotificationPlugin")) {
+ // Fix wrong pod name
+ console.log('ā ļø Podfile uses wrong pod name (TimesafariDailyNotificationPlugin) - fixing...');
+ content = content.replace(
+ /pod ['"]TimesafariDailyNotificationPlugin['"].*:path.*/,
+ correctPodLine
+ );
+
+ if (content !== originalContent) {
+ fs.writeFileSync(PODFILE_PATH, content);
+ console.log('ā
Fixed pod name in Podfile (TimesafariDailyNotificationPlugin -> DailyNotificationPlugin)');
+ }
+ } else {
+ // Add the pod reference if it's missing
+ console.log('ā ļø Podfile missing DailyNotificationPlugin - adding...');
+
+ // Find the capacitor_pods function or target section
+ if (content.includes('def capacitor_pods')) {
+ // Add after capacitor_pods function
+ content = content.replace(
+ /(def capacitor_pods[\s\S]*?end)/,
+ `$1\n\n # Daily Notification Plugin\n ${correctPodLine}`
+ );
+ } else if (content.includes("target 'App'")) {
+ // Add in target section
+ content = content.replace(
+ /(target 'App' do)/,
+ `$1\n ${correctPodLine}`
+ );
+ } else {
+ // Add at end before post_install
+ content = content.replace(
+ /(post_install)/,
+ `${correctPodLine}\n\n$1`
+ );
+ }
+
+ if (content !== originalContent) {
+ fs.writeFileSync(PODFILE_PATH, content);
+ console.log('ā
Added DailyNotificationPlugin to Podfile');
+ }
+ }
+
+ } catch (error) {
+ console.error('ā Error fixing Podfile:', error.message);
+ // Don't exit - iOS might not be set up yet
+ }
+}
+
/**
* Run all fixes
*/
@@ -112,9 +205,10 @@ function fixAll() {
fixCapacitorPlugins();
fixCapacitorSettingsGradle();
+ fixPodfile();
console.log('\nā
All fixes applied successfully!');
- console.log('š” These fixes will persist until the next "npx cap sync android"');
+ console.log('š” These fixes will persist until the next "npx cap sync"');
}
// Run if called directly
@@ -122,4 +216,4 @@ if (import.meta.url === `file://${process.argv[1]}`) {
fixAll();
}
-export { fixCapacitorPlugins, fixCapacitorSettingsGradle, fixAll };
+export { fixCapacitorPlugins, fixCapacitorSettingsGradle, fixPodfile, fixAll };
diff --git a/test-apps/daily-notification-test/src/lib/typed-plugin.ts b/test-apps/daily-notification-test/src/lib/typed-plugin.ts
index 7dda576..cdf0c67 100644
--- a/test-apps/daily-notification-test/src/lib/typed-plugin.ts
+++ b/test-apps/daily-notification-test/src/lib/typed-plugin.ts
@@ -72,15 +72,20 @@ export class TypedDailyNotificationPlugin implements DailyNotificationBridge {
/**
* Check permissions with validation
+ * Uses checkPermissionStatus() which is the correct method name for iOS
*/
async checkPermissions(): Promise {
try {
- const result = await (this.plugin as { checkPermissions: () => Promise }).checkPermissions()
+ // Use checkPermissionStatus() which is implemented on both iOS and Android
+ const result = await (this.plugin as { checkPermissionStatus: () => Promise }).checkPermissionStatus()
- // Ensure response has required fields
+ // Map PermissionStatusResult to PermissionStatus format
return {
- notifications: result.notifications || 'denied',
- notificationsEnabled: Boolean(result.notificationsEnabled)
+ notifications: result.notificationsEnabled ? 'granted' : 'denied',
+ notificationsEnabled: Boolean(result.notificationsEnabled),
+ exactAlarmEnabled: Boolean(result.exactAlarmEnabled),
+ wakeLockEnabled: Boolean(result.wakeLockEnabled),
+ allPermissionsGranted: Boolean(result.allPermissionsGranted)
}
} catch (error) {
@@ -166,6 +171,26 @@ export class TypedDailyNotificationPlugin implements DailyNotificationBridge {
}
}
+ /**
+ * Request notification permissions (iOS method name)
+ * This is an alias for requestPermissions() for iOS compatibility
+ */
+ async requestNotificationPermissions(): Promise {
+ try {
+ // Try requestNotificationPermissions first (iOS), fallback to requestPermissions
+ if (typeof (this.plugin as any).requestNotificationPermissions === 'function') {
+ await (this.plugin as { requestNotificationPermissions: () => Promise }).requestNotificationPermissions()
+ } else if (typeof (this.plugin as any).requestPermissions === 'function') {
+ await (this.plugin as { requestPermissions: () => Promise }).requestPermissions()
+ } else {
+ throw new Error('Neither requestNotificationPermissions nor requestPermissions is available')
+ }
+ } catch (error) {
+ logError(error, 'requestNotificationPermissions')
+ throw error
+ }
+ }
+
/**
* Open exact alarm settings
*/
diff --git a/test-apps/daily-notification-test/src/views/HomeView.vue b/test-apps/daily-notification-test/src/views/HomeView.vue
index 72b1550..448333f 100644
--- a/test-apps/daily-notification-test/src/views/HomeView.vue
+++ b/test-apps/daily-notification-test/src/views/HomeView.vue
@@ -47,6 +47,13 @@
@click="checkSystemStatus"
:loading="isCheckingStatus"
/>
+
=> {
console.log('ā
Plugin available, checking status...')
try {
const status = await plugin.getNotificationStatus()
- const permissions = await plugin.checkPermissions()
+ // Use checkPermissionStatus() which is the correct method name for iOS
+ const permissions = await plugin.checkPermissionStatus()
const exactAlarmStatus = await plugin.getExactAlarmStatus()
console.log('š Plugin status object:', status)
@@ -232,17 +240,17 @@ const checkSystemStatus = async (): Promise => {
console.log('š Plugin permissions:', permissions)
console.log('š Permissions details:')
- console.log(' - notifications:', permissions.notifications)
- console.log(' - notificationsEnabled:', (permissions as unknown as Record).notificationsEnabled)
- console.log(' - exactAlarmEnabled:', (permissions as unknown as Record).exactAlarmEnabled)
- console.log(' - wakeLockEnabled:', (permissions as unknown as Record).wakeLockEnabled)
- console.log(' - allPermissionsGranted:', (permissions as unknown as Record).allPermissionsGranted)
+ console.log(' - notificationsEnabled:', permissions.notificationsEnabled)
+ console.log(' - exactAlarmEnabled:', permissions.exactAlarmEnabled)
+ console.log(' - wakeLockEnabled:', permissions.wakeLockEnabled)
+ console.log(' - allPermissionsGranted:', permissions.allPermissionsGranted)
console.log('š Exact alarm status:', exactAlarmStatus)
// Map plugin response to app store format
+ // checkPermissionStatus() returns PermissionStatusResult with boolean flags
const mappedStatus = {
canScheduleNow: status.isEnabled ?? false,
- postNotificationsGranted: permissions.notifications === 'granted',
+ postNotificationsGranted: permissions.notificationsEnabled ?? false,
channelEnabled: true, // Default for now
channelImportance: 3, // Default for now
channelId: 'daily-notifications',
@@ -351,6 +359,80 @@ const refreshSystemStatus = async (): Promise => {
await checkSystemStatus()
}
+/**
+ * Check permissions and request if needed (Android pattern)
+ * 1. Check permission status first
+ * 2. If not granted, show system dialog
+ * 3. Refresh status after request
+ */
+const checkAndRequestPermissions = async (): Promise => {
+ console.log('š CLICK: Check and Request Permissions')
+
+ if (isRequestingPermissions.value) {
+ console.log('ā³ Permission request already in progress')
+ return
+ }
+
+ isRequestingPermissions.value = true
+
+ try {
+ const { DailyNotification } = await import('@timesafari/daily-notification-plugin')
+ const plugin = DailyNotification
+
+ if (!plugin) {
+ console.error('ā DailyNotification plugin not available')
+ return
+ }
+
+ // Step 1: Check permission status first (Android pattern)
+ console.log('š Step 1: Checking current permission status...')
+ const permissionStatus = await plugin.checkPermissionStatus()
+
+ console.log('š Permission status:', {
+ notificationsEnabled: permissionStatus.notificationsEnabled,
+ exactAlarmEnabled: permissionStatus.exactAlarmEnabled,
+ allPermissionsGranted: permissionStatus.allPermissionsGranted
+ })
+
+ // Step 2: If not granted, show system dialog
+ if (!permissionStatus.notificationsEnabled) {
+ console.log('ā ļø Permissions not granted - showing system dialog...')
+ console.log('š± iOS will show native permission dialog now...')
+
+ // Request permissions - this will show the iOS system dialog
+ // Try requestNotificationPermissions first (iOS), fallback to requestPermissions
+ if (typeof (plugin as any).requestNotificationPermissions === 'function') {
+ await (plugin as { requestNotificationPermissions: () => Promise }).requestNotificationPermissions()
+ } else if (typeof (plugin as any).requestPermissions === 'function') {
+ await (plugin as { requestPermissions: () => Promise }).requestPermissions()
+ } else {
+ throw new Error('Permission request method not available')
+ }
+
+ console.log('ā
Permission request completed')
+
+ // Step 3: Refresh status after request
+ console.log('š Refreshing status after permission request...')
+ await new Promise(resolve => setTimeout(resolve, 1000)) // Wait 1 second for system to update
+ await checkSystemStatus()
+ } else {
+ console.log('ā
Permissions already granted - no dialog needed')
+ // Still refresh status to show current state
+ await checkSystemStatus()
+ }
+
+ } catch (error) {
+ console.error('ā Permission check/request failed:', error)
+ console.error('ā Error details:', {
+ name: (error as Error).name,
+ message: (error as Error).message,
+ stack: (error as Error).stack
+ })
+ } finally {
+ isRequestingPermissions.value = false
+ }
+}
+
const runPluginDiagnostics = async (): Promise => {
console.log('š CLICK: Plugin Diagnostics - METHOD CALLED!')
console.log('š FUNCTION START: runPluginDiagnostics called at', new Date().toISOString())