Browse Source
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.shios-implementation
12 changed files with 2325 additions and 108 deletions
@ -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. |
||||
|
|
||||
@ -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 <DEVICE_ID> |
||||
|
|
||||
|
# 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 <name>` | `xcrun simctl boot <name>` | `xcrun simctl boot <name>` | |
||||
|
| Install app | `adb install <apk>` | `xcrun simctl install booted <app>` | `xcrun simctl install booted <app>` | |
||||
|
| Launch app | `adb shell am start` | `xcrun simctl launch booted <bundle>` | `xcrun simctl launch booted <bundle>` | |
||||
|
| 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) |
||||
|
|
||||
@ -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" |
||||
@ -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" |
||||
|
|
||||
@ -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 |
||||
@ -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! |
||||
|
|
||||
@ -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" |
||||
|
|
||||
Loading…
Reference in new issue