Skip to content

Build FadCam Pro+ APK (Custom) #5

Build FadCam Pro+ APK (Custom)

Build FadCam Pro+ APK (Custom) #5

name: Build FadCam Pro+ APK (Custom)
on:
workflow_dispatch:
inputs:
icon_base64:
description: 'Icon image as base64 string (PNG/JPG)'
required: true
type: string
app_name:
description: 'Custom app name (max 50 chars, alphanumeric + spaces)'
required: true
type: string
jobs:
build-pro-plus-apk:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Java 17
uses: actions/setup-java@v4
with:
java-version: 17
distribution: 'temurin'
cache: 'gradle'
- name: Install ImageMagick and WebP tools
run: |
sudo apt-get update
sudo apt-get install -y imagemagick webp
- name: Setup local.properties with release keystore
run: |
echo "KEYSTORE_FILE=$RUNNER_TEMP/release.keystore" >> local.properties
echo "KEYSTORE_PASSWORD=${{ secrets.KEYSTORE_PASSWORD }}" >> local.properties
echo "KEY_ALIAS=${{ secrets.KEY_ALIAS }}" >> local.properties
echo "KEY_PASSWORD=${{ secrets.KEY_PASSWORD }}" >> local.properties
- name: Decode and write keystore
run: |
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > $RUNNER_TEMP/release.keystore
if [ ! -f "$RUNNER_TEMP/release.keystore" ]; then
echo "❌ Keystore file not created"
exit 1
fi
echo "✓ Keystore file created"
echo "✓ local.properties configured"
- name: Validate and sanitize app name
run: |
APP_NAME="${{ inputs.app_name }}"
# Check length
if [ ${#APP_NAME} -gt 50 ]; then
echo "❌ App name must be 50 characters or less"
exit 1
fi
# Remove leading/trailing whitespace and special characters
# Keep only alphanumeric, spaces, and hyphens
SANITIZED=$(echo "$APP_NAME" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | sed 's/[^a-zA-Z0-9 -]//g')
# Verify it's not empty after sanitization
if [ -z "$SANITIZED" ]; then
echo "❌ App name contains no valid characters"
exit 1
fi
echo "FINAL_APP_NAME=$SANITIZED" >> $GITHUB_ENV
echo "✓ App name sanitized: $SANITIZED"
- name: Decode and validate icon
run: |
# Decode base64 to temp file
echo "${{ inputs.icon_base64 }}" | base64 -d > /tmp/icon_temp.png
# Check if file was created and is valid image
if ! file /tmp/icon_temp.png | grep -q "image"; then
echo "Invalid image file. Please provide a valid PNG or JPG image in base64 format"
exit 1
fi
# Check minimum size (192x192)
DIMENSIONS=$(identify -format "%wx%h" /tmp/icon_temp.png)
echo "Icon dimensions: $DIMENSIONS"
WIDTH=$(echo $DIMENSIONS | cut -d'x' -f1)
HEIGHT=$(echo $DIMENSIONS | cut -d'x' -f2)
if [ $WIDTH -lt 192 ] || [ $HEIGHT -lt 192 ]; then
echo "Icon must be at least 192x192 pixels"
exit 1
fi
echo "✓ Icon validated: ${WIDTH}x${HEIGHT}"
- name: Process icon - resize and convert to WebP
run: |
# Define density sizes (mdpi, hdpi, xhdpi, xxhdpi, xxxhdpi)
SIZES=(48 72 96 144 192)
DENSITY_NAMES=(mdpi hdpi xhdpi xxhdpi xxxhdpi)
# Create temp directory for processed icons
mkdir -p /tmp/icons_webp
for i in "${!SIZES[@]}"; do
SIZE=${SIZES[$i]}
DENSITY=${DENSITY_NAMES[$i]}
# Resize to square, convert to WebP
convert /tmp/icon_temp.png \
-resize ${SIZE}x${SIZE}! \
-gravity center \
-extent ${SIZE}x${SIZE} \
/tmp/icons_webp/ic_launcher_${DENSITY}.webp
echo "✓ Created ic_launcher_${DENSITY}.webp (${SIZE}x${SIZE})"
done
- name: Replace icon files in mipmap folders
run: |
SIZES=(48 72 96 144 192)
DENSITY_NAMES=(mdpi hdpi xhdpi xxhdpi xxxhdpi)
for i in "${!SIZES[@]}"; do
DENSITY=${DENSITY_NAMES[$i]}
# Replace all ic_launcher* files in this density folder
MIPMAP_DIR="app/src/main/res/mipmap-${DENSITY}"
if [ -d "$MIPMAP_DIR" ]; then
# Copy processed icon as ic_launcher_foreground (what adaptive icon uses)
cp /tmp/icons_webp/ic_launcher_${DENSITY}.webp "$MIPMAP_DIR/ic_launcher_foreground.webp"
# Also update ic_launcher.webp for non-adaptive fallback
cp /tmp/icons_webp/ic_launcher_${DENSITY}.webp "$MIPMAP_DIR/ic_launcher.webp"
echo "✓ Updated $MIPMAP_DIR"
fi
done
- name: Update app name in build config
run: |
APP_NAME="${{ inputs.app_name }}"
echo "APP_NAME=$APP_NAME" >> $GITHUB_ENV
- name: Build Pro+ APK (Custom build with user icon/name)
run: |
chmod +x ./gradlew
# Build standalone proPlus with custom app name
./gradlew assembleProPlus -PcustomAppName="${{ env.FINAL_APP_NAME }}"
- name: Verify APK was built
run: |
if [ -f "app/build/outputs/apk/default/proPlus/app-default-proPlus.apk" ]; then
echo "✓ Pro+ APK built successfully"
ls -lh app/build/outputs/apk/default/proPlus/app-default-proPlus.apk
else
echo "✗ APK not found"
ls -lh app/build/outputs/apk/default/proPlus/ || echo "Directory doesn't exist"
exit 1
fi
- name: Upload APK artifacts
uses: actions/upload-artifact@v4
with:
name: fadcam-pro-plus-apk
path: app/build/outputs/apk/default/proPlus/app-default-proPlus.apk
retention-days: 1
- name: Build summary
run: |
echo "## ✅ FadCam Pro+ APK Built Successfully" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Build Details:**" >> $GITHUB_STEP_SUMMARY
echo "- Package ID: com.fadcam.proplus" >> $GITHUB_STEP_SUMMARY
echo "- App Name: ${{ env.FINAL_APP_NAME }}" >> $GITHUB_STEP_SUMMARY
echo "- Build Type: Pro+ (Custom, Debuggable)" >> $GITHUB_STEP_SUMMARY
echo "- Architecture: arm64-v8a" >> $GITHUB_STEP_SUMMARY
echo "- Commit: ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
echo "- Timestamp: $(date -u +'%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Download:**" >> $GITHUB_STEP_SUMMARY
echo "APK is available in the workflow artifacts (expires in 24 hours)" >> $GITHUB_STEP_SUMMARY