1 Commits

Author SHA1 Message Date
Jose Olarte III
8191fb07db fix(test-app): Fix iOS build issues and TypeScript errors
Fix multiple issues preventing iOS builds and TypeScript compilation:

- Fix postinstall script to handle missing directories gracefully
  - Create assets directory if it doesn't exist before writing capacitor.plugins.json
  - Don't exit on error if Capacitor hasn't synced yet (allows npm install to succeed)

- Fix TypeScript compilation errors
  - Add optional fields to PermissionStatus interface (exactAlarmEnabled, wakeLockEnabled, allPermissionsGranted)
  - Fix type assertion in HomeView.vue to use 'as any' for dynamic plugin methods

- Fix Podfile configuration issues
  - Update fix script to detect correct pod path (node_modules vs file dependency)
  - Fix pod name from TimesafariDailyNotificationPlugin to DailyNotificationPlugin
  - Handle both node_modules and relative paths for file dependencies

- Update iOS sync workflow
  - Add fix script to cap:sync:ios (runs before and after sync)
  - Automatically run pod install after fixing Podfile
  - Handle cap sync failures gracefully with || true

- Update documentation
  - Reflect that iOS sync now includes fix script
  - Note that pod install is handled automatically
  - Update troubleshooting section for Podfile errors

Fixes:
- npm install failing due to missing assets directory
- TypeScript build errors in typed-plugin.ts and HomeView.vue
- iOS pod install failing with "No podspec found for TimesafariDailyNotificationPlugin"
- Capacitor sync overwriting Podfile with incorrect pod name
2025-12-19 12:54:49 +08:00
7 changed files with 61 additions and 18 deletions

View File

@@ -110,16 +110,20 @@ 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.
**Problem**: `npx cap sync` overwrites configuration files with incorrect paths:
- `capacitor.plugins.json` - Plugin registry gets cleared
- `capacitor.settings.gradle` - Android plugin path is wrong
- `ios/App/Podfile` - iOS pod name is wrong (`TimesafariDailyNotificationPlugin` instead of `DailyNotificationPlugin`)
**Solution**: The `cap:sync` script automatically:
1. Runs `npx cap sync` (syncs both Android and iOS)
2. Fixes `capacitor.settings.gradle` (corrects plugin path from `android/` to `android/plugin/`)
2. Fixes `capacitor.settings.gradle` (corrects plugin path from `android/plugin/` to `android/`)
3. Restores the DailyNotification plugin entry in `capacitor.plugins.json`
4. Fixes `ios/App/Podfile` (corrects pod name and path)
**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)
- `npm run cap:sync:ios` - Syncs iOS only (includes fix script and runs `pod install`)
**Without the fix**: Plugin detection fails, build errors occur, "simplified dialog" appears.
@@ -326,8 +330,8 @@ xcrun simctl spawn booted log stream | grep -i "dailynotification\|capacitor\|pl
## 📝 Important Notes
**Remember**:
- Use `npm run cap:sync` to sync both platforms (automatically fixes Android configuration files)
- Use `npm run cap:sync` to sync both platforms (automatically fixes 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
- Use `npm run cap:sync:ios` for iOS-only sync (includes fix script and automatically runs `pod install`)
- 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
- The iOS sync script handles `pod install` automatically, but you can run it manually in `ios/App/` if needed

View File

@@ -1,4 +1,4 @@
require_relative '../../../../node_modules/@capacitor/ios/scripts/pods_helpers'
require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'
platform :ios, '13.0'
use_frameworks!
@@ -9,8 +9,8 @@ use_frameworks!
install! 'cocoapods', :disable_input_output_paths => true
def capacitor_pods
pod 'Capacitor', :path => '../../../../node_modules/@capacitor/ios'
pod 'CapacitorCordova', :path => '../../../../node_modules/@capacitor/ios'
pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
pod 'DailyNotificationPlugin', :path => '../../node_modules/@timesafari/daily-notification-plugin/ios'
end

View File

@@ -12,6 +12,7 @@
"@capacitor/android": "^6.2.1",
"@capacitor/cli": "^6.2.1",
"@capacitor/core": "^6.2.1",
"@capacitor/ios": "^6.2.1",
"@timesafari/daily-notification-plugin": "file:../../",
"date-fns": "^4.1.0",
"did-jwt": "^7.4.7",
@@ -117,6 +118,7 @@
"integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.3",
@@ -416,6 +418,7 @@
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz",
"integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/types": "^7.28.4"
},
@@ -634,10 +637,20 @@
"resolved": "https://registry.npmjs.org/@capacitor/core/-/core-6.2.1.tgz",
"integrity": "sha512-urZwxa7hVE/BnA18oCFAdizXPse6fCKanQyEqpmz6cBJ2vObwMpyJDG5jBeoSsgocS9+Ax+9vb4ducWJn0y2qQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"tslib": "^2.1.0"
}
},
"node_modules/@capacitor/ios": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-6.2.1.tgz",
"integrity": "sha512-tbMlQdQjxe1wyaBvYVU1yTojKJjgluZQsJkALuJxv/6F8QTw5b6vd7X785O/O7cMpIAZfUWo/vtAHzFkRV+kXw==",
"license": "MIT",
"peerDependencies": {
"@capacitor/core": "^6.2.0"
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.25.11",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.11.tgz",
@@ -2065,6 +2078,7 @@
"integrity": "sha512-6JSSaBZmsKvEkbRUkf7Zj7dru/8ZCrJxAqArcLaVMee5907JdtEbKGsZ7zNiIm/UAkpGUkaSMZEXShnN2D1HZA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.46.1",
"@typescript-eslint/types": "8.46.1",
@@ -2663,6 +2677,7 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -2911,6 +2926,7 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.8.9",
"caniuse-lite": "^1.0.30001746",
@@ -3373,6 +3389,7 @@
"integrity": "sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1",
@@ -3434,6 +3451,7 @@
"integrity": "sha512-K6tP0dW8FJVZLQxa2S7LcE1lLw3X8VvB3t887Q6CLrFVxHYBXGANbXvwNzYIu6Ughx1bSJ5BDT0YB3ybPT39lw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
"natural-compare": "^1.4.0",
@@ -4293,6 +4311,7 @@
"integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"jiti": "lib/jiti-cli.mjs"
}
@@ -5721,6 +5740,7 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},
@@ -5798,6 +5818,7 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"devOptional": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -6031,6 +6052,7 @@
"integrity": "sha512-CmuvUBzVJ/e3HGxhg6cYk88NGgTnBoOo7ogtfJJ0fefUWAxN/WDSUa50o+oVBxuIhO8FoEZW0j2eW7sfjs5EtA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.5.0",
@@ -6301,6 +6323,7 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},
@@ -6320,6 +6343,7 @@
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.22.tgz",
"integrity": "sha512-toaZjQ3a/G/mYaLSbV+QsQhIdMo9x5rrqIpYRObsJ6T/J+RyCSFwN2LHNVH9v8uIcljDNa3QzPVdv3Y6b9hAJQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/compiler-dom": "3.5.22",
"@vue/compiler-sfc": "3.5.22",

View File

@@ -15,7 +15,7 @@
"lint": "eslint . --fix",
"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",
"cap:sync:ios": "node scripts/fix-capacitor-plugins.js && (npx cap sync ios || true) && node scripts/fix-capacitor-plugins.js && cd ios/App && pod install && cd ../..",
"postinstall": "node scripts/fix-capacitor-plugins.js"
},
"dependencies": {

View File

@@ -36,6 +36,13 @@ function fixCapacitorPlugins() {
console.log('🔧 Fixing capacitor.plugins.json...');
try {
// Ensure directory exists before writing
const pluginsDir = path.dirname(PLUGINS_JSON_PATH);
if (!fs.existsSync(pluginsDir)) {
fs.mkdirSync(pluginsDir, { recursive: true });
console.log(' Created assets directory:', pluginsDir);
}
// Read current content
let plugins = [];
if (fs.existsSync(PLUGINS_JSON_PATH)) {
@@ -56,7 +63,8 @@ function fixCapacitorPlugins() {
} catch (error) {
console.error('❌ Error fixing capacitor.plugins.json:', error.message);
process.exit(1);
// Don't exit on error - this might run before cap sync creates the file
console.log(' This is normal if Capacitor hasn\'t synced yet. Run "npx cap sync android" first.');
}
}
@@ -119,14 +127,18 @@ function fixPodfile() {
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'";
// Determine correct path - check if plugin is in node_modules or use relative path for file dependencies
// From ios/App/Podfile: ../../../../ios points to plugin root's ios directory
const nodeModulesPath = '../../node_modules/@timesafari/daily-notification-plugin/ios';
const relativePath = '../../../../ios';
const correctPodLine = fs.existsSync(path.join(path.dirname(PODFILE_PATH), nodeModulesPath, 'DailyNotificationPlugin.podspec'))
? `pod 'DailyNotificationPlugin', :path => '${nodeModulesPath}'`
: `pod 'DailyNotificationPlugin', :path => '${relativePath}'`;
// 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')) {
// Check if path is correct (either node_modules or relative path)
if (content.includes('@timesafari/daily-notification-plugin/ios') || content.includes("'../../../../ios'")) {
console.log('✅ Podfile has correct DailyNotificationPlugin reference');
} else {
// Fix the path

View File

@@ -40,6 +40,9 @@ export interface ScheduleResponse {
export interface PermissionStatus {
notifications: 'granted' | 'denied'
notificationsEnabled: boolean
exactAlarmEnabled?: boolean
wakeLockEnabled?: boolean
allPermissionsGranted?: boolean
}
export interface NotificationStatus {

View File

@@ -402,9 +402,9 @@ const checkAndRequestPermissions = async (): Promise<void> => {
// 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<void> }).requestNotificationPermissions()
await (plugin as any).requestNotificationPermissions()
} else if (typeof (plugin as any).requestPermissions === 'function') {
await (plugin as { requestPermissions: () => Promise<any> }).requestPermissions()
await (plugin as any).requestPermissions()
} else {
throw new Error('Permission request method not available')
}