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