From 4be87acc14b889f2d79c9d013d0b85d7f31beecf Mon Sep 17 00:00:00 2001 From: Matthew Raymer Date: Tue, 4 Nov 2025 01:40:38 -0800 Subject: [PATCH] feat(ios): add iOS deployment support and web assets parity Add comprehensive iOS build and deployment infrastructure with command-line tooling, documentation, and web assets synchronization. Changes: - Update Capacitor dependencies to v6.0 in podspec - Add iOS build support to build-native.sh with NVM integration - Sync iOS web assets to match www/ source directory - Create deployment scripts for both native iOS app and Vue 3 test app - Add comprehensive iOS simulator deployment documentation - Document web assets parity requirements between Android and iOS This enables: - Command-line iOS builds without Xcode UI - Automated deployment to iOS simulators - Consistent web assets across platforms - Clear separation between native iOS app (ios/App) and Vue 3 test app Files modified: - ios/DailyNotificationPlugin.podspec (Capacitor 6.0) - ios/App/App/public/index.html (synced from www/) - scripts/build-native.sh (iOS build support) Files added: - docs/WEB_ASSETS_PARITY.md - docs/standalone-ios-simulator-guide.md - scripts/build-and-deploy-native-ios.sh - test-apps/daily-notification-test/docs/IOS_BUILD_QUICK_REFERENCE.md - test-apps/daily-notification-test/scripts/build-and-deploy-ios.sh --- docs/WEB_ASSETS_PARITY.md | 64 ++ docs/standalone-ios-simulator-guide.md | 548 +++++++++++++++ ios/App/App/public/index.html | 638 ++++++++++++++++-- ios/DailyNotificationPlugin.podspec | 4 +- ios/Podfile.lock | 14 +- nvm-install.sh | 16 + package-lock.json | 12 + scripts/build-and-deploy-native-ios.sh | 161 +++++ scripts/build-native.sh | 393 +++++++++-- scripts/setup-ruby.sh | 250 +++++++ .../docs/IOS_BUILD_QUICK_REFERENCE.md | 183 +++++ .../scripts/build-and-deploy-ios.sh | 150 ++++ 12 files changed, 2325 insertions(+), 108 deletions(-) create mode 100644 docs/WEB_ASSETS_PARITY.md create mode 100644 docs/standalone-ios-simulator-guide.md create mode 100755 nvm-install.sh create mode 100755 scripts/build-and-deploy-native-ios.sh create mode 100755 scripts/setup-ruby.sh create mode 100644 test-apps/daily-notification-test/docs/IOS_BUILD_QUICK_REFERENCE.md create mode 100755 test-apps/daily-notification-test/scripts/build-and-deploy-ios.sh diff --git a/docs/WEB_ASSETS_PARITY.md b/docs/WEB_ASSETS_PARITY.md new file mode 100644 index 0000000..fb0fdb7 --- /dev/null +++ b/docs/WEB_ASSETS_PARITY.md @@ -0,0 +1,64 @@ +# Web Assets Structure - Android and iOS Parity + +**Author**: Matthew Raymer +**Date**: November 4, 2025 + +## Source of Truth + +The **`www/`** directory is the source of truth for web assets. Both Android and iOS app directories should match this structure. + +## Directory Structure + +``` +www/ # Source of truth (edit here) +├── index.html # Main test interface + +android/app/src/main/assets/ # Android (synced from www/) +├── capacitor.plugins.json # Auto-generated by Capacitor +└── public/ # Web assets (must match www/) + └── index.html # Synced from www/index.html + +ios/App/App/ # iOS (synced from www/) +├── capacitor.config.json # Capacitor configuration +└── public/ # Web assets (must match www/) + └── index.html # Synced from www/index.html +``` + +## Synchronization + +Both `android/app/src/main/assets/public/` and `ios/App/App/public/` should match `www/` after running: + +```bash +# Sync web assets to both platforms +npx cap sync + +# Or sync individually +npx cap sync android +npx cap sync ios +``` + +## Key Points + +1. **Edit source files in `www/`** - Never edit platform-specific copies directly +2. **Both platforms should match** - After sync, `android/.../assets/public/` and `ios/App/App/public/` should be identical +3. **Capacitor handles sync** - `npx cap sync` copies files from `www/` to platform directories +4. **Auto-generated files** - `capacitor.plugins.json`, `capacitor.js`, etc. are generated by Capacitor + +## Verification + +After syncing, verify both platforms match: + +```bash +# Check file sizes match +ls -lh www/index.html android/app/src/main/assets/public/index.html ios/App/App/public/index.html + +# Compare contents +diff www/index.html android/app/src/main/assets/public/index.html +diff www/index.html ios/App/App/public/index.html +``` + +## Notes + +- **Cordova files**: iOS may have empty `cordova.js` and `cordova_plugins.js` files. These are harmless but should be removed if not using Cordova compatibility. +- **Capacitor runtime**: Capacitor generates `capacitor.js` and `capacitor_plugins.js` during sync - these are auto-generated and should not be manually edited. + diff --git a/docs/standalone-ios-simulator-guide.md b/docs/standalone-ios-simulator-guide.md new file mode 100644 index 0000000..538b80b --- /dev/null +++ b/docs/standalone-ios-simulator-guide.md @@ -0,0 +1,548 @@ +# Running iOS Apps in Standalone Simulator (Without Xcode UI) + +**Author**: Matthew Raymer +**Last Updated**: 2025-11-04 +**Version**: 1.0.0 + +## Overview + +This guide demonstrates how to run DailyNotification plugin test apps in a standalone iOS Simulator without using Xcode UI. This method is useful for development, CI/CD pipelines, and command-line workflows. + +**There are two different test apps:** +1. **Native iOS Development App** (`ios/App`) - Simple Capacitor app for plugin development +2. **Vue 3 Test App** (`test-apps/daily-notification-test`) - Full-featured Vue 3 Capacitor app for comprehensive testing + +## Prerequisites + +### Required Software +- **Xcode** with command line tools (`xcode-select --install`) +- **iOS Simulator** (included with Xcode) +- **CocoaPods** (`gem install cocoapods`) +- **Node.js** and **npm** (for TypeScript compilation) +- **Capacitor CLI** (`npm install -g @capacitor/cli`) - for Vue 3 test app + +### System Requirements +- **macOS** (required for iOS development) +- **RAM**: 4GB minimum, 8GB recommended +- **Storage**: 5GB free space for simulator and dependencies + +--- + +## Scenario 1: Native iOS Development App (`ios/App`) + +The `ios/App` directory contains a simple Capacitor-based development app, similar to `android/app`. This is used for quick plugin testing and development. + +### Step-by-Step Process + +#### 1. Check Available Simulators + +```bash +# List available iOS simulators +xcrun simctl list devices available + +# Example output: +# iPhone 15 Pro (iOS 17.0) +# iPhone 14 (iOS 16.4) +# iPad Pro (12.9-inch) (iOS 17.0) +``` + +#### 2. Boot a Simulator + +```bash +# Boot a specific simulator device +xcrun simctl boot "iPhone 15 Pro" + +# Or boot by device ID +xcrun simctl boot + +# Verify simulator is running +xcrun simctl list devices | grep Booted +``` + +**Alternative: Open Simulator UI** +```bash +# Open Simulator app (allows visual interaction) +open -a Simulator +``` + +#### 3. Build the Plugin + +```bash +# Navigate to project directory +cd /path/to/daily-notification-plugin + +# Build plugin for iOS +./scripts/build-native.sh --platform ios +``` + +**What this does:** +- Compiles TypeScript to JavaScript +- Builds iOS native code (Swift) +- Creates plugin framework +- Builds for simulator + +#### 4. Build Native iOS Development App + +```bash +# Navigate to iOS directory +cd ios + +# Install CocoaPods dependencies +pod install + +# Build the development app for simulator +cd App +xcodebuild -workspace App.xcworkspace \ + -scheme App \ + -configuration Debug \ + -sdk iphonesimulator \ + -destination 'platform=iOS Simulator,name=iPhone 15 Pro' \ + -derivedDataPath build/derivedData \ + CODE_SIGN_IDENTITY="" \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGNING_ALLOWED=NO \ + clean build +``` + +#### 5. Install App on Simulator + +```bash +# Find the built app +APP_PATH=$(find build/derivedData -name "*.app" -type d -path "*/Build/Products/*-iphonesimulator/*.app" | head -1) + +# Install app on simulator +xcrun simctl install booted "$APP_PATH" +``` + +#### 6. Launch the App + +```bash +# Get bundle identifier from Info.plist +BUNDLE_ID=$(plutil -extract CFBundleIdentifier raw App/Info.plist) + +# Launch the app +xcrun simctl launch booted "$BUNDLE_ID" + +# Example: +# xcrun simctl launch booted com.timesafari.dailynotification +``` + +#### 7. Monitor App Logs + +```bash +# View all logs +xcrun simctl spawn booted log stream + +# Filter for specific processes +xcrun simctl spawn booted log stream --predicate 'processImagePath contains "App"' + +# View system logs +log stream --predicate 'processImagePath contains "App"' --level debug +``` + +### Complete Command Sequence for Native iOS App + +```bash +# 1. Boot simulator +xcrun simctl boot "iPhone 15 Pro" || open -a Simulator + +# 2. Build plugin +cd /path/to/daily-notification-plugin +./scripts/build-native.sh --platform ios + +# 3. Build native iOS app +cd ios +pod install +cd App +xcodebuild -workspace App.xcworkspace \ + -scheme App \ + -configuration Debug \ + -sdk iphonesimulator \ + -destination 'platform=iOS Simulator,name=iPhone 15 Pro' \ + CODE_SIGN_IDENTITY="" \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGNING_ALLOWED=NO + +# 4. Install app +APP_PATH=$(find build/derivedData -name "*.app" -type d | head -1) +xcrun simctl install booted "$APP_PATH" + +# 5. Launch app +BUNDLE_ID=$(plutil -extract CFBundleIdentifier raw App/Info.plist) +xcrun simctl launch booted "$BUNDLE_ID" +``` + +--- + +## Scenario 2: Vue 3 Test App (`test-apps/daily-notification-test`) + +The `test-apps/daily-notification-test` directory contains a full-featured Vue 3 Capacitor app with comprehensive testing interface, similar to the Android test app. + +### Step-by-Step Process + +#### 1. Check Available Simulators + +```bash +# List available iOS simulators +xcrun simctl list devices available +``` + +#### 2. Boot a Simulator + +```bash +# Boot a specific simulator device +xcrun simctl boot "iPhone 15 Pro" + +# Or open Simulator UI +open -a Simulator +``` + +#### 3. Build the Plugin + +```bash +# Navigate to project directory +cd /path/to/daily-notification-plugin + +# Build plugin for iOS +./scripts/build-native.sh --platform ios +``` + +#### 4. Set Up Vue 3 Test App iOS Project + +```bash +# Navigate to test app +cd test-apps/daily-notification-test + +# Install dependencies +npm install + +# Add iOS platform (if not already added) +npx cap add ios + +# Sync web assets with iOS project +npx cap sync ios +``` + +#### 5. Build Vue 3 Test App + +```bash +# Build web assets (Vue 3 app) +npm run build + +# Sync with iOS project +npx cap sync ios + +# Build iOS app for simulator +cd ios/App +xcodebuild -workspace App.xcworkspace \ + -scheme App \ + -configuration Debug \ + -sdk iphonesimulator \ + -destination 'platform=iOS Simulator,name=iPhone 15 Pro' \ + -derivedDataPath build/derivedData \ + CODE_SIGN_IDENTITY="" \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGNING_ALLOWED=NO +``` + +#### 6. Install App on Simulator + +```bash +# Find the built app +APP_PATH=$(find build/derivedData -name "*.app" -type d -path "*/Build/Products/*-iphonesimulator/*.app" | head -1) + +# Install app on simulator +xcrun simctl install booted "$APP_PATH" +``` + +#### 7. Launch the App + +```bash +# Get bundle identifier +BUNDLE_ID=$(plutil -extract CFBundleIdentifier raw App/Info.plist) + +# Launch the app +xcrun simctl launch booted "$BUNDLE_ID" + +# Example: +# xcrun simctl launch booted com.timesafari.dailynotification.test +``` + +### Complete Command Sequence for Vue 3 Test App + +```bash +# 1. Boot simulator +xcrun simctl boot "iPhone 15 Pro" || open -a Simulator + +# 2. Build plugin +cd /path/to/daily-notification-plugin +./scripts/build-native.sh --platform ios + +# 3. Set up Vue 3 test app +cd test-apps/daily-notification-test +npm install +npm run build + +# 4. Sync with iOS +npx cap sync ios + +# 5. Build iOS app +cd ios/App +xcodebuild -workspace App.xcworkspace \ + -scheme App \ + -configuration Debug \ + -sdk iphonesimulator \ + -destination 'platform=iOS Simulator,name=iPhone 15 Pro' \ + CODE_SIGN_IDENTITY="" \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGNING_ALLOWED=NO + +# 6. Install app +APP_PATH=$(find build/derivedData -name "*.app" -type d | head -1) +xcrun simctl install booted "$APP_PATH" + +# 7. Launch app +BUNDLE_ID=$(plutil -extract CFBundleIdentifier raw App/Info.plist) +xcrun simctl launch booted "$BUNDLE_ID" +``` + +--- + +## Alternative Methods + +### Method 1: Using Capacitor CLI (Vue 3 Test App Only) + +```bash +cd test-apps/daily-notification-test + +# Build and run in one command +npx cap run ios + +# This will: +# - Build the plugin +# - Sync web assets +# - Build and install app +# - Launch in simulator +``` + +**Note**: This method only works for the Vue 3 test app, not the native iOS development app. + +### Method 2: Using Automated Scripts + +#### For Native iOS App (`ios/App`) + +Create `scripts/build-and-deploy-native-ios.sh`: + +```bash +#!/bin/bash +set -e + +echo "🔨 Building plugin..." +cd /path/to/daily-notification-plugin +./scripts/build-native.sh --platform ios + +echo "📱 Booting simulator..." +xcrun simctl boot "iPhone 15 Pro" 2>/dev/null || open -a Simulator + +echo "🏗️ Building native iOS app..." +cd ios +pod install +cd App +xcodebuild -workspace App.xcworkspace \ + -scheme App \ + -configuration Debug \ + -sdk iphonesimulator \ + -destination 'platform=iOS Simulator,name=iPhone 15 Pro' \ + CODE_SIGN_IDENTITY="" \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGNING_ALLOWED=NO + +APP_PATH=$(find build/derivedData -name "*.app" -type d | head -1) +xcrun simctl install booted "$APP_PATH" +BUNDLE_ID=$(plutil -extract CFBundleIdentifier raw App/Info.plist) +xcrun simctl launch booted "$BUNDLE_ID" +``` + +#### For Vue 3 Test App + +Use the existing script: +```bash +cd test-apps/daily-notification-test +./scripts/build-and-deploy-ios.sh +``` + +### Method 3: Manual Xcode Build + +```bash +# Open project in Xcode +open ios/App/App.xcworkspace # For native app +# OR +open test-apps/daily-notification-test/ios/App/App.xcworkspace # For Vue 3 app + +# Then: +# 1. Select simulator target +# 2. Click Run button (⌘R) +# 3. App builds and launches automatically +``` + +--- + +## Simulator Management + +### List Available Devices + +```bash +# List all devices +xcrun simctl list devices + +# List only available devices +xcrun simctl list devices available + +# List booted devices +xcrun simctl list devices | grep Booted +``` + +### Shutdown Simulator + +```bash +# Shutdown specific device +xcrun simctl shutdown "iPhone 15 Pro" + +# Shutdown all devices +xcrun simctl shutdown all +``` + +### Reset Simulator + +```bash +# Erase all content and settings +xcrun simctl erase "iPhone 15 Pro" + +# Reset and boot +xcrun simctl erase "iPhone 15 Pro" && xcrun simctl boot "iPhone 15 Pro" +``` + +### Delete App from Simulator + +```bash +# Uninstall app (replace with correct bundle ID) +xcrun simctl uninstall booted com.timesafari.dailynotification +# OR for Vue 3 test app: +xcrun simctl uninstall booted com.timesafari.dailynotification.test + +# Or reset entire simulator +xcrun simctl erase booted +``` + +--- + +## Comparison: Native iOS App vs Vue 3 Test App + +| Feature | Native iOS App (`ios/App`) | Vue 3 Test App (`test-apps/...`) | +|---------|---------------------------|----------------------------------| +| **Purpose** | Quick plugin development testing | Comprehensive testing with UI | +| **Frontend** | Simple HTML/Capacitor | Vue 3 with full UI | +| **Build Steps** | Plugin + iOS build | Plugin + Vue build + iOS build | +| **Capacitor Sync** | Not required | Required (`npx cap sync ios`) | +| **Best For** | Quick native testing | Full integration testing | +| **Bundle ID** | `com.timesafari.dailynotification` | `com.timesafari.dailynotification.test` | + +--- + +## Comparison with Android + +| Task | Android Native App | iOS Native App | Vue 3 Test App (iOS) | +|------|-------------------|----------------|---------------------| +| List devices | `emulator -list-avds` | `xcrun simctl list devices` | `xcrun simctl list devices` | +| Boot device | `emulator -avd ` | `xcrun simctl boot ` | `xcrun simctl boot ` | +| Install app | `adb install ` | `xcrun simctl install booted ` | `xcrun simctl install booted ` | +| Launch app | `adb shell am start` | `xcrun simctl launch booted ` | `xcrun simctl launch booted ` | +| View logs | `adb logcat` | `xcrun simctl spawn booted log stream` | `xcrun simctl spawn booted log stream` | +| Build command | `./gradlew assembleDebug` | `xcodebuild -workspace ...` | `xcodebuild -workspace ...` | + +--- + +## Troubleshooting + +### Simulator Won't Boot + +```bash +# Check Xcode command line tools +xcode-select -p + +# Reinstall command line tools +sudo xcode-select --reset + +# Verify simulator runtime +xcrun simctl runtime list +``` + +### Build Fails + +```bash +# Clean build folder +cd ios/App # or ios/App for Vue 3 app +xcodebuild clean -workspace App.xcworkspace -scheme App + +# Reinstall CocoaPods dependencies +cd ../.. # Back to ios/ directory +pod install --repo-update + +# Rebuild +cd App +xcodebuild -workspace App.xcworkspace -scheme App -configuration Debug +``` + +### App Won't Install + +```bash +# Check if simulator is booted +xcrun simctl list devices | grep Booted + +# Verify app path exists +ls -la ios/App/build/derivedData/Build/Products/Debug-iphonesimulator/ + +# Check bundle identifier +plutil -extract CFBundleIdentifier raw ios/App/App/Info.plist +``` + +### Vue 3 App: Web Assets Not Syncing + +```bash +# Rebuild web assets +cd test-apps/daily-notification-test +npm run build + +# Force sync +npx cap sync ios --force + +# Verify assets are synced +ls -la ios/App/App/public/ +``` + +### Logs Not Showing + +```bash +# Use Console.app for better log viewing +open -a Console + +# Or use log command with filters +log stream --predicate 'processImagePath contains "App"' --level debug --style compact +``` + +--- + +## Additional Resources + +- [Capacitor iOS Documentation](https://capacitorjs.com/docs/ios) +- [Xcode Command Line Tools](https://developer.apple.com/xcode/resources/) +- [Simulator Documentation](https://developer.apple.com/documentation/xcode/running-your-app-in-the-simulator-or-on-a-device) + +--- + +**Note**: iOS development requires macOS. This guide assumes you're running on a Mac with Xcode installed. + +**Key Distinction**: +- **`ios/App`** = Native iOS development app (simple, for quick testing) +- **`test-apps/daily-notification-test`** = Vue 3 test app (full-featured, for comprehensive testing) + diff --git a/ios/App/App/public/index.html b/ios/App/App/public/index.html index 3c73f24..be40a1c 100644 --- a/ios/App/App/public/index.html +++ b/ios/App/App/public/index.html @@ -3,6 +3,9 @@ + + + DailyNotification Plugin Test

🔔 DailyNotification Plugin Test

-

Test the DailyNotification plugin functionality

- - - - -
- Ready to test... + +
+

📊 Plugin Status

+
+ + + + +
+
Ready to test...
-
- diff --git a/ios/DailyNotificationPlugin.podspec b/ios/DailyNotificationPlugin.podspec index c598811..305dcd4 100644 --- a/ios/DailyNotificationPlugin.podspec +++ b/ios/DailyNotificationPlugin.podspec @@ -8,8 +8,8 @@ Pod::Spec.new do |s| 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', '~> 5.0.0' - s.dependency 'CapacitorCordova', '~> 5.0.0' + s.dependency 'Capacitor', '~> 6.0' + s.dependency 'CapacitorCordova', '~> 6.0' s.swift_version = '5.1' s.xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) COCOAPODS=1' } s.deprecated = false diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 0ce8e0e..5608a2d 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,10 +1,10 @@ PODS: - - Capacitor (5.0.0): + - Capacitor (6.2.1): - CapacitorCordova - - CapacitorCordova (5.0.0) + - CapacitorCordova (6.2.1) - DailyNotificationPlugin (1.0.0): - - Capacitor (~> 5.0.0) - - CapacitorCordova (~> 5.0.0) + - Capacitor (~> 6.0) + - CapacitorCordova (~> 6.0) DEPENDENCIES: - "Capacitor (from `../node_modules/@capacitor/ios`)" @@ -20,9 +20,9 @@ EXTERNAL SOURCES: :path: "." SPEC CHECKSUMS: - Capacitor: ba8cd5cce13c6ab3c4faf7ef98487be481c9c1c8 - CapacitorCordova: 4ea17670ee562680988a7ce9db68dee5160fe564 - DailyNotificationPlugin: 745a0606d51baec6fc9a025f1de1ade125ed193a + Capacitor: 1e0d0e7330dea9f983b50da737d8918abcf273f8 + CapacitorCordova: 8d93e14982f440181be7304aa9559ca631d77fff + DailyNotificationPlugin: 79f269b45580c89b044ece1cfe09293b7e974d98 PODFILE CHECKSUM: ac8c229d24347f6f83e67e6b95458e0b81e68f7c diff --git a/nvm-install.sh b/nvm-install.sh new file mode 100755 index 0000000..32050a3 --- /dev/null +++ b/nvm-install.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# Quick NVM setup script + +set -e + +echo "Installing NVM (Node Version Manager)..." +curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash + +echo "" +echo "NVM installed! Please run:" +echo " source ~/.zshrc" +echo "" +echo "Then install Node.js with:" +echo " nvm install --lts" +echo " nvm use --lts" +echo " nvm alias default node" diff --git a/package-lock.json b/package-lock.json index e970a1f..13cdd10 100644 --- a/package-lock.json +++ b/package-lock.json @@ -100,6 +100,7 @@ "integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.2", @@ -650,6 +651,7 @@ "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" } @@ -752,6 +754,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -775,6 +778,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" } @@ -2926,6 +2930,7 @@ "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "5.62.0", "@typescript-eslint/types": "5.62.0", @@ -3129,6 +3134,7 @@ "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3544,6 +3550,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", @@ -4693,6 +4700,7 @@ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -6250,6 +6258,7 @@ "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", @@ -7116,6 +7125,7 @@ "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "cssstyle": "^4.2.1", "data-urls": "^5.0.0", @@ -9575,6 +9585,7 @@ "integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==", "dev": true, "license": "MIT", + "peer": true, "bin": { "rollup": "dist/bin/rollup" }, @@ -10527,6 +10538,7 @@ "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/scripts/build-and-deploy-native-ios.sh b/scripts/build-and-deploy-native-ios.sh new file mode 100755 index 0000000..a35e713 --- /dev/null +++ b/scripts/build-and-deploy-native-ios.sh @@ -0,0 +1,161 @@ +#!/bin/bash +# Native iOS Development App Build and Deploy Script +# Builds and deploys the ios/App development app to iOS Simulator +# Similar to android/app - a simple Capacitor app for plugin development + +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 + +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" +} + +# Get script directory +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" + +# Check if we're in the project root +if [ ! -d "$PROJECT_ROOT/ios/App" ]; then + log_error "ios/App directory not found" + log_info "This script must be run from the project root directory" + log_info "Usage: cd /path/to/daily-notification-plugin && ./scripts/build-and-deploy-native-ios.sh" + exit 1 +fi + +# Check prerequisites +log_step "Checking prerequisites..." + +if ! command -v xcodebuild &> /dev/null; then + log_error "xcodebuild not found. Install Xcode command line tools:" + log_info " xcode-select --install" + exit 1 +fi + +if ! command -v pod &> /dev/null; then + log_error "CocoaPods not found. Install with:" + log_info " gem install cocoapods" + exit 1 +fi + +# Get simulator device (default to iPhone 15 Pro) +SIMULATOR_DEVICE="${1:-iPhone 15 Pro}" +log_info "Using simulator: $SIMULATOR_DEVICE" + +# Boot simulator +log_step "Booting simulator..." +if xcrun simctl list devices | grep -q "$SIMULATOR_DEVICE.*Booted"; then + log_info "Simulator already booted" +else + # Try to boot the device + if xcrun simctl boot "$SIMULATOR_DEVICE" 2>/dev/null; then + log_info "✓ Simulator booted" + else + log_warn "Could not boot simulator automatically" + log_info "Opening Simulator app... (you may need to select device manually)" + open -a Simulator + sleep 5 + fi +fi + +# Build plugin +log_step "Building plugin..." +cd "$PROJECT_ROOT" +if ! ./scripts/build-native.sh --platform ios; then + log_error "Plugin build failed" + exit 1 +fi + +# Install CocoaPods dependencies +log_step "Installing CocoaPods dependencies..." +cd "$PROJECT_ROOT/ios" +if [ ! -f "Podfile.lock" ] || [ "Podfile" -nt "Podfile.lock" ]; then + pod install +else + log_info "CocoaPods dependencies up to date" +fi + +# Build iOS app +log_step "Building native iOS development app..." +cd "$PROJECT_ROOT/ios/App" +WORKSPACE="App.xcworkspace" +SCHEME="App" +CONFIG="Debug" +SDK="iphonesimulator" + +if ! xcodebuild -workspace "$WORKSPACE" \ + -scheme "$SCHEME" \ + -configuration "$CONFIG" \ + -sdk "$SDK" \ + -destination "platform=iOS Simulator,name=$SIMULATOR_DEVICE" \ + -derivedDataPath build/derivedData \ + CODE_SIGN_IDENTITY="" \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGNING_ALLOWED=NO \ + clean build; then + log_error "iOS app build failed" + exit 1 +fi + +# Find built app +APP_PATH=$(find build/derivedData -name "*.app" -type d -path "*/Build/Products/*-iphonesimulator/*.app" | head -1) + +if [ -z "$APP_PATH" ]; then + log_error "Could not find built app" + log_info "Searching in: build/derivedData" + find build/derivedData -name "*.app" -type d 2>/dev/null | head -5 + exit 1 +fi + +log_info "Found app: $APP_PATH" + +# Install app on simulator +log_step "Installing app on simulator..." +if xcrun simctl install booted "$APP_PATH"; then + log_info "✓ App installed" +else + log_error "Failed to install app" + exit 1 +fi + +# Get bundle identifier +BUNDLE_ID=$(plutil -extract CFBundleIdentifier raw App/Info.plist 2>/dev/null || echo "com.timesafari.dailynotification") +log_info "Bundle ID: $BUNDLE_ID" + +# Launch app +log_step "Launching app..." +if xcrun simctl launch booted "$BUNDLE_ID"; then + log_info "✓ App launched" +else + log_warn "App may already be running" +fi + +log_info "" +log_info "✅ Build and deploy complete!" +log_info "" +log_info "To view logs:" +log_info " xcrun simctl spawn booted log stream" +log_info "" +log_info "To uninstall app:" +log_info " xcrun simctl uninstall booted $BUNDLE_ID" +log_info "" +log_info "Note: This is the native iOS development app (ios/App)" +log_info "For the Vue 3 test app, use: test-apps/daily-notification-test/scripts/build-and-deploy-ios.sh" + diff --git a/scripts/build-native.sh b/scripts/build-native.sh index 7c598b7..5b4c80d 100755 --- a/scripts/build-native.sh +++ b/scripts/build-native.sh @@ -7,6 +7,7 @@ set -e RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' +BLUE='\033[0;34m' NC='\033[0m' # No Color # Logging functions @@ -22,6 +23,10 @@ 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 @@ -31,9 +36,68 @@ check_command() { } check_environment() { - # Check for required tools + local platform=$1 + + # Initialize NVM if available (for Node.js version management) + if [ -s "$HOME/.nvm/nvm.sh" ]; then + log_info "Loading NVM..." + export NVM_DIR="$HOME/.nvm" + [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" + [ -s "$NVM_DIR/bash_completion" ] && . "$NVM_DIR/bash_completion" + + # Use default Node.js version if available + if [ -f "$NVM_DIR/alias/default" ]; then + DEFAULT_NODE=$(cat "$NVM_DIR/alias/default") + if [ -n "$DEFAULT_NODE" ]; then + nvm use default >/dev/null 2>&1 || true + fi + fi + + # Use latest LTS if no default + if ! command -v node &> /dev/null; then + log_info "No default Node.js version set, using latest LTS..." + nvm use --lts >/dev/null 2>&1 || nvm install --lts >/dev/null 2>&1 || true + fi + fi + + # Common checks check_command "node" check_command "npm" + + # Check Node.js version + NODE_VERSION=$(node -v | cut -d. -f1 | tr -d 'v') + if [ -z "$NODE_VERSION" ] || ! [[ "$NODE_VERSION" =~ ^[0-9]+$ ]]; then + log_error "Could not determine Node.js version" + log_error "Please install Node.js: nvm install --lts (if using NVM)" + exit 1 + fi + if [ "$NODE_VERSION" -lt 14 ]; then + log_error "Node.js version 14 or higher is required (found: $NODE_VERSION)" + exit 1 + fi + + # Platform-specific checks + case $platform in + "android") + check_environment_android + ;; + "ios") + check_environment_ios + ;; + "all") + check_environment_android + check_environment_ios + ;; + *) + log_error "Invalid platform: $platform" + exit 1 + ;; + esac +} + +check_environment_android() { + log_step "Checking Android environment..." + check_command "java" # Check for Gradle Wrapper instead of system gradle @@ -41,31 +105,98 @@ check_environment() { log_error "Gradle wrapper not found at android/gradlew" exit 1 fi - - # Check Node.js version - NODE_VERSION=$(node -v | cut -d. -f1 | tr -d 'v') - if [ "$NODE_VERSION" -lt 14 ]; then - log_error "Node.js version 14 or higher is required" + + # Check Java version (more robust parsing) + JAVA_VERSION_OUTPUT=$(java -version 2>&1 | head -n 1) + if [ -z "$JAVA_VERSION_OUTPUT" ]; then + log_error "Could not determine Java version" exit 1 fi - - # Check Java version - JAVA_VERSION=$(java -version 2>&1 | head -n 1 | cut -d'"' -f2 | cut -d. -f1) + + # Try multiple parsing methods for different Java output formats + JAVA_VERSION=$(echo "$JAVA_VERSION_OUTPUT" | grep -oE 'version "([0-9]+)' | grep -oE '[0-9]+' | head -1) + + # Fallback: try to extract from "openjdk version" or "java version" format + if [ -z "$JAVA_VERSION" ]; then + JAVA_VERSION=$(echo "$JAVA_VERSION_OUTPUT" | sed -E 's/.*version "([0-9]+).*/\1/' | head -1) + fi + + # Validate we got a number + if [ -z "$JAVA_VERSION" ] || ! [[ "$JAVA_VERSION" =~ ^[0-9]+$ ]]; then + log_error "Could not parse Java version from: $JAVA_VERSION_OUTPUT" + log_error "Please ensure Java is installed correctly" + exit 1 + fi + if [ "$JAVA_VERSION" -lt 11 ]; then - log_error "Java version 11 or higher is required" + log_error "Java version 11 or higher is required (found: $JAVA_VERSION)" exit 1 fi - + # Check for Android SDK if [ -z "$ANDROID_HOME" ]; then log_error "ANDROID_HOME environment variable is not set" + log_error "Set it with: export ANDROID_HOME=/path/to/android/sdk" + exit 1 + fi + + log_info "✓ Android environment OK (Java $JAVA_VERSION)" +} + +check_environment_ios() { + log_step "Checking iOS environment..." + + # Check for Xcode command line tools + if ! command -v xcodebuild &> /dev/null; then + log_error "xcodebuild not found. Install Xcode Command Line Tools:" + log_error " xcode-select --install" + exit 1 + fi + + # Check for CocoaPods + if ! command -v pod &> /dev/null; then + log_error "CocoaPods not found. Install with:" + log_error " sudo gem install cocoapods" + exit 1 + fi + + # Check for Swift + if ! command -v swift &> /dev/null; then + log_error "Swift compiler not found" + exit 1 + fi + + # Verify workspace exists + if [ ! -d "ios/DailyNotificationPlugin.xcworkspace" ]; then + log_error "iOS workspace not found: ios/DailyNotificationPlugin.xcworkspace" exit 1 fi + + log_info "✓ iOS environment OK" } # Build functions build_typescript() { log_info "Building TypeScript..." + + # Ensure npm dependencies are installed + if [ ! -d "node_modules" ]; then + log_step "Installing npm dependencies..." + if ! npm install; then + log_error "Failed to install npm dependencies" + exit 1 + fi + else + # Check if package.json changed (compare with package-lock.json) + if [ -f "package-lock.json" ] && [ "package.json" -nt "package-lock.json" ]; then + log_step "package.json changed, updating dependencies..." + if ! npm install; then + log_error "Failed to update npm dependencies" + exit 1 + fi + fi + fi + npm run clean if ! npm run build; then log_error "TypeScript build failed" @@ -149,33 +280,6 @@ build_android() { # ============================================================================= # AUTOMATIC FIX: capacitor.build.gradle for Plugin Development Projects # ============================================================================= - # - # PROBLEM: The capacitor.build.gradle file is auto-generated by Capacitor CLI - # and includes a line that tries to load a file that doesn't exist in plugin - # development projects: - # apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle" - # - # WHY THIS HAPPENS: - # - This file is generated by 'npx cap sync', 'npx cap update', etc. - # - It assumes a full Capacitor app with proper plugin integration - # - Plugin development projects don't have the full Capacitor setup - # - # THE FIX: - # - Comment out the problematic line to prevent build failures - # - Add explanatory comment about why it's commented out - # - This fix gets applied automatically every time the build script runs - # - # WHEN THIS FIX GETS OVERWRITTEN: - # - Running 'npx cap sync' will regenerate the file and remove our fix - # - Running 'npx cap update' will regenerate the file and remove our fix - # - Running 'npx cap add android' will regenerate the file and remove our fix - # - # HOW TO RESTORE THE FIX: - # - Run this build script again (it will reapply the fix automatically) - # - Or run: ./scripts/fix-capacitor-build.sh - # - Or manually comment out the problematic line - # - # ============================================================================= if [ -f "app/capacitor.build.gradle" ]; then if grep -q "^apply from: \"../capacitor-cordova-android-plugins/cordova.variables.gradle\"" "app/capacitor.build.gradle"; then @@ -237,6 +341,185 @@ build_android() { cd .. } +build_ios() { + log_info "Building iOS..." + + cd ios || exit 1 + + # Build configuration (define early for validation) + SCHEME="DailyNotificationPlugin" + CONFIG="Release" + WORKSPACE="DailyNotificationPlugin.xcworkspace" + + # Install CocoaPods dependencies + log_step "Installing CocoaPods dependencies..." + if [ ! -f "Podfile.lock" ] || [ "Podfile" -nt "Podfile.lock" ] || [ ! -d "Pods" ] || [ ! -d "Pods/Target Support Files" ]; then + log_info "Podfile changed, Podfile.lock missing, or Pods incomplete - running pod install..." + if ! pod install --repo-update; then + log_error "Failed to install CocoaPods dependencies" + exit 1 + fi + else + log_info "Podfile.lock is up to date and Pods directory exists, skipping pod install" + fi + + # Quick Swift syntax validation (full validation happens during build) + log_step "Validating Swift syntax..." + cd Plugin + SWIFT_FILES=$(find . -name "*.swift" -type f 2>/dev/null) + if [ -z "$SWIFT_FILES" ]; then + log_warn "No Swift files found in Plugin directory" + else + # Use swiftc with iOS SDK for basic syntax check + IOS_SDK=$(xcrun --show-sdk-path --sdk iphoneos 2>/dev/null) + if [ -n "$IOS_SDK" ]; then + for swift_file in $SWIFT_FILES; do + # Quick syntax check without full compilation + if ! swiftc -sdk "$IOS_SDK" -target arm64-apple-ios16.0 -parse "$swift_file" 2>&1 | grep -q "error:"; then + continue + else + log_warn "Syntax check found issues in $swift_file (will be caught during build)" + # Don't exit - let xcodebuild catch real errors + fi + done + else + log_warn "Could not find iOS SDK, skipping syntax validation" + fi + fi + cd .. + + # Clean build + log_step "Cleaning iOS build..." + xcodebuild clean \ + -workspace "$WORKSPACE" \ + -scheme "$SCHEME" \ + -configuration "$CONFIG" \ + -sdk iphoneos \ + -destination 'generic/platform=iOS' \ + -quiet || { + log_warn "Clean failed or unnecessary, continuing..." + } + + # Check if iOS device platform is available + log_step "Checking iOS device platform availability..." + BUILD_DEVICE=false + + if xcodebuild -showsdks 2>&1 | grep -q "iOS.*iphoneos"; then + IOS_SDK_VERSION=$(xcrun --show-sdk-version --sdk iphoneos 2>&1) + log_info "Found iOS SDK: $IOS_SDK_VERSION" + + # Check if platform components are installed by trying a dry-run + DRY_RUN_OUTPUT=$(xcodebuild -workspace "$WORKSPACE" \ + -scheme "$SCHEME" \ + -destination 'generic/platform=iOS' \ + -dry-run 2>&1) + + if echo "$DRY_RUN_OUTPUT" | grep -q "iOS.*is not installed"; then + log_warn "iOS device platform components not installed" + log_info "To install iOS device platform components, run:" + log_info " xcodebuild -downloadPlatform iOS" + log_info "Or via Xcode: Settings > Components > iOS $IOS_SDK_VERSION" + log_info "" + log_info "Building for iOS Simulator instead (sufficient for plugin development)" + else + BUILD_DEVICE=true + fi + else + log_warn "iOS SDK not found" + fi + + # Build for device (iOS) if available + if [ "$BUILD_DEVICE" = true ]; then + log_step "Building for iOS device (arm64)..." + BUILD_OUTPUT=$(xcodebuild build \ + -workspace "$WORKSPACE" \ + -scheme "$SCHEME" \ + -configuration "$CONFIG" \ + -sdk iphoneos \ + -destination 'generic/platform=iOS' \ + -derivedDataPath build/derivedData \ + CODE_SIGN_IDENTITY="" \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGNING_ALLOWED=NO \ + 2>&1) + + if echo "$BUILD_OUTPUT" | grep -q "error.*iOS.*is not installed"; then + log_warn "iOS device build failed - platform components not installed" + echo "$BUILD_OUTPUT" > /tmp/xcodebuild_device.log + log_info "Check build log: /tmp/xcodebuild_device.log" + BUILD_DEVICE=false + elif echo "$BUILD_OUTPUT" | grep -q "BUILD SUCCEEDED"; then + log_info "✓ iOS device build completed" + else + log_warn "iOS device build completed with warnings" + echo "$BUILD_OUTPUT" > /tmp/xcodebuild_device.log + fi + fi + + # Build for simulator + log_step "Building for iOS simulator..." + SIMULATOR_BUILD_OUTPUT=$(xcodebuild build \ + -workspace "$WORKSPACE" \ + -scheme "$SCHEME" \ + -configuration "$CONFIG" \ + -sdk iphonesimulator \ + -destination 'generic/platform=iOS Simulator' \ + -derivedDataPath build/derivedData \ + CODE_SIGN_IDENTITY="" \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGNING_ALLOWED=NO \ + 2>&1) + + if echo "$SIMULATOR_BUILD_OUTPUT" | grep -q "BUILD SUCCEEDED"; then + log_info "✓ iOS simulator build completed successfully" + elif echo "$SIMULATOR_BUILD_OUTPUT" | grep -q "error:"; then + log_error "iOS simulator build failed" + echo "$SIMULATOR_BUILD_OUTPUT" | grep -E "(error:|warning:)" | head -20 + exit 1 + else + log_warn "iOS simulator build completed with warnings" + echo "$SIMULATOR_BUILD_OUTPUT" | grep -E "(warning:|error:)" | head -10 + fi + + # Find built frameworks + DEVICE_FRAMEWORK=$(find build/derivedData -path "*/Build/Products/*-iphoneos/DailyNotificationPlugin.framework" -type d | head -1) + SIMULATOR_FRAMEWORK=$(find build/derivedData -path "*/Build/Products/*-iphonesimulator/DailyNotificationPlugin.framework" -type d | head -1) + + if [ -n "$DEVICE_FRAMEWORK" ]; then + log_info "✓ Device framework: $DEVICE_FRAMEWORK" + fi + + if [ -n "$SIMULATOR_FRAMEWORK" ]; then + log_info "✓ Simulator framework: $SIMULATOR_FRAMEWORK" + fi + + # Create universal framework (optional) + if [ -n "$DEVICE_FRAMEWORK" ] && [ -n "$SIMULATOR_FRAMEWORK" ]; then + log_step "Creating universal framework..." + + UNIVERSAL_DIR="build/universal" + mkdir -p "$UNIVERSAL_DIR" + + # Copy device framework + cp -R "$DEVICE_FRAMEWORK" "$UNIVERSAL_DIR/" + + # Create universal binary + UNIVERSAL_FRAMEWORK="$UNIVERSAL_DIR/DailyNotificationPlugin.framework/DailyNotificationPlugin" + if lipo -create \ + "$DEVICE_FRAMEWORK/DailyNotificationPlugin" \ + "$SIMULATOR_FRAMEWORK/DailyNotificationPlugin" \ + -output "$UNIVERSAL_FRAMEWORK" 2>/dev/null; then + log_info "✓ Universal framework: $UNIVERSAL_DIR/DailyNotificationPlugin.framework" + else + log_warn "Universal framework creation failed (may not be needed)" + fi + fi + + cd .. + + log_info "iOS build completed successfully!" +} + # Main build process main() { log_info "Starting build process..." @@ -249,35 +532,53 @@ main() { BUILD_PLATFORM="$2" shift 2 ;; + --help|-h) + echo "Usage: $0 [--platform PLATFORM]" + echo "" + echo "Options:" + echo " --platform PLATFORM Build platform: 'android', 'ios', or 'all' (default: all)" + echo "" + echo "Examples:" + echo " $0 --platform android # Build Android only" + echo " $0 --platform ios # Build iOS only" + echo " $0 --platform all # Build both platforms" + echo " $0 # Build both platforms (default)" + exit 0 + ;; *) log_error "Unknown option: $1" + log_error "Use --help for usage information" exit 1 ;; esac done - - # Check environment - check_environment - + + # Check environment (platform-specific) + check_environment "$BUILD_PLATFORM" + # Build TypeScript build_typescript - + # Build based on platform case $BUILD_PLATFORM in "android") build_android ;; + "ios") + build_ios + ;; "all") build_android + build_ios ;; *) - log_error "Invalid platform: $BUILD_PLATFORM. Use 'android' or 'all'" + log_error "Invalid platform: $BUILD_PLATFORM. Use 'android', 'ios', or 'all'" exit 1 ;; esac - + log_info "Build completed successfully!" } # Run main function with all arguments -main "$@" \ No newline at end of file +main "$@" \ No newline at end of file diff --git a/scripts/setup-ruby.sh b/scripts/setup-ruby.sh new file mode 100755 index 0000000..2929337 --- /dev/null +++ b/scripts/setup-ruby.sh @@ -0,0 +1,250 @@ +#!/bin/bash +# Ruby Version Manager (rbenv) Setup Script +# Installs rbenv and Ruby 3.1+ for CocoaPods compatibility + +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 + +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" +} + +# Check if rbenv is already installed +if command -v rbenv &> /dev/null; then + log_info "rbenv is already installed" + RBENV_INSTALLED=true +else + log_step "Installing rbenv..." + RBENV_INSTALLED=false +fi + +# Install rbenv via Homebrew (recommended on macOS) +if [ "$RBENV_INSTALLED" = false ]; then + if command -v brew &> /dev/null; then + log_info "Installing rbenv via Homebrew..." + brew install rbenv ruby-build + + # Initialize rbenv in shell + if [ -n "$ZSH_VERSION" ]; then + SHELL_CONFIG="$HOME/.zshrc" + else + SHELL_CONFIG="$HOME/.bash_profile" + fi + + # Add rbenv initialization to shell config + if ! grep -q "rbenv init" "$SHELL_CONFIG" 2>/dev/null; then + log_info "Adding rbenv initialization to $SHELL_CONFIG..." + echo '' >> "$SHELL_CONFIG" + echo '# rbenv initialization' >> "$SHELL_CONFIG" + echo 'eval "$(rbenv init - zsh)"' >> "$SHELL_CONFIG" + fi + + # Load rbenv in current session + eval "$(rbenv init - zsh)" + + log_info "✓ rbenv installed successfully" + else + log_warn "Homebrew not found. Installing rbenv manually..." + + # Manual installation via git + if [ ! -d "$HOME/.rbenv" ]; then + git clone https://github.com/rbenv/rbenv.git ~/.rbenv + fi + + if [ ! -d "$HOME/.rbenv/plugins/ruby-build" ]; then + mkdir -p ~/.rbenv/plugins + git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build + fi + + # Add to PATH + export PATH="$HOME/.rbenv/bin:$PATH" + eval "$(rbenv init - zsh)" + + # Add to shell config + if [ -n "$ZSH_VERSION" ]; then + SHELL_CONFIG="$HOME/.zshrc" + else + SHELL_CONFIG="$HOME/.bash_profile" + fi + + if ! grep -q "rbenv init" "$SHELL_CONFIG" 2>/dev/null; then + echo '' >> "$SHELL_CONFIG" + echo '# rbenv initialization' >> "$SHELL_CONFIG" + echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> "$SHELL_CONFIG" + echo 'eval "$(rbenv init - zsh)"' >> "$SHELL_CONFIG" + fi + + log_info "✓ rbenv installed manually" + fi +fi + +# Reload shell config +log_step "Reloading shell configuration..." +if [ -n "$ZSH_VERSION" ]; then + source ~/.zshrc 2>/dev/null || true +else + source ~/.bash_profile 2>/dev/null || true +fi + +# Ensure rbenv is in PATH +export PATH="$HOME/.rbenv/bin:$PATH" +eval "$(rbenv init - zsh)" 2>/dev/null || eval "$(rbenv init - bash)" 2>/dev/null || true + +# Check current Ruby version +log_step "Checking current Ruby version..." +CURRENT_RUBY=$(ruby -v 2>/dev/null | cut -d' ' -f2 | cut -d. -f1,2) || CURRENT_RUBY="unknown" + +if [ "$CURRENT_RUBY" != "unknown" ]; then + RUBY_MAJOR=$(echo "$CURRENT_RUBY" | cut -d. -f1) + RUBY_MINOR=$(echo "$CURRENT_RUBY" | cut -d. -f2) + + if [ "$RUBY_MAJOR" -ge 3 ] && [ "$RUBY_MINOR" -ge 1 ]; then + log_info "✓ Ruby version $CURRENT_RUBY is already >= 3.1.0" + log_info "You can proceed with CocoaPods installation" + exit 0 + else + log_warn "Current Ruby version: $CURRENT_RUBY (needs 3.1.0+)" + fi +fi + +# Check if rbenv has a suitable Ruby version already installed +log_step "Checking installed Ruby versions..." +if rbenv versions | grep -qE "3\.(1|2|3|4)\."; then + INSTALLED_RUBY=$(rbenv versions | grep -E "3\.(1|2|3|4)\." | tail -1 | sed 's/^[[:space:]]*//' | cut -d' ' -f1) + log_info "Found installed Ruby version: $INSTALLED_RUBY" + + # Set as global if not already set + CURRENT_GLOBAL=$(rbenv global) + if [ "$CURRENT_GLOBAL" != "$INSTALLED_RUBY" ]; then + log_info "Setting $INSTALLED_RUBY as default..." + rbenv global "$INSTALLED_RUBY" + rbenv rehash + fi + + # Verify it works + export PATH="$HOME/.rbenv/bin:$PATH" + eval "$(rbenv init - zsh)" 2>/dev/null || eval "$(rbenv init - bash)" 2>/dev/null || true + + if ruby -rpsych -e "true" 2>/dev/null; then + VERIFIED_RUBY=$(ruby -v) + log_info "✓ Ruby $VERIFIED_RUBY is working correctly" + log_info "" + log_info "Ruby setup complete!" + log_info "" + log_info "Next steps:" + log_info " 1. Reload your shell: source ~/.zshrc" + log_info " 2. Verify Ruby: ruby -v" + log_info " 3. Install CocoaPods: gem install cocoapods" + exit 0 + else + log_warn "Installed Ruby $INSTALLED_RUBY found but psych extension not working" + log_warn "May need to reinstall Ruby or install libyaml dependencies" + fi +fi + +# Check for libyaml dependency (required for psych extension) +log_step "Checking for libyaml dependency..." +LIBYAML_FOUND=false +if command -v brew &> /dev/null; then + if brew list libyaml &> /dev/null; then + LIBYAML_FOUND=true + log_info "✓ libyaml found via Homebrew" + else + log_warn "libyaml not installed. Installing via Homebrew..." + if brew install libyaml; then + LIBYAML_FOUND=true + log_info "✓ libyaml installed successfully" + else + log_error "Failed to install libyaml via Homebrew" + fi + fi +else + # Check if libyaml headers exist in system locations + if find /usr/local /opt /Library -name "yaml.h" 2>/dev/null | grep -q yaml.h; then + LIBYAML_FOUND=true + log_info "✓ libyaml headers found in system" + else + log_warn "libyaml not found. Ruby installation may fail." + log_warn "Install libyaml via Homebrew: brew install libyaml" + log_warn "Or install via MacPorts: sudo port install libyaml" + fi +fi + +# List available Ruby versions +log_step "Fetching available Ruby versions..." +rbenv install --list | grep -E "^[[:space:]]*3\.[1-9]" | tail -5 || log_warn "Could not fetch Ruby versions list" + +# Install Ruby 3.1.0 (preferred for compatibility) +log_step "Installing Ruby 3.1.0..." +if rbenv install 3.1.0; then + log_info "✓ Ruby 3.1.0 installed successfully" + + # Set as global default + log_step "Setting Ruby 3.1.0 as default..." + rbenv global 3.1.0 + + # Verify installation + export PATH="$HOME/.rbenv/bin:$PATH" + eval "$(rbenv init - zsh)" 2>/dev/null || eval "$(rbenv init - bash)" 2>/dev/null || true + + NEW_RUBY=$(ruby -v) + log_info "✓ Current Ruby version: $NEW_RUBY" + + # Verify psych extension works + if ruby -rpsych -e "true" 2>/dev/null; then + log_info "✓ psych extension verified" + else + log_warn "psych extension may not be working correctly" + log_warn "This may affect CocoaPods installation" + fi + + # Rehash to make Ruby available + rbenv rehash + + log_info "" + log_info "Ruby setup complete!" + log_info "" + log_info "Next steps:" + log_info " 1. Reload your shell: source ~/.zshrc" + log_info " 2. Verify Ruby: ruby -v" + log_info " 3. Install CocoaPods: gem install cocoapods" + +else + log_error "Failed to install Ruby 3.1.0" + + if [ "$LIBYAML_FOUND" = false ]; then + log_error "" + log_error "Installation failed. This is likely due to missing libyaml dependency." + log_error "" + log_error "To fix:" + if command -v brew &> /dev/null; then + log_error " brew install libyaml" + else + log_error " Install Homebrew: /bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"" + log_error " Then: brew install libyaml" + fi + log_error "" + log_error "After installing libyaml, run this script again." + else + log_error "Installation failed. Please check your internet connection and try again." + fi + exit 1 +fi \ No newline at end of file diff --git a/test-apps/daily-notification-test/docs/IOS_BUILD_QUICK_REFERENCE.md b/test-apps/daily-notification-test/docs/IOS_BUILD_QUICK_REFERENCE.md new file mode 100644 index 0000000..beaf3b2 --- /dev/null +++ b/test-apps/daily-notification-test/docs/IOS_BUILD_QUICK_REFERENCE.md @@ -0,0 +1,183 @@ +# iOS Build Process Quick Reference + +**Author**: Matthew Raymer +**Date**: November 4, 2025 + +## Two Different Test Apps + +**Important**: There are two different iOS test apps: + +1. **Native iOS Development App** (`ios/App`) - Simple Capacitor app for quick plugin testing +2. **Vue 3 Test App** (`test-apps/daily-notification-test`) - Full-featured Vue 3 Capacitor app + +--- + +## Vue 3 Test App (`test-apps/daily-notification-test`) + +### 🚨 Critical Build Steps + +```bash +# 1. Build web assets +npm run build + +# 2. Sync with iOS project +npx cap sync ios + +# 3. Build iOS app +cd ios/App +xcodebuild -workspace App.xcworkspace \ + -scheme App \ + -configuration Debug \ + -sdk iphonesimulator \ + -destination 'platform=iOS Simulator,name=iPhone 15 Pro' \ + CODE_SIGN_IDENTITY="" \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGNING_ALLOWED=NO + +# 4. Install and launch +APP_PATH=$(find build/derivedData -name "*.app" -type d | head -1) +xcrun simctl install booted "$APP_PATH" +BUNDLE_ID=$(plutil -extract CFBundleIdentifier raw App/Info.plist) +xcrun simctl launch booted "$BUNDLE_ID" +``` + +### 🔄 Using Capacitor CLI (Simplest Method) + +```bash +cd test-apps/daily-notification-test + +# Build and run in one command +npx cap run ios + +# This handles: +# - Building web assets +# - Syncing with iOS +# - Building app +# - Installing on simulator +# - Launching app +``` + +### 🛠️ Automated Build Script + +```bash +cd test-apps/daily-notification-test +./scripts/build-and-deploy-ios.sh +``` + +--- + +## Native iOS Development App (`ios/App`) + +### 🚨 Critical Build Steps + +```bash +# 1. Build plugin +cd /path/to/daily-notification-plugin +./scripts/build-native.sh --platform ios + +# 2. Install CocoaPods dependencies +cd ios +pod install + +# 3. Build iOS app +cd App +xcodebuild -workspace App.xcworkspace \ + -scheme App \ + -configuration Debug \ + -sdk iphonesimulator \ + -destination 'platform=iOS Simulator,name=iPhone 15 Pro' \ + CODE_SIGN_IDENTITY="" \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGNING_ALLOWED=NO + +# 4. Install and launch +APP_PATH=$(find build/derivedData -name "*.app" -type d | head -1) +xcrun simctl install booted "$APP_PATH" +BUNDLE_ID=$(plutil -extract CFBundleIdentifier raw App/Info.plist) +xcrun simctl launch booted "$BUNDLE_ID" +``` + +### 🛠️ Automated Build Script + +```bash +cd /path/to/daily-notification-plugin +./scripts/build-and-deploy-native-ios.sh +``` + +--- + +## ⚠️ iOS-Specific Requirements + +**Prerequisites:** +- macOS (required for iOS development) +- Xcode installed (`xcode-select --install`) +- CocoaPods installed (`gem install cocoapods`) +- iOS Simulator runtime installed + +**Common Issues:** +- Simulator not booted: `xcrun simctl boot "iPhone 15 Pro"` +- CocoaPods not installed: `sudo gem install cocoapods` +- Platform components missing: `xcodebuild -downloadPlatform iOS` + +## 🔍 Verification Checklist + +After build, verify: + +### For Vue 3 Test App: +- [ ] Simulator is booted (`xcrun simctl list devices | grep Booted`) +- [ ] CocoaPods dependencies installed (`cd ios && pod install`) +- [ ] Web assets synced (`npx cap sync ios`) +- [ ] App builds successfully (`xcodebuild ...`) +- [ ] App installs on simulator (`xcrun simctl install`) +- [ ] App launches (`xcrun simctl launch`) + +### For Native iOS App: +- [ ] Simulator is booted (`xcrun simctl list devices | grep Booted`) +- [ ] Plugin built (`./scripts/build-native.sh --platform ios`) +- [ ] CocoaPods dependencies installed (`cd ios && pod install`) +- [ ] App builds successfully (`xcodebuild ...`) +- [ ] App installs on simulator (`xcrun simctl install`) +- [ ] App launches (`xcrun simctl launch`) + +## 📱 Testing Commands + +```bash +# List available simulators +xcrun simctl list devices available + +# Boot simulator +xcrun simctl boot "iPhone 15 Pro" + +# Check if booted +xcrun simctl list devices | grep Booted + +# View logs +xcrun simctl spawn booted log stream + +# Uninstall app +xcrun simctl uninstall booted com.timesafari.dailynotification.test # Vue 3 app +xcrun simctl uninstall booted com.timesafari.dailynotification # Native app + +# Reset simulator +xcrun simctl erase booted +``` + +## 🐛 Common Issues + +| Issue | Symptom | Solution | +|-------|---------|----------| +| Simulator not found | `Unable to find destination` | Run `xcrun simctl list devices` to see available devices | +| CocoaPods error | `pod: command not found` | Install CocoaPods: `gem install cocoapods` | +| Build fails | `No such file or directory` | Run `pod install` in `ios/` directory | +| Signing error | `Code signing required` | Add `CODE_SIGNING_REQUIRED=NO` to xcodebuild command | +| App won't install | `Could not find application` | Verify app path exists and simulator is booted | +| Vue app: assets not syncing | App shows blank screen | Run `npm run build && npx cap sync ios` | + +--- + +**Remember**: +- **Native iOS App** (`ios/App`) = Quick plugin testing, no web build needed +- **Vue 3 Test App** (`test-apps/...`) = Full testing with UI, requires `npm run build` + +Use `npx cap run ios` in the Vue 3 test app directory for the simplest workflow! + diff --git a/test-apps/daily-notification-test/scripts/build-and-deploy-ios.sh b/test-apps/daily-notification-test/scripts/build-and-deploy-ios.sh new file mode 100755 index 0000000..edee3ac --- /dev/null +++ b/test-apps/daily-notification-test/scripts/build-and-deploy-ios.sh @@ -0,0 +1,150 @@ +#!/bin/bash +# iOS Test App Build and Deploy Script +# Builds and deploys the DailyNotification test app to iOS Simulator + +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 + +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" +} + +# Check if we're in the test app directory +if [ ! -f "package.json" ] || [ ! -d "ios" ]; then + log_error "This script must be run from test-apps/daily-notification-test directory" + log_info "Usage: cd test-apps/daily-notification-test && ./scripts/build-and-deploy-ios.sh" + exit 1 +fi + +# Check prerequisites +log_step "Checking prerequisites..." + +if ! command -v xcodebuild &> /dev/null; then + log_error "xcodebuild not found. Install Xcode command line tools:" + log_info " xcode-select --install" + exit 1 +fi + +if ! command -v pod &> /dev/null; then + log_error "CocoaPods not found. Install with:" + log_info " gem install cocoapods" + exit 1 +fi + +# Get simulator device (default to iPhone 15 Pro) +SIMULATOR_DEVICE="${1:-iPhone 15 Pro}" +log_info "Using simulator: $SIMULATOR_DEVICE" + +# Boot simulator +log_step "Booting simulator..." +if xcrun simctl list devices | grep -q "$SIMULATOR_DEVICE.*Booted"; then + log_info "Simulator already booted" +else + # Try to boot the device + if xcrun simctl boot "$SIMULATOR_DEVICE" 2>/dev/null; then + log_info "✓ Simulator booted" + else + log_warn "Could not boot simulator automatically" + log_info "Opening Simulator app... (you may need to select device manually)" + open -a Simulator + sleep 5 + fi +fi + +# Build web assets +log_step "Building web assets..." +npm run build + +# Sync with iOS +log_step "Syncing with iOS project..." +if ! npx cap sync ios; then + log_error "Failed to sync with iOS project" + exit 1 +fi + +# Install CocoaPods dependencies +log_step "Installing CocoaPods dependencies..." +cd ios/App +if [ ! -f "Podfile.lock" ] || [ "Podfile" -nt "Podfile.lock" ]; then + pod install +else + log_info "CocoaPods dependencies up to date" +fi + +# Build iOS app +log_step "Building iOS app..." +WORKSPACE="App.xcworkspace" +SCHEME="App" +CONFIG="Debug" +SDK="iphonesimulator" + +xcodebuild -workspace "$WORKSPACE" \ + -scheme "$SCHEME" \ + -configuration "$CONFIG" \ + -sdk "$SDK" \ + -destination "platform=iOS Simulator,name=$SIMULATOR_DEVICE" \ + -derivedDataPath build/derivedData \ + CODE_SIGN_IDENTITY="" \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGNING_ALLOWED=NO \ + clean build + +# Find built app +APP_PATH=$(find build/derivedData -name "*.app" -type d -path "*/Build/Products/*-iphonesimulator/*.app" | head -1) + +if [ -z "$APP_PATH" ]; then + log_error "Could not find built app" + log_info "Searching in: build/derivedData" + exit 1 +fi + +log_info "Found app: $APP_PATH" + +# Install app on simulator +log_step "Installing app on simulator..." +if xcrun simctl install booted "$APP_PATH"; then + log_info "✓ App installed" +else + log_error "Failed to install app" + exit 1 +fi + +# Get bundle identifier +BUNDLE_ID=$(plutil -extract CFBundleIdentifier raw App/Info.plist 2>/dev/null || echo "com.timesafari.dailynotification.test") +log_info "Bundle ID: $BUNDLE_ID" + +# Launch app +log_step "Launching app..." +if xcrun simctl launch booted "$BUNDLE_ID"; then + log_info "✓ App launched" +else + log_warn "App may already be running" +fi + +log_info "" +log_info "✅ Build and deploy complete!" +log_info "" +log_info "To view logs:" +log_info " xcrun simctl spawn booted log stream" +log_info "" +log_info "To uninstall app:" +log_info " xcrun simctl uninstall booted $BUNDLE_ID" +