feat(build): add automated Android resource detection and generation
- Add generate-android-icons.sh script to create all required launcher icon sizes - Add check-android-resources.sh script to detect and fix missing Android resources - Integrate resource check into build-android.sh to prevent build failures - Fix splash screen resource naming (splash-dark.png -> splash_dark.png) - Add SplashScreen plugin configuration to capacitor.config.json - Automatically generate missing mipmap icons from assets/icon.png - Fix XML resource references to use correct drawable paths Author: Matthew Raymer SECURITY AUDIT CHECKLIST: - [x] No sensitive data exposed in generated resources - [x] Resource generation uses safe file operations - [x] Scripts include proper error handling and validation - [x] All generated files use appropriate permissions - [x] No hardcoded secrets or credentials in scripts
This commit is contained in:
@@ -16,6 +16,19 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"SplashScreen": {
|
||||||
|
"launchShowDuration": 3000,
|
||||||
|
"launchAutoHide": true,
|
||||||
|
"backgroundColor": "#ffffff",
|
||||||
|
"androidSplashResourceName": "splash",
|
||||||
|
"androidScaleType": "CENTER_CROP",
|
||||||
|
"showSpinner": false,
|
||||||
|
"androidSpinnerStyle": "large",
|
||||||
|
"iosSpinnerStyle": "small",
|
||||||
|
"spinnerColor": "#999999",
|
||||||
|
"splashFullScreen": true,
|
||||||
|
"splashImmersive": true
|
||||||
|
},
|
||||||
"CapacitorSQLite": {
|
"CapacitorSQLite": {
|
||||||
"iosDatabaseLocation": "Library/CapacitorDatabase",
|
"iosDatabaseLocation": "Library/CapacitorDatabase",
|
||||||
"iosIsEncryption": false,
|
"iosIsEncryption": false,
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
# 6 - Capacitor sync failed
|
# 6 - Capacitor sync failed
|
||||||
# 7 - Asset generation failed
|
# 7 - Asset generation failed
|
||||||
# 8 - Android Studio launch failed
|
# 8 - Android Studio launch failed
|
||||||
|
# 9 - Resource check failed
|
||||||
|
|
||||||
# Exit on any error
|
# Exit on any error
|
||||||
set -e
|
set -e
|
||||||
@@ -37,26 +38,31 @@ setup_app_directories
|
|||||||
# Load environment from .env file if it exists
|
# Load environment from .env file if it exists
|
||||||
load_env_file ".env"
|
load_env_file ".env"
|
||||||
|
|
||||||
# Step 1: Clean Android app
|
# Step 1: Check and fix Android resources
|
||||||
|
safe_execute "Checking Android resources" "$(dirname "$0")/check-android-resources.sh" || {
|
||||||
|
log_warning "Resource check found issues, but continuing with build..."
|
||||||
|
}
|
||||||
|
|
||||||
|
# Step 2: Clean Android app
|
||||||
safe_execute "Cleaning Android app" "npm run clean:android" || exit 1
|
safe_execute "Cleaning Android app" "npm run clean:android" || exit 1
|
||||||
|
|
||||||
# Step 2: Clean dist directory
|
# Step 3: Clean dist directory
|
||||||
log_info "Cleaning dist directory..."
|
log_info "Cleaning dist directory..."
|
||||||
clean_build_artifacts "dist"
|
clean_build_artifacts "dist"
|
||||||
|
|
||||||
# Step 3: Build Capacitor version
|
# Step 4: Build Capacitor version
|
||||||
safe_execute "Building Capacitor version" "npm run build:capacitor" || exit 3
|
safe_execute "Building Capacitor version" "npm run build:capacitor" || exit 3
|
||||||
|
|
||||||
# Step 4: Clean Gradle build
|
# Step 5: Clean Gradle build
|
||||||
safe_execute "Cleaning Gradle build" "cd android && ./gradlew clean && cd .." || exit 4
|
safe_execute "Cleaning Gradle build" "cd android && ./gradlew clean && cd .." || exit 4
|
||||||
|
|
||||||
# Step 5: Assemble debug build
|
# Step 6: Assemble debug build
|
||||||
safe_execute "Assembling debug build" "cd android && ./gradlew assembleDebug && cd .." || exit 5
|
safe_execute "Assembling debug build" "cd android && ./gradlew assembleDebug && cd .." || exit 5
|
||||||
|
|
||||||
# Step 6: Sync with Capacitor
|
# Step 7: Sync with Capacitor
|
||||||
safe_execute "Syncing with Capacitor" "npx cap sync android" || exit 6
|
safe_execute "Syncing with Capacitor" "npx cap sync android" || exit 6
|
||||||
|
|
||||||
# Step 7: Generate assets and open Android Studio
|
# Step 8: Generate assets and open Android Studio
|
||||||
safe_execute "Generating assets" "npx capacitor-assets generate --android" || exit 7
|
safe_execute "Generating assets" "npx capacitor-assets generate --android" || exit 7
|
||||||
safe_execute "Opening Android Studio" "npx cap open android" || exit 8
|
safe_execute "Opening Android Studio" "npx cap open android" || exit 8
|
||||||
|
|
||||||
|
|||||||
142
scripts/check-android-resources.sh
Executable file
142
scripts/check-android-resources.sh
Executable file
@@ -0,0 +1,142 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# TimeSafari Android Resource Check Script
|
||||||
|
# Checks for missing Android resources and automatically fixes common issues
|
||||||
|
# Author: Matthew Raymer
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||||
|
ANDROID_RES_DIR="$PROJECT_ROOT/android/app/src/main/res"
|
||||||
|
ASSETS_DIR="$PROJECT_ROOT/assets"
|
||||||
|
|
||||||
|
echo "=== TimeSafari Android Resource Check ==="
|
||||||
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] Checking Android resources"
|
||||||
|
|
||||||
|
# Function to check if a file exists
|
||||||
|
check_file() {
|
||||||
|
local file="$1"
|
||||||
|
local description="$2"
|
||||||
|
if [ -f "$file" ]; then
|
||||||
|
echo "[✓] $description: $file"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo "[✗] $description: $file (MISSING)"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to check if a directory exists and has files
|
||||||
|
check_directory() {
|
||||||
|
local dir="$1"
|
||||||
|
local description="$2"
|
||||||
|
if [ -d "$dir" ] && [ "$(ls -A "$dir" 2>/dev/null)" ]; then
|
||||||
|
echo "[✓] $description: $dir"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo "[✗] $description: $dir (MISSING OR EMPTY)"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Track issues
|
||||||
|
issues_found=0
|
||||||
|
fixes_applied=0
|
||||||
|
|
||||||
|
echo "[INFO] Checking splash screen resources..."
|
||||||
|
# Check splash screen resources
|
||||||
|
if ! check_file "$ANDROID_RES_DIR/drawable/splash.png" "Splash screen (light)"; then
|
||||||
|
if [ -f "$ASSETS_DIR/splash.png" ]; then
|
||||||
|
echo "[FIX] Copying splash.png to Android resources..."
|
||||||
|
cp "$ASSETS_DIR/splash.png" "$ANDROID_RES_DIR/drawable/splash.png"
|
||||||
|
fixes_applied=$((fixes_applied + 1))
|
||||||
|
else
|
||||||
|
issues_found=$((issues_found + 1))
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! check_file "$ANDROID_RES_DIR/drawable/splash_dark.png" "Splash screen (dark)"; then
|
||||||
|
if [ -f "$ASSETS_DIR/splash_dark.png" ]; then
|
||||||
|
echo "[FIX] Copying splash_dark.png to Android resources..."
|
||||||
|
cp "$ASSETS_DIR/splash_dark.png" "$ANDROID_RES_DIR/drawable/splash_dark.png"
|
||||||
|
fixes_applied=$((fixes_applied + 1))
|
||||||
|
else
|
||||||
|
issues_found=$((issues_found + 1))
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[INFO] Checking launcher icon resources..."
|
||||||
|
# Check launcher icon resources
|
||||||
|
required_icons=(
|
||||||
|
"mipmap-mdpi/ic_launcher.png"
|
||||||
|
"mipmap-hdpi/ic_launcher.png"
|
||||||
|
"mipmap-xhdpi/ic_launcher.png"
|
||||||
|
"mipmap-xxhdpi/ic_launcher.png"
|
||||||
|
"mipmap-xxxhdpi/ic_launcher.png"
|
||||||
|
"mipmap-anydpi-v26/ic_launcher.xml"
|
||||||
|
"mipmap-anydpi-v26/ic_launcher_round.xml"
|
||||||
|
)
|
||||||
|
|
||||||
|
missing_icons=0
|
||||||
|
for icon in "${required_icons[@]}"; do
|
||||||
|
if ! check_file "$ANDROID_RES_DIR/$icon" "Launcher icon: $icon"; then
|
||||||
|
missing_icons=$((missing_icons + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ $missing_icons -gt 0 ]; then
|
||||||
|
echo "[FIX] Missing launcher icons detected. Running icon generation script..."
|
||||||
|
if [ -f "$SCRIPT_DIR/generate-android-icons.sh" ]; then
|
||||||
|
"$SCRIPT_DIR/generate-android-icons.sh"
|
||||||
|
fixes_applied=$((fixes_applied + 1))
|
||||||
|
else
|
||||||
|
echo "[ERROR] Icon generation script not found: $SCRIPT_DIR/generate-android-icons.sh"
|
||||||
|
issues_found=$((issues_found + 1))
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[INFO] Checking Capacitor platform status..."
|
||||||
|
# Check if Android platform is properly initialized
|
||||||
|
if [ ! -d "$PROJECT_ROOT/android" ]; then
|
||||||
|
echo "[ERROR] Android platform directory not found"
|
||||||
|
issues_found=$((issues_found + 1))
|
||||||
|
elif [ ! -f "$PROJECT_ROOT/android/app/src/main/AndroidManifest.xml" ]; then
|
||||||
|
echo "[ERROR] AndroidManifest.xml not found - platform may be corrupted"
|
||||||
|
issues_found=$((issues_found + 1))
|
||||||
|
else
|
||||||
|
echo "[✓] Android platform appears to be properly initialized"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for common build issues
|
||||||
|
echo "[INFO] Checking for common build issues..."
|
||||||
|
|
||||||
|
# Check for invalid resource names (dashes in filenames)
|
||||||
|
invalid_resources=$(find "$ANDROID_RES_DIR" -name "*-*" -type f 2>/dev/null | grep -E '\.(png|jpg|jpeg|gif|xml)$' || true)
|
||||||
|
if [ -n "$invalid_resources" ]; then
|
||||||
|
echo "[WARNING] Found resources with invalid names (containing dashes):"
|
||||||
|
echo "$invalid_resources" | while read -r file; do
|
||||||
|
echo " - $file"
|
||||||
|
done
|
||||||
|
echo "[INFO] Android resource names must contain only lowercase a-z, 0-9, or underscore"
|
||||||
|
issues_found=$((issues_found + 1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
echo ""
|
||||||
|
echo "=== Resource Check Summary ==="
|
||||||
|
if [ $issues_found -eq 0 ] && [ $fixes_applied -eq 0 ]; then
|
||||||
|
echo "[SUCCESS] All Android resources are present and valid"
|
||||||
|
exit 0
|
||||||
|
elif [ $fixes_applied -gt 0 ]; then
|
||||||
|
echo "[SUCCESS] Fixed $fixes_applied resource issues automatically"
|
||||||
|
if [ $issues_found -gt 0 ]; then
|
||||||
|
echo "[WARNING] $issues_found issues remain that require manual attention"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "[ERROR] Found $issues_found resource issues that require manual attention"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
96
scripts/generate-android-icons.sh
Executable file
96
scripts/generate-android-icons.sh
Executable file
@@ -0,0 +1,96 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# TimeSafari Android Icon Generation Script
|
||||||
|
# Generates all required Android launcher icon sizes from assets/icon.png
|
||||||
|
# Author: Matthew Raymer
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||||
|
ASSETS_DIR="$PROJECT_ROOT/assets"
|
||||||
|
ANDROID_RES_DIR="$PROJECT_ROOT/android/app/src/main/res"
|
||||||
|
|
||||||
|
echo "=== TimeSafari Android Icon Generation ==="
|
||||||
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] Starting Android icon generation"
|
||||||
|
|
||||||
|
# Check if source icon exists
|
||||||
|
if [ ! -f "$ASSETS_DIR/icon.png" ]; then
|
||||||
|
echo "[ERROR] Source icon not found: $ASSETS_DIR/icon.png"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if ImageMagick is available
|
||||||
|
if ! command -v convert &> /dev/null; then
|
||||||
|
echo "[ERROR] ImageMagick (convert) not found. Please install ImageMagick."
|
||||||
|
echo " Arch: sudo pacman -S imagemagick"
|
||||||
|
echo " Ubuntu: sudo apt-get install imagemagick"
|
||||||
|
echo " macOS: brew install imagemagick"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create mipmap directories if they don't exist
|
||||||
|
mkdir -p "$ANDROID_RES_DIR/mipmap-hdpi"
|
||||||
|
mkdir -p "$ANDROID_RES_DIR/mipmap-mdpi"
|
||||||
|
mkdir -p "$ANDROID_RES_DIR/mipmap-xhdpi"
|
||||||
|
mkdir -p "$ANDROID_RES_DIR/mipmap-xxhdpi"
|
||||||
|
mkdir -p "$ANDROID_RES_DIR/mipmap-xxxhdpi"
|
||||||
|
|
||||||
|
echo "[INFO] Generating launcher icons..."
|
||||||
|
|
||||||
|
# Generate launcher icons for different densities
|
||||||
|
# Android launcher icon sizes: mdpi=48, hdpi=72, xhdpi=96, xxhdpi=144, xxxhdpi=192
|
||||||
|
convert "$ASSETS_DIR/icon.png" -resize 48x48 "$ANDROID_RES_DIR/mipmap-mdpi/ic_launcher.png"
|
||||||
|
convert "$ASSETS_DIR/icon.png" -resize 72x72 "$ANDROID_RES_DIR/mipmap-hdpi/ic_launcher.png"
|
||||||
|
convert "$ASSETS_DIR/icon.png" -resize 96x96 "$ANDROID_RES_DIR/mipmap-xhdpi/ic_launcher.png"
|
||||||
|
convert "$ASSETS_DIR/icon.png" -resize 144x144 "$ANDROID_RES_DIR/mipmap-xxhdpi/ic_launcher.png"
|
||||||
|
convert "$ASSETS_DIR/icon.png" -resize 192x192 "$ANDROID_RES_DIR/mipmap-xxxhdpi/ic_launcher.png"
|
||||||
|
|
||||||
|
# Generate round launcher icons
|
||||||
|
convert "$ASSETS_DIR/icon.png" -resize 48x48 "$ANDROID_RES_DIR/mipmap-mdpi/ic_launcher_round.png"
|
||||||
|
convert "$ASSETS_DIR/icon.png" -resize 72x72 "$ANDROID_RES_DIR/mipmap-hdpi/ic_launcher_round.png"
|
||||||
|
convert "$ASSETS_DIR/icon.png" -resize 96x96 "$ANDROID_RES_DIR/mipmap-xhdpi/ic_launcher_round.png"
|
||||||
|
convert "$ASSETS_DIR/icon.png" -resize 144x144 "$ANDROID_RES_DIR/mipmap-xxhdpi/ic_launcher_round.png"
|
||||||
|
convert "$ASSETS_DIR/icon.png" -resize 192x192 "$ANDROID_RES_DIR/mipmap-xxxhdpi/ic_launcher_round.png"
|
||||||
|
|
||||||
|
# Create background and foreground mipmap files
|
||||||
|
# These reference the existing drawable files
|
||||||
|
cat > "$ANDROID_RES_DIR/mipmap-anydpi-v26/ic_launcher_background.xml" << 'EOF'
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||||
|
</adaptive-icon>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > "$ANDROID_RES_DIR/mipmap-anydpi-v26/ic_launcher_foreground.xml" << 'EOF'
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||||
|
</adaptive-icon>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Update the existing launcher XML files to reference the correct resources
|
||||||
|
cat > "$ANDROID_RES_DIR/mipmap-anydpi-v26/ic_launcher.xml" << 'EOF'
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||||
|
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||||
|
</adaptive-icon>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > "$ANDROID_RES_DIR/mipmap-anydpi-v26/ic_launcher_round.xml" << 'EOF'
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||||
|
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||||
|
</adaptive-icon>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "[SUCCESS] Generated Android launcher icons:"
|
||||||
|
echo " - mipmap-mdpi/ic_launcher.png (48x48)"
|
||||||
|
echo " - mipmap-hdpi/ic_launcher.png (72x72)"
|
||||||
|
echo " - mipmap-xhdpi/ic_launcher.png (96x96)"
|
||||||
|
echo " - mipmap-xxhdpi/ic_launcher.png (144x144)"
|
||||||
|
echo " - mipmap-xxxhdpi/ic_launcher.png (192x192)"
|
||||||
|
echo " - Updated mipmap-anydpi-v26 XML files"
|
||||||
|
echo "[SUCCESS] Android icon generation completed successfully!"
|
||||||
Reference in New Issue
Block a user