diff --git a/scripts/build-native.sh b/scripts/build-native.sh index 358de4c..cb61152 100755 --- a/scripts/build-native.sh +++ b/scripts/build-native.sh @@ -25,22 +25,34 @@ log_error() { # 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 } -check_environment() { - # Check for required tools - check_command "node" - check_command "npm" - check_command "java" - - # Check for Gradle Wrapper instead of system gradle - if [ ! -f "android/gradlew" ]; then - log_error "Gradle wrapper not found at android/gradlew" +# 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() { + local PLATFORM=$1 + + # Check for required tools (always needed) + check_command "node" + check_command "npm" # Check Node.js version NODE_VERSION=$(node -v | cut -d. -f1 | tr -d 'v') @@ -49,17 +61,34 @@ check_environment() { exit 1 fi - # Check Java version - JAVA_VERSION=$(java -version 2>&1 | head -n 1 | cut -d'"' -f2 | cut -d. -f1) - if [ "$JAVA_VERSION" -lt 11 ]; then - log_error "Java version 11 or higher is required" - exit 1 - fi + # Platform-specific checks + if [ "$PLATFORM" = "android" ] || [ "$PLATFORM" = "all" ]; then + check_command "java" + + # Check for Gradle Wrapper instead of system gradle + if [ ! -f "android/gradlew" ]; then + log_error "Gradle wrapper not found at android/gradlew" + exit 1 + fi - # Check for Android SDK - if [ -z "$ANDROID_HOME" ]; then - log_error "ANDROID_HOME environment variable is not set" - exit 1 + # Check Java version + JAVA_VERSION=$(java -version 2>&1 | head -n 1 | cut -d'"' -f2 | cut -d. -f1) + if [ "$JAVA_VERSION" -lt 11 ]; then + log_error "Java version 11 or higher is required" + exit 1 + fi + + # Check for Android SDK + if [ -z "$ANDROID_HOME" ]; then + log_error "ANDROID_HOME environment variable is not set" + exit 1 + fi + fi + + if [ "$PLATFORM" = "ios" ] || [ "$PLATFORM" = "all" ]; then + # iOS checks are done in build_ios() function + # to avoid failing if iOS tools aren't available when building Android only + : fi } @@ -117,6 +146,113 @@ build_plugin_for_test_app() { cd ../../.. } +build_plugin_for_test_app_ios() { + log_info "Building iOS test app..." + + # Ensure symlink is in place FIRST (before building) + # The test app expects the plugin at node_modules/@timesafari/daily-notification-plugin + SYMLINK="test-apps/daily-notification-test/node_modules/@timesafari/daily-notification-plugin" + if [ ! -L "$SYMLINK" ] || [ ! -e "$SYMLINK" ]; then + log_info "Creating symlink to plugin..." + mkdir -p "$(dirname "$SYMLINK")" + rm -f "$SYMLINK" + ln -sf "../../../" "$SYMLINK" + fi + + # Navigate to test app directory + cd test-apps/daily-notification-test || exit 1 + + # Build Vue app + log_info "Building Vue app..." + if ! npm run build; then + log_error "Vue app build failed" + exit 1 + fi + + # Sync Capacitor iOS (handles Podfile fixes and pod install) + log_info "Syncing Capacitor iOS..." + if ! npm run cap:sync:ios; then + log_error "Capacitor iOS sync failed" + exit 1 + fi + + # Build with xcodebuild + cd ios/App || exit 1 + + # Find workspace + 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" + log_info "Expected: App.xcworkspace or App.xcodeproj" + exit 1 + fi + + # Auto-detect available iPhone simulator + log_info "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 + DESTINATION="platform=iOS Simulator,id=$SIMULATOR_ID" + log_info "Building for iOS Simulator ($SIMULATOR_NAME, ID: $SIMULATOR_ID)..." + elif [ -n "$SIMULATOR_NAME" ]; then + DESTINATION="platform=iOS Simulator,name=$SIMULATOR_NAME" + log_info "Building for iOS Simulator ($SIMULATOR_NAME)..." + else + DESTINATION="platform=iOS Simulator,name=iPhone 14" + log_warn "Using default simulator destination: iPhone 14" + fi + else + DESTINATION="platform=iOS Simulator,name=iPhone 14" + log_warn "No iPhone simulators found, using default: iPhone 14" + fi + + # Build for simulator + log_info "Building iOS app for simulator..." + if [ -n "$WORKSPACE" ]; then + if ! xcodebuild build \ + -workspace "$WORKSPACE" \ + -scheme "$SCHEME" \ + -configuration Debug \ + -sdk iphonesimulator \ + -destination "$DESTINATION" \ + CODE_SIGN_IDENTITY="" \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGNING_ALLOWED=NO; then + log_error "iOS build failed" + exit 1 + fi + else + if ! xcodebuild build \ + -project "$PROJECT" \ + -scheme "$SCHEME" \ + -configuration Debug \ + -sdk iphonesimulator \ + -destination "$DESTINATION" \ + CODE_SIGN_IDENTITY="" \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGNING_ALLOWED=NO; then + log_error "iOS build failed" + exit 1 + fi + fi + + log_info "iOS build successful!" + log_info "App built in DerivedData. To run: xcrun simctl boot && xcrun simctl install booted " + + cd ../../.. +} + build_android() { log_info "Building Android..." @@ -225,6 +361,65 @@ build_android() { cd .. } +build_ios() { + log_info "Building iOS..." + + # Check iOS-specific requirements + check_command "xcodebuild" + check_command "pod" + + # Check for Xcode + if ! xcodebuild -version &> /dev/null; then + log_error "Xcode is not installed or not properly configured" + exit 1 + fi + + # Detect project type + if [ -d "test-apps/daily-notification-test" ]; then + log_info "Detected test app. Building plugin and test app together..." + build_plugin_for_test_app_ios + return 0 + fi + + # For plugin-only builds, navigate to iOS directory + cd ios || exit 1 + + log_warn "This appears to be a plugin development project" + log_warn "iOS plugin source code has been built successfully" + log_warn "To test the plugin, use it in a Capacitor app instead" + + # Install CocoaPods dependencies if Podfile exists + if [ -f "Podfile" ]; then + log_info "Installing CocoaPods dependencies..." + POD_CMD=$(get_pod_command) + if ! $POD_CMD install; then + log_error "CocoaPods installation failed" + exit 1 + fi + fi + + # Build plugin framework (if workspace exists) + if [ -d "DailyNotificationPlugin.xcworkspace" ]; then + log_info "Building iOS plugin framework..." + if ! xcodebuild build \ + -workspace DailyNotificationPlugin.xcworkspace \ + -scheme DailyNotificationPlugin \ + -configuration Release \ + -sdk iphoneos \ + CODE_SIGN_IDENTITY="" \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGNING_ALLOWED=NO; then + log_error "iOS plugin build failed" + exit 1 + fi + log_info "iOS plugin build successful" + else + log_warn "No Xcode workspace found - plugin may need to be built in a host app" + fi + + cd .. +} + # Main build process main() { log_info "Starting build process..." @@ -244,22 +439,26 @@ main() { esac done - # Check environment - check_environment - - # Build TypeScript + # Build TypeScript (needed for all platforms) build_typescript + # Check environment (after parsing platform so we can check conditionally) + check_environment "$BUILD_PLATFORM" + # Build based on platform case $BUILD_PLATFORM in "android") build_android ;; + "ios") + build_ios + ;; "all") build_android + build_ios ;; *) - log_error "Invalid platform: $BUILD_PLATFORM. Use 'android' or 'all'" + log_error "Invalid platform: $BUILD_PLATFORM. Use 'android', 'ios', or 'all'" exit 1 ;; esac