feat(build): add iOS support to build-native.sh

Adds iOS platform support to the unified build script, enabling
building of test-apps/daily-notification-test for iOS alongside
existing Android support.

Changes:
- Add build_plugin_for_test_app_ios() to build iOS test app
- Add build_ios() function for iOS platform handling
- Make environment checks conditional based on target platform
- Add get_pod_command() helper to handle CocoaPods via rbenv
- Update main() to accept --platform ios and include iOS in "all"

This aligns the script with BUILDING.md documentation (lines 71, 75)
which implied iOS support was already available. The iOS build
process mirrors Android: creates plugin symlink, builds Vue app,
syncs Capacitor iOS (handles Podfile fixes), and builds with
xcodebuild for simulator.

Platform-specific environment checks allow iOS-only builds without
requiring Android toolchain, and vice versa.
This commit is contained in:
Jose Olarte III
2025-12-31 13:11:08 +08:00
parent 83ec604a4b
commit a7d33e2d37

View File

@@ -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 <simulator-id> && xcrun simctl install booted <app-path>"
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