feat(ios): implement Phase 1 permission methods and fix build issues
Implement checkPermissionStatus() and requestNotificationPermissions() methods for iOS plugin, matching Android functionality. Fix compilation errors across plugin files and add comprehensive build/test infrastructure. Key Changes: - Add checkPermissionStatus() and requestNotificationPermissions() methods - Fix 13+ categories of Swift compilation errors (type conversions, logger API, access control, async/await, etc.) - Create DailyNotificationScheduler, DailyNotificationStorage, DailyNotificationStateActor, and DailyNotificationErrorCodes components - Fix CoreData initialization to handle missing model gracefully for Phase 1 - Add iOS test app build script with simulator auto-detection - Update directive with lessons learned from build and permission work Build Status: ✅ BUILD SUCCEEDED Test App: ✅ Ready for iOS Simulator testing Files Modified: - doc/directives/0003-iOS-Android-Parity-Directive.md (lessons learned) - ios/Plugin/DailyNotificationPlugin.swift (Phase 1 methods) - ios/Plugin/DailyNotificationModel.swift (CoreData fix) - 11+ other plugin files (compilation fixes) Files Added: - ios/Plugin/DailyNotificationScheduler.swift - ios/Plugin/DailyNotificationStorage.swift - ios/Plugin/DailyNotificationStateActor.swift - ios/Plugin/DailyNotificationErrorCodes.swift - scripts/build-ios-test-app.sh - scripts/setup-ios-test-app.sh - test-apps/ios-test-app/ (full test app) - Multiple Phase 1 documentation files
This commit is contained in:
485
scripts/build-ios-test-app.sh
Executable file
485
scripts/build-ios-test-app.sh
Executable file
@@ -0,0 +1,485 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Exit on error
|
||||
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
|
||||
|
||||
# Logging functions
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
log_step() {
|
||||
echo -e "${BLUE}[STEP]${NC} $1"
|
||||
}
|
||||
|
||||
# Validation functions
|
||||
check_command() {
|
||||
if ! command -v $1 &> /dev/null; then
|
||||
# Try rbenv shims for pod command
|
||||
if [ "$1" = "pod" ] && [ -f "$HOME/.rbenv/shims/pod" ]; then
|
||||
log_info "Found pod in rbenv shims"
|
||||
return 0
|
||||
fi
|
||||
log_error "$1 is not installed. Please install it first."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Get pod command (handles rbenv)
|
||||
get_pod_command() {
|
||||
if command -v pod &> /dev/null; then
|
||||
echo "pod"
|
||||
elif [ -f "$HOME/.rbenv/shims/pod" ]; then
|
||||
echo "$HOME/.rbenv/shims/pod"
|
||||
else
|
||||
log_error "CocoaPods (pod) not found. Please install CocoaPods first."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_environment() {
|
||||
log_step "Checking environment..."
|
||||
|
||||
# Check for required tools
|
||||
check_command "xcodebuild"
|
||||
check_command "pod"
|
||||
check_command "node"
|
||||
check_command "npm"
|
||||
|
||||
# Check for Xcode
|
||||
if ! xcodebuild -version &> /dev/null; then
|
||||
log_error "Xcode is not installed or not properly configured"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check Node.js version
|
||||
NODE_VERSION=$(node -v | cut -d. -f1 | tr -d 'v')
|
||||
if [ "$NODE_VERSION" -lt 14 ]; then
|
||||
log_error "Node.js version 14 or higher is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Environment check passed"
|
||||
}
|
||||
|
||||
# Parse arguments
|
||||
TARGET="simulator"
|
||||
BUILD_CONFIG="Debug"
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--simulator)
|
||||
TARGET="simulator"
|
||||
shift
|
||||
;;
|
||||
--device)
|
||||
TARGET="device"
|
||||
shift
|
||||
;;
|
||||
--release)
|
||||
BUILD_CONFIG="Release"
|
||||
shift
|
||||
;;
|
||||
--help)
|
||||
echo "Usage: $0 [--simulator|--device] [--release]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " --simulator Build for iOS Simulator (default)"
|
||||
echo " --device Build for physical device"
|
||||
echo " --release Build Release configuration (default: Debug)"
|
||||
echo " --help Show this help message"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
log_error "Unknown option: $1"
|
||||
echo "Use --help for usage information"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Check if iOS test app exists
|
||||
TEST_APP_DIR="test-apps/ios-test-app"
|
||||
if [ ! -d "$TEST_APP_DIR" ]; then
|
||||
log_error "iOS test app not found at $TEST_APP_DIR"
|
||||
log_info "The iOS test app needs to be created first."
|
||||
log_info "See doc/directives/0003-iOS-Android-Parity-Directive.md for requirements."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Main build function
|
||||
build_ios_test_app() {
|
||||
log_step "Building iOS test app..."
|
||||
|
||||
# Navigate to iOS App directory (where workspace is located)
|
||||
IOS_APP_DIR="$TEST_APP_DIR/ios/App"
|
||||
if [ ! -d "$IOS_APP_DIR" ]; then
|
||||
log_error "iOS App directory not found: $IOS_APP_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$IOS_APP_DIR" || exit 1
|
||||
|
||||
# Check for workspace or project (these are directories, not files)
|
||||
if [ -d "App.xcworkspace" ]; then
|
||||
WORKSPACE="App.xcworkspace"
|
||||
SCHEME="App"
|
||||
elif [ -d "App.xcodeproj" ]; then
|
||||
PROJECT="App.xcodeproj"
|
||||
SCHEME="App"
|
||||
else
|
||||
log_error "No Xcode workspace or project found in $IOS_APP_DIR"
|
||||
log_info "Expected: App.xcworkspace or App.xcodeproj"
|
||||
log_info "Found files: $(ls -la | head -10)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Install CocoaPods dependencies
|
||||
log_step "Installing CocoaPods dependencies..."
|
||||
POD_CMD=$(get_pod_command)
|
||||
if [ -f "Podfile" ]; then
|
||||
if ! $POD_CMD install; then
|
||||
log_error "CocoaPods installation failed"
|
||||
exit 1
|
||||
fi
|
||||
log_info "CocoaPods dependencies installed"
|
||||
else
|
||||
log_warn "No Podfile found, skipping pod install"
|
||||
fi
|
||||
|
||||
# Build TypeScript/JavaScript if package.json exists
|
||||
if [ -f "package.json" ]; then
|
||||
log_step "Building web assets..."
|
||||
if [ -f "package.json" ] && grep -q "\"build\"" package.json; then
|
||||
if ! npm run build; then
|
||||
log_error "Web assets build failed"
|
||||
exit 1
|
||||
fi
|
||||
log_info "Web assets built"
|
||||
fi
|
||||
|
||||
# Sync Capacitor if needed
|
||||
if command -v npx &> /dev/null && [ -f "capacitor.config.ts" ] || [ -f "capacitor.config.json" ]; then
|
||||
log_step "Syncing Capacitor..."
|
||||
if ! npx cap sync ios; then
|
||||
log_error "Capacitor sync failed"
|
||||
exit 1
|
||||
fi
|
||||
log_info "Capacitor synced"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Determine SDK and destination
|
||||
if [ "$TARGET" = "simulator" ]; then
|
||||
SDK="iphonesimulator"
|
||||
|
||||
# Initialize simulator variables
|
||||
SIMULATOR_ID=""
|
||||
SIMULATOR_NAME=""
|
||||
|
||||
# Auto-detect available iPhone simulator using device ID (more reliable)
|
||||
log_step "Detecting available iPhone simulator..."
|
||||
SIMULATOR_LINE=$(xcrun simctl list devices available 2>&1 | grep -i "iPhone" | head -1)
|
||||
|
||||
if [ -n "$SIMULATOR_LINE" ]; then
|
||||
# Extract device ID (UUID in parentheses)
|
||||
SIMULATOR_ID=$(echo "$SIMULATOR_LINE" | sed -E 's/.*\(([A-F0-9-]+)\).*/\1/')
|
||||
# Extract device name (everything before the first parenthesis)
|
||||
SIMULATOR_NAME=$(echo "$SIMULATOR_LINE" | sed -E 's/^[[:space:]]*([^(]+).*/\1/' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
||||
|
||||
if [ -n "$SIMULATOR_ID" ] && [ "$SIMULATOR_ID" != "Shutdown" ] && [ "$SIMULATOR_ID" != "Booted" ]; then
|
||||
# Use device ID (most reliable)
|
||||
DESTINATION="platform=iOS Simulator,id=$SIMULATOR_ID"
|
||||
log_info "Building for iOS Simulator ($SIMULATOR_NAME, ID: $SIMULATOR_ID)..."
|
||||
elif [ -n "$SIMULATOR_NAME" ]; then
|
||||
# Fallback to device name
|
||||
DESTINATION="platform=iOS Simulator,name=$SIMULATOR_NAME"
|
||||
log_info "Building for iOS Simulator ($SIMULATOR_NAME)..."
|
||||
else
|
||||
# Last resort: generic destination
|
||||
DESTINATION="platform=iOS Simulator,name=Any iOS Simulator Device"
|
||||
log_warn "Using generic simulator destination"
|
||||
fi
|
||||
else
|
||||
# No iPhone simulators found, use generic
|
||||
DESTINATION="platform=iOS Simulator,name=Any iOS Simulator Device"
|
||||
log_warn "No iPhone simulators found, using generic destination"
|
||||
fi
|
||||
|
||||
ARCHIVE_PATH="build/ios-test-app-simulator.xcarchive"
|
||||
else
|
||||
SDK="iphoneos"
|
||||
DESTINATION="generic/platform=iOS"
|
||||
ARCHIVE_PATH="build/ios-test-app-device.xcarchive"
|
||||
fi
|
||||
|
||||
# Clean build folder
|
||||
log_step "Cleaning build folder..."
|
||||
if [ -n "$WORKSPACE" ]; then
|
||||
xcodebuild clean -workspace "$WORKSPACE" -scheme "$SCHEME" -configuration "$BUILD_CONFIG" -sdk "$SDK" || true
|
||||
else
|
||||
xcodebuild clean -project "$PROJECT" -scheme "$SCHEME" -configuration "$BUILD_CONFIG" -sdk "$SDK" || true
|
||||
fi
|
||||
|
||||
# Build
|
||||
log_step "Building for $TARGET ($BUILD_CONFIG)..."
|
||||
if [ -n "$WORKSPACE" ]; then
|
||||
if ! xcodebuild build \
|
||||
-workspace "$WORKSPACE" \
|
||||
-scheme "$SCHEME" \
|
||||
-configuration "$BUILD_CONFIG" \
|
||||
-sdk "$SDK" \
|
||||
-destination "$DESTINATION" \
|
||||
CODE_SIGN_IDENTITY="" \
|
||||
CODE_SIGNING_REQUIRED=NO \
|
||||
CODE_SIGNING_ALLOWED=NO; then
|
||||
log_error "Build failed"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
if ! xcodebuild build \
|
||||
-project "$PROJECT" \
|
||||
-scheme "$SCHEME" \
|
||||
-configuration "$BUILD_CONFIG" \
|
||||
-sdk "$SDK" \
|
||||
-destination "$DESTINATION" \
|
||||
CODE_SIGN_IDENTITY="" \
|
||||
CODE_SIGNING_REQUIRED=NO \
|
||||
CODE_SIGNING_ALLOWED=NO; then
|
||||
log_error "Build failed"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
log_info "Build successful!"
|
||||
|
||||
# Find the built app in DerivedData
|
||||
if [ "$TARGET" = "simulator" ]; then
|
||||
# Xcode builds to DerivedData, find the app there
|
||||
DERIVED_DATA_PATH="$HOME/Library/Developer/Xcode/DerivedData"
|
||||
APP_PATH=$(find "$DERIVED_DATA_PATH" -name "App.app" -path "*/Build/Products/Debug-iphonesimulator/*" -type d 2>/dev/null | head -1)
|
||||
|
||||
if [ -n "$APP_PATH" ]; then
|
||||
log_info "App built at: $APP_PATH"
|
||||
log_info ""
|
||||
|
||||
# Boot simulator if not already booted
|
||||
log_step "Checking simulator status..."
|
||||
if [ -n "$SIMULATOR_ID" ]; then
|
||||
SIMULATOR_STATE=$(xcrun simctl list devices | grep "$SIMULATOR_ID" | grep -o "(Booted\|Shutdown)" | head -1)
|
||||
|
||||
if [ "$SIMULATOR_STATE" != "Booted" ]; then
|
||||
log_step "Booting simulator ($SIMULATOR_NAME)..."
|
||||
xcrun simctl boot "$SIMULATOR_ID" 2>/dev/null || log_warn "Simulator may already be booting"
|
||||
|
||||
# Open Simulator app if not already open
|
||||
if ! pgrep -x "Simulator" > /dev/null; then
|
||||
log_step "Opening Simulator app..."
|
||||
open -a Simulator
|
||||
fi
|
||||
|
||||
# Wait for simulator to fully boot (up to 60 seconds)
|
||||
log_step "Waiting for simulator to boot (this may take up to 60 seconds)..."
|
||||
BOOT_TIMEOUT=60
|
||||
ELAPSED=0
|
||||
CURRENT_STATE="Shutdown"
|
||||
while [ $ELAPSED -lt $BOOT_TIMEOUT ]; do
|
||||
CURRENT_STATE=$(xcrun simctl list devices | grep "$SIMULATOR_ID" | grep -o "(Booted\|Shutdown)" | head -1)
|
||||
if [ "$CURRENT_STATE" = "Booted" ]; then
|
||||
log_info "Simulator booted successfully (took ${ELAPSED}s)"
|
||||
# Give it a few more seconds to fully initialize
|
||||
sleep 3
|
||||
break
|
||||
fi
|
||||
if [ $((ELAPSED % 5)) -eq 0 ] && [ $ELAPSED -gt 0 ]; then
|
||||
log_info "Still waiting... (${ELAPSED}s elapsed)"
|
||||
fi
|
||||
sleep 1
|
||||
ELAPSED=$((ELAPSED + 1))
|
||||
done
|
||||
|
||||
if [ "$CURRENT_STATE" != "Booted" ]; then
|
||||
log_warn "Simulator may not have finished booting (waited ${ELAPSED}s)"
|
||||
log_warn "You may need to manually boot the simulator and try again"
|
||||
else
|
||||
# Verify simulator is actually ready (not just booted)
|
||||
log_info "Verifying simulator is ready..."
|
||||
READY_ATTEMPTS=0
|
||||
MAX_READY_ATTEMPTS=10
|
||||
while [ $READY_ATTEMPTS -lt $MAX_READY_ATTEMPTS ]; do
|
||||
# Try a simple command to verify simulator is responsive
|
||||
if xcrun simctl list devices | grep "$SIMULATOR_ID" | grep -q "Booted"; then
|
||||
# Try to get device info to verify it's responsive
|
||||
if xcrun simctl get_app_container "$SIMULATOR_ID" com.apple.Preferences >/dev/null 2>&1; then
|
||||
log_info "Simulator is ready"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
sleep 1
|
||||
READY_ATTEMPTS=$((READY_ATTEMPTS + 1))
|
||||
done
|
||||
if [ $READY_ATTEMPTS -eq $MAX_READY_ATTEMPTS ]; then
|
||||
log_warn "Simulator may not be fully ready yet"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
log_info "Simulator already booted"
|
||||
# Verify it's actually ready
|
||||
if ! xcrun simctl get_app_container "$SIMULATOR_ID" com.apple.Preferences >/dev/null 2>&1; then
|
||||
log_warn "Simulator is booted but may not be fully ready"
|
||||
log_info "Waiting a few seconds for simulator to be ready..."
|
||||
sleep 5
|
||||
fi
|
||||
fi
|
||||
|
||||
# Install the app
|
||||
log_step "Installing app on simulator..."
|
||||
if xcrun simctl install "$SIMULATOR_ID" "$APP_PATH" 2>&1; then
|
||||
log_info "App installed successfully"
|
||||
else
|
||||
log_warn "Install may have failed (app may already be installed)"
|
||||
fi
|
||||
|
||||
# Wait a moment for install to complete
|
||||
sleep 1
|
||||
|
||||
# Launch the app (try multiple methods)
|
||||
log_step "Launching app..."
|
||||
LAUNCH_SUCCESS=false
|
||||
LAUNCH_ERROR=""
|
||||
|
||||
# Wait a moment for simulator to be fully ready
|
||||
sleep 2
|
||||
|
||||
# Method 1: Direct launch (capture output to check for errors)
|
||||
# Note: Bundle ID is com.timesafari.dailynotification (not .test)
|
||||
log_info "Attempting to launch app..."
|
||||
LAUNCH_OUTPUT=$(xcrun simctl launch "$SIMULATOR_ID" com.timesafari.dailynotification 2>&1)
|
||||
LAUNCH_EXIT_CODE=$?
|
||||
|
||||
if [ $LAUNCH_EXIT_CODE -eq 0 ]; then
|
||||
# Check if output contains process ID (successful launch)
|
||||
# Format can be either "PID" or "bundle: PID"
|
||||
if echo "$LAUNCH_OUTPUT" | grep -qE "^[0-9]+$|^[^:]+: [0-9]+$"; then
|
||||
LAUNCH_SUCCESS=true
|
||||
# Extract PID (either standalone number or after colon)
|
||||
APP_PID=$(echo "$LAUNCH_OUTPUT" | sed -E 's/^[^:]*:? *([0-9]+).*/\1/' | head -1)
|
||||
log_info "✅ App launched successfully! (PID: $APP_PID)"
|
||||
else
|
||||
# Launch command succeeded but may not have actually launched
|
||||
log_warn "Launch command returned success but output unexpected: $LAUNCH_OUTPUT"
|
||||
fi
|
||||
else
|
||||
# Capture error message
|
||||
LAUNCH_ERROR="$LAUNCH_OUTPUT"
|
||||
log_warn "Launch failed: $LAUNCH_ERROR"
|
||||
fi
|
||||
|
||||
# Method 2: Verify app is actually running
|
||||
if [ "$LAUNCH_SUCCESS" = false ]; then
|
||||
log_info "Checking if app is already running..."
|
||||
sleep 2
|
||||
RUNNING_APPS=$(xcrun simctl listapps "$SIMULATOR_ID" 2>/dev/null | grep -A 5 "com.timesafari.dailynotification" || echo "")
|
||||
|
||||
if [ -n "$RUNNING_APPS" ]; then
|
||||
log_info "App appears to be installed. Trying to verify it's running..."
|
||||
# Try to get app state
|
||||
APP_STATE=$(xcrun simctl listapps "$SIMULATOR_ID" 2>/dev/null | grep -A 10 "com.timesafari.dailynotification" | grep "ApplicationType" || echo "")
|
||||
if [ -n "$APP_STATE" ]; then
|
||||
log_info "App found in simulator. Attempting manual launch..."
|
||||
# Try opening via Simulator app
|
||||
open -a Simulator
|
||||
sleep 1
|
||||
# Try launch one more time
|
||||
if xcrun simctl launch "$SIMULATOR_ID" com.timesafari.dailynotification >/dev/null 2>&1; then
|
||||
LAUNCH_SUCCESS=true
|
||||
log_info "✅ App launched successfully on retry!"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Final verification: check if app process is running
|
||||
if [ "$LAUNCH_SUCCESS" = true ]; then
|
||||
sleep 2
|
||||
# Try to verify app is running by checking if we can get its container
|
||||
if xcrun simctl get_app_container "$SIMULATOR_ID" com.timesafari.dailynotification >/dev/null 2>&1; then
|
||||
log_info "✅ Verified: App is installed and accessible"
|
||||
else
|
||||
log_warn "⚠️ Launch reported success but app verification failed"
|
||||
log_warn " The app may still be starting. Check the Simulator."
|
||||
fi
|
||||
else
|
||||
log_warn "❌ Automatic launch failed"
|
||||
log_info ""
|
||||
log_info "The app is installed. To launch manually:"
|
||||
log_info " 1. Open Simulator app (if not already open)"
|
||||
log_info " 2. Find the app icon on the home screen and tap it"
|
||||
log_info " 3. Or run: xcrun simctl launch $SIMULATOR_ID com.timesafari.dailynotification"
|
||||
if [ -n "$LAUNCH_ERROR" ]; then
|
||||
log_info ""
|
||||
log_info "Launch error details:"
|
||||
log_info " $LAUNCH_ERROR"
|
||||
fi
|
||||
fi
|
||||
|
||||
log_info ""
|
||||
log_info "✅ Build and deployment complete!"
|
||||
else
|
||||
log_info ""
|
||||
log_info "To run on simulator manually:"
|
||||
log_info " xcrun simctl install booted \"$APP_PATH\""
|
||||
log_info " xcrun simctl launch booted com.timesafari.dailynotification"
|
||||
fi
|
||||
else
|
||||
log_warn "Could not find built app in DerivedData"
|
||||
log_info "App was built successfully, but path detection failed."
|
||||
log_info "You can find it in Xcode's DerivedData folder or run from Xcode directly."
|
||||
fi
|
||||
else
|
||||
log_info ""
|
||||
log_info "To install on device:"
|
||||
log_info " Open App.xcworkspace in Xcode"
|
||||
log_info " Select your device"
|
||||
log_info " Press Cmd+R to build and run"
|
||||
fi
|
||||
|
||||
cd - > /dev/null
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
log_info "iOS Test App Build Script"
|
||||
log_info "Target: $TARGET | Configuration: $BUILD_CONFIG"
|
||||
log_info ""
|
||||
|
||||
check_environment
|
||||
|
||||
# Get absolute path to repo root
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
REPO_ROOT="$( cd "$SCRIPT_DIR/.." && pwd )"
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
build_ios_test_app
|
||||
|
||||
log_info ""
|
||||
log_info "✅ Build complete!"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
275
scripts/setup-ios-test-app.sh
Executable file
275
scripts/setup-ios-test-app.sh
Executable file
@@ -0,0 +1,275 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Exit on error
|
||||
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
|
||||
|
||||
# Logging functions
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
log_step() {
|
||||
echo -e "${BLUE}[STEP]${NC} $1"
|
||||
}
|
||||
|
||||
# Check prerequisites
|
||||
check_prerequisites() {
|
||||
log_step "Checking prerequisites..."
|
||||
|
||||
if ! command -v node &> /dev/null; then
|
||||
log_error "Node.js is not installed. Please install Node.js first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v npm &> /dev/null; then
|
||||
log_error "npm is not installed. Please install npm first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v npx &> /dev/null; then
|
||||
log_error "npx is not installed. Please install npx first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Prerequisites check passed"
|
||||
}
|
||||
|
||||
# Get absolute paths
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
REPO_ROOT="$( cd "$SCRIPT_DIR/.." && pwd )"
|
||||
TEST_APP_DIR="$REPO_ROOT/test-apps/ios-test-app"
|
||||
ANDROID_TEST_APP_DIR="$REPO_ROOT/test-apps/android-test-app"
|
||||
|
||||
# Main setup function
|
||||
setup_ios_test_app() {
|
||||
log_info "Setting up iOS test app..."
|
||||
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
# Check if Android test app exists (for reference)
|
||||
if [ ! -d "$ANDROID_TEST_APP_DIR" ]; then
|
||||
log_warn "Android test app not found at $ANDROID_TEST_APP_DIR"
|
||||
log_warn "Will create iOS test app from scratch"
|
||||
fi
|
||||
|
||||
# Create test-apps directory if it doesn't exist
|
||||
mkdir -p "$REPO_ROOT/test-apps"
|
||||
|
||||
# Check if iOS test app already exists
|
||||
if [ -d "$TEST_APP_DIR" ]; then
|
||||
log_warn "iOS test app already exists at $TEST_APP_DIR"
|
||||
read -p "Do you want to recreate it? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
log_info "Skipping iOS test app creation"
|
||||
return 0
|
||||
fi
|
||||
log_info "Removing existing iOS test app..."
|
||||
rm -rf "$TEST_APP_DIR"
|
||||
fi
|
||||
|
||||
log_step "Creating iOS test app directory..."
|
||||
mkdir -p "$TEST_APP_DIR"
|
||||
cd "$TEST_APP_DIR"
|
||||
|
||||
log_step "Initializing Capacitor iOS app..."
|
||||
|
||||
# Create a minimal Capacitor iOS app structure
|
||||
# Note: This creates a basic structure. Full setup requires Capacitor CLI.
|
||||
|
||||
log_info "Creating basic app structure..."
|
||||
|
||||
# Create App directory
|
||||
mkdir -p "App/App"
|
||||
mkdir -p "App/App/Public"
|
||||
|
||||
# Copy HTML from Android test app
|
||||
if [ -f "$ANDROID_TEST_APP_DIR/app/src/main/assets/public/index.html" ]; then
|
||||
log_step "Copying HTML from Android test app..."
|
||||
cp "$ANDROID_TEST_APP_DIR/app/src/main/assets/public/index.html" "App/App/Public/index.html"
|
||||
log_info "HTML copied successfully"
|
||||
else
|
||||
log_warn "Android test app HTML not found, creating minimal HTML..."
|
||||
create_minimal_html
|
||||
fi
|
||||
|
||||
# Create capacitor.config.json
|
||||
log_step "Creating capacitor.config.json..."
|
||||
cat > "capacitor.config.json" << 'EOF'
|
||||
{
|
||||
"appId": "com.timesafari.dailynotification.test",
|
||||
"appName": "DailyNotification Test App",
|
||||
"webDir": "App/App/Public",
|
||||
"server": {
|
||||
"iosScheme": "capacitor"
|
||||
},
|
||||
"plugins": {
|
||||
"DailyNotification": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Create package.json
|
||||
log_step "Creating package.json..."
|
||||
cat > "package.json" << 'EOF'
|
||||
{
|
||||
"name": "ios-test-app",
|
||||
"version": "1.0.0",
|
||||
"description": "iOS test app for DailyNotification plugin",
|
||||
"scripts": {
|
||||
"sync": "npx cap sync ios",
|
||||
"open": "npx cap open ios"
|
||||
},
|
||||
"dependencies": {
|
||||
"@capacitor/core": "^5.0.0",
|
||||
"@capacitor/ios": "^5.0.0"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
log_info "Basic structure created"
|
||||
log_warn ""
|
||||
log_warn "⚠️ IMPORTANT: This script creates a basic structure only."
|
||||
log_warn "You need to run Capacitor CLI to create the full iOS project:"
|
||||
log_warn ""
|
||||
log_warn " cd test-apps/ios-test-app"
|
||||
log_warn " npm install"
|
||||
log_warn " npx cap add ios"
|
||||
log_warn " npx cap sync ios"
|
||||
log_warn ""
|
||||
log_warn "Then configure Info.plist with BGTask identifiers (see doc/test-app-ios/IOS_TEST_APP_REQUIREMENTS.md)"
|
||||
log_warn ""
|
||||
|
||||
log_info "✅ Basic iOS test app structure created at $TEST_APP_DIR"
|
||||
}
|
||||
|
||||
# Create minimal HTML if Android HTML not available
|
||||
create_minimal_html() {
|
||||
cat > "App/App/Public/index.html" << 'EOF'
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0">
|
||||
<title>DailyNotification Plugin Test</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
color: white;
|
||||
}
|
||||
.container {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
.button {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border: 2px solid rgba(255, 255, 255, 0.3);
|
||||
color: white;
|
||||
padding: 15px 30px;
|
||||
margin: 10px;
|
||||
border-radius: 25px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
}
|
||||
.status {
|
||||
margin-top: 30px;
|
||||
padding: 20px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 10px;
|
||||
font-family: monospace;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>🔔 DailyNotification Plugin Test</h1>
|
||||
<button class="button" onclick="testPlugin()">Test Plugin</button>
|
||||
<button class="button" onclick="scheduleNotification()">Schedule Notification</button>
|
||||
<div id="status" class="status">Ready to test...</div>
|
||||
</div>
|
||||
<script>
|
||||
window.DailyNotification = window.Capacitor?.Plugins?.DailyNotification;
|
||||
|
||||
function testPlugin() {
|
||||
const status = document.getElementById('status');
|
||||
if (window.DailyNotification) {
|
||||
status.innerHTML = 'Plugin is loaded and ready!';
|
||||
status.style.background = 'rgba(0, 255, 0, 0.3)';
|
||||
} else {
|
||||
status.innerHTML = 'Plugin not available';
|
||||
status.style.background = 'rgba(255, 0, 0, 0.3)';
|
||||
}
|
||||
}
|
||||
|
||||
function scheduleNotification() {
|
||||
const status = document.getElementById('status');
|
||||
if (!window.DailyNotification) {
|
||||
status.innerHTML = 'Plugin not available';
|
||||
return;
|
||||
}
|
||||
const now = new Date();
|
||||
const time = new Date(now.getTime() + 600000);
|
||||
const timeString = time.getHours().toString().padStart(2, '0') + ':' +
|
||||
time.getMinutes().toString().padStart(2, '0');
|
||||
window.DailyNotification.scheduleDailyNotification({
|
||||
time: timeString,
|
||||
title: 'Test Notification',
|
||||
body: 'This is a test notification'
|
||||
}).then(() => {
|
||||
status.innerHTML = 'Notification scheduled for ' + timeString;
|
||||
status.style.background = 'rgba(0, 255, 0, 0.3)';
|
||||
}).catch(error => {
|
||||
status.innerHTML = 'Error: ' + error.message;
|
||||
status.style.background = 'rgba(255, 0, 0, 0.3)';
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
EOF
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
log_info "iOS Test App Setup Script"
|
||||
log_info ""
|
||||
|
||||
check_prerequisites
|
||||
setup_ios_test_app
|
||||
|
||||
log_info ""
|
||||
log_info "✅ Setup complete!"
|
||||
log_info ""
|
||||
log_info "Next steps:"
|
||||
log_info "1. cd test-apps/ios-test-app"
|
||||
log_info "2. npm install"
|
||||
log_info "3. npx cap add ios"
|
||||
log_info "4. Configure Info.plist (see doc/test-app-ios/IOS_TEST_APP_REQUIREMENTS.md)"
|
||||
log_info "5. npx cap sync ios"
|
||||
log_info "6. ./scripts/build-ios-test-app.sh --simulator"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
Reference in New Issue
Block a user