New Giftopia App Icons and Splashes #236
@@ -1360,7 +1360,7 @@ npm run assets:validate
|
|||||||
**Source Assets (Required):**
|
**Source Assets (Required):**
|
||||||
- `resources/icon.png` - App icon source
|
- `resources/icon.png` - App icon source
|
||||||
- `resources/splash.png` - Splash screen source
|
- `resources/splash.png` - Splash screen source
|
||||||
- `resources/splash_dark.png` - Dark mode splash source
|
- `resources/splash-dark.png` - Dark mode splash source
|
||||||
|
|
||||||
**Android Resources (Generated):**
|
**Android Resources (Generated):**
|
||||||
- `android/app/src/main/res/drawable/splash.png` - Splash screen drawable
|
- `android/app/src/main/res/drawable/splash.png` - Splash screen drawable
|
||||||
@@ -1604,6 +1604,11 @@ Use the commands above to check and fix code quality issues.
|
|||||||
4. **Native Build**: Platform-specific compilation
|
4. **Native Build**: Platform-specific compilation
|
||||||
5. **Package Creation**: APK/IPA generation
|
5. **Package Creation**: APK/IPA generation
|
||||||
|
|
||||||
|
`resources/` is the canonical source for app icons and splash screens.
|
||||||
|
Do not keep a legacy top-level `assets/` directory unless it is intentionally
|
||||||
|
used: `@capacitor/assets` prioritizes `assets/` over `resources/`, which can
|
||||||
|
prevent the canonical assets from being discovered.
|
||||||
|
|
||||||
## Architecture Environment Configuration
|
## Architecture Environment Configuration
|
||||||
|
|
||||||
### Environment Files
|
### Environment Files
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ icon and splash screen generation across all platforms.
|
|||||||
### Asset Sources
|
### Asset Sources
|
||||||
|
|
||||||
- **Single source of truth**: `resources/` directory (Capacitor default)
|
- **Single source of truth**: `resources/` directory (Capacitor default)
|
||||||
- **Source files**: `icon.png`, `splash.png`, `splash_dark.png`
|
- **Source files**: `icon.png`, `splash.png`, `splash-dark.png`
|
||||||
- **Format**: PNG or SVG files for optimal quality
|
- **Format**: PNG or SVG files for optimal quality
|
||||||
|
|
||||||
### Asset Generation
|
### Asset Generation
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
"icon": {
|
"icon": {
|
||||||
"android": {
|
"android": {
|
||||||
"adaptive": {
|
"adaptive": {
|
||||||
"background": "#121212",
|
"background": "resources/android/icon/icon-background.png",
|
||||||
"foreground": "resources/icon.png",
|
"foreground": "resources/android/icon/icon-foreground.png",
|
||||||
"monochrome": "resources/icon.png"
|
"monochrome": "resources/android/icon/icon-monochrome.png"
|
||||||
},
|
},
|
||||||
"target": "android/app/src/main/res"
|
"target": "android/app/src/main/res"
|
||||||
},
|
},
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
"scale": "cover",
|
"scale": "cover",
|
||||||
"target": "android/app/src/main/res"
|
"target": "android/app/src/main/res"
|
||||||
},
|
},
|
||||||
"darkSource": "resources/splash_dark.png",
|
"darkSource": "resources/splash-dark.png",
|
||||||
"ios": {
|
"ios": {
|
||||||
"target": "ios/App/App/Assets.xcassets",
|
"target": "ios/App/App/Assets.xcassets",
|
||||||
"useStoryBoard": true
|
"useStoryBoard": true
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
"scale": "cover",
|
"scale": "cover",
|
||||||
"target": "android/app/src/main/res"
|
"target": "android/app/src/main/res"
|
||||||
},
|
},
|
||||||
"darkSource": "resources/splash_dark.png",
|
"darkSource": "resources/splash-dark.png",
|
||||||
"ios": {
|
"ios": {
|
||||||
"target": "ios/App/App/Assets.xcassets",
|
"target": "ios/App/App/Assets.xcassets",
|
||||||
"useStoryBoard": true
|
"useStoryBoard": true
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ npm run build:android:studio
|
|||||||
#### Source Assets (Required)
|
#### Source Assets (Required)
|
||||||
- `resources/icon.png` - App icon source
|
- `resources/icon.png` - App icon source
|
||||||
- `resources/splash.png` - Splash screen source
|
- `resources/splash.png` - Splash screen source
|
||||||
- `resources/splash_dark.png` - Dark mode splash source
|
- `resources/splash-dark.png` - Dark mode splash source
|
||||||
|
|
||||||
#### Android Resources (Generated)
|
#### Android Resources (Generated)
|
||||||
- `android/app/src/main/res/drawable/splash.png` - Splash screen drawable
|
- `android/app/src/main/res/drawable/splash.png` - Splash screen drawable
|
||||||
@@ -201,13 +201,13 @@ mkdir -p android/app/src/main/res/mipmap-{mdpi,hdpi,xhdpi,xxhdpi,xxxhdpi}
|
|||||||
# Copy source assets to assets directory
|
# Copy source assets to assets directory
|
||||||
cp resources/icon.png assets/
|
cp resources/icon.png assets/
|
||||||
cp resources/splash.png assets/
|
cp resources/splash.png assets/
|
||||||
cp resources/splash_dark.png assets/
|
cp resources/splash-dark.png assets/
|
||||||
|
|
||||||
# Generate assets manually
|
# Generate assets manually
|
||||||
npx @capacitor/assets generate
|
npx @capacitor/assets generate
|
||||||
|
|
||||||
# Clean up
|
# Clean up
|
||||||
rm assets/icon.png assets/splash.png assets/splash_dark.png
|
rm assets/icon.png assets/splash.png assets/splash-dark.png
|
||||||
```
|
```
|
||||||
|
|
||||||
## Future Enhancements
|
## Future Enhancements
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ system to a standardized, single-source asset configuration approach using
|
|||||||
resources/ # Image sources ONLY
|
resources/ # Image sources ONLY
|
||||||
icon.png
|
icon.png
|
||||||
splash.png
|
splash.png
|
||||||
splash_dark.png
|
splash-dark.png
|
||||||
|
|
||||||
config/assets/ # Versioned config & schema
|
config/assets/ # Versioned config & schema
|
||||||
capacitor-assets.config.json
|
capacitor-assets.config.json
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"filename" : "splash@1x.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "splash@2x.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename" : "splash@3x.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 156 KiB |
@@ -56,7 +56,10 @@ npx capacitor-assets generate --web
|
|||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
Asset generation is configured in `capacitor-assets.config.json` at the project root.
|
`resources/` is this project's canonical asset source. `@capacitor/assets`
|
||||||
|
prioritizes a top-level `assets/` directory over `resources/`, so a legacy
|
||||||
|
`assets/` directory can prevent these assets from being discovered. Remove that
|
||||||
|
directory when it is empty or obsolete.
|
||||||
|
|
||||||
## Version Control
|
## Version Control
|
||||||
|
|
||||||
|
|||||||
BIN
resources/android/icon/icon-background.png
Normal file
|
After Width: | Height: | Size: 602 KiB |
BIN
resources/android/icon/icon-foreground.png
Normal file
|
After Width: | Height: | Size: 223 KiB |
BIN
resources/android/icon/icon-monochrome.png
Normal file
|
After Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 279 KiB After Width: | Height: | Size: 624 KiB |
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 3.3 MiB |
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 1.8 MiB |
|
Before Width: | Height: | Size: 279 KiB After Width: | Height: | Size: 624 KiB |
BIN
resources/ios/icon/icon-dark.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 279 KiB After Width: | Height: | Size: 624 KiB |
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 3.3 MiB |
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 1.8 MiB |
BIN
resources/splash-dark.png
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 3.3 MiB |
|
Before Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 279 KiB After Width: | Height: | Size: 624 KiB |
@@ -92,7 +92,7 @@ function generateAssetConfig(): AssetConfig {
|
|||||||
},
|
},
|
||||||
splash: {
|
splash: {
|
||||||
source: "resources/splash.png",
|
source: "resources/splash.png",
|
||||||
darkSource: "resources/splash_dark.png",
|
darkSource: "resources/splash-dark.png",
|
||||||
android: {
|
android: {
|
||||||
scale: "cover",
|
scale: "cover",
|
||||||
target: "android/app/src/main/res"
|
target: "android/app/src/main/res"
|
||||||
@@ -138,7 +138,7 @@ function validateSourceFiles(): void {
|
|||||||
const requiredFiles = [
|
const requiredFiles = [
|
||||||
'resources/icon.png',
|
'resources/icon.png',
|
||||||
'resources/splash.png',
|
'resources/splash.png',
|
||||||
'resources/splash_dark.png'
|
'resources/splash-dark.png'
|
||||||
];
|
];
|
||||||
|
|
||||||
const missingFiles = requiredFiles.filter(file => {
|
const missingFiles = requiredFiles.filter(file => {
|
||||||
|
|||||||
@@ -230,8 +230,8 @@ validate_android_assets() {
|
|||||||
missing_assets+=("resources/splash.png")
|
missing_assets+=("resources/splash.png")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -f "resources/splash_dark.png" ]; then
|
if [ ! -f "resources/splash-dark.png" ]; then
|
||||||
missing_assets+=("resources/splash_dark.png")
|
missing_assets+=("resources/splash-dark.png")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ${#missing_assets[@]} -gt 0 ]; then
|
if [ ${#missing_assets[@]} -gt 0 ]; then
|
||||||
@@ -278,14 +278,14 @@ validate_android_assets() {
|
|||||||
# Copy source assets to assets directory for capacitor-assets
|
# Copy source assets to assets directory for capacitor-assets
|
||||||
cp resources/icon.png assets/ 2>/dev/null || log_warn "Could not copy icon.png"
|
cp resources/icon.png assets/ 2>/dev/null || log_warn "Could not copy icon.png"
|
||||||
cp resources/splash.png assets/ 2>/dev/null || log_warn "Could not copy splash.png"
|
cp resources/splash.png assets/ 2>/dev/null || log_warn "Could not copy splash.png"
|
||||||
cp resources/splash_dark.png assets/ 2>/dev/null || log_warn "Could not copy splash_dark.png"
|
cp resources/splash-dark.png assets/ 2>/dev/null || log_warn "Could not copy splash-dark.png"
|
||||||
|
|
||||||
# Generate assets
|
# Generate assets
|
||||||
if npx @capacitor/assets generate >/dev/null 2>&1; then
|
if npx @capacitor/assets generate >/dev/null 2>&1; then
|
||||||
log_success "Android assets regenerated successfully"
|
log_success "Android assets regenerated successfully"
|
||||||
|
|
||||||
# Clean up temporary assets
|
# Clean up temporary assets
|
||||||
rm -f assets/icon.png assets/splash.png assets/splash_dark.png
|
rm -f assets/icon.png assets/splash.png assets/splash-dark.png
|
||||||
|
|
||||||
# Verify the resources were created
|
# Verify the resources were created
|
||||||
local verification_failed=false
|
local verification_failed=false
|
||||||
|
|||||||
@@ -172,12 +172,12 @@ check_ios_resources() {
|
|||||||
log_info "Checking iOS resources..."
|
log_info "Checking iOS resources..."
|
||||||
|
|
||||||
# Check for required assets
|
# Check for required assets
|
||||||
if [ ! -f "assets/icon.png" ]; then
|
if [ ! -f "resources/icon.png" ]; then
|
||||||
log_warn "App icon not found at assets/icon.png"
|
log_warn "App icon not found at resources/icon.png"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -f "assets/splash.png" ]; then
|
if [ ! -f "resources/splash.png" ]; then
|
||||||
log_warn "Splash screen not found at assets/splash.png"
|
log_warn "Splash screen not found at resources/splash.png"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check for iOS-specific files
|
# Check for iOS-specific files
|
||||||
@@ -192,6 +192,118 @@ check_ios_resources() {
|
|||||||
log_success "iOS resource check completed"
|
log_success "iOS resource check completed"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# iOS app icon appearance variants (Dark, Tinted, …).
|
||||||
|
# Luminosity appearance values match Apple's asset catalog format (iOS 18+).
|
||||||
|
readonly _IOS_APP_ICON_APPEARANCE_LUMINOSITY="luminosity"
|
||||||
|
readonly _IOS_APP_ICON_APPEARANCE_DARK="dark"
|
||||||
|
readonly _IOS_APP_ICON_APPEARANCE_TINTED="tinted"
|
||||||
|
|
||||||
|
# Each row: source_file|luminosity_value|dest_filename
|
||||||
|
# To add a variant: append one row and place the source PNG under resources/ios/.
|
||||||
|
readonly _IOS_APP_ICON_APPEARANCE_VARIANTS=(
|
||||||
|
"resources/ios/icon/icon-dark.png|${_IOS_APP_ICON_APPEARANCE_DARK}|AppIcon-Dark.png"
|
||||||
|
"resources/ios/icon/icon-tinted.png|${_IOS_APP_ICON_APPEARANCE_TINTED}|AppIcon-Tinted.png"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Update AppIcon.appiconset/Contents.json with one 1024×1024 appearance entry.
|
||||||
|
# Preserves all other images (including capacitor-assets output); replaces any
|
||||||
|
# existing entry for the same luminosity appearance.
|
||||||
|
_update_appicon_contents_for_appearance() {
|
||||||
|
local contents_json="$1"
|
||||||
|
local dest_filename="$2"
|
||||||
|
local luminosity_value="$3"
|
||||||
|
|
||||||
|
local tmp_file
|
||||||
|
tmp_file="$(mktemp)"
|
||||||
|
|
||||||
|
if ! jq --arg filename "$dest_filename" \
|
||||||
|
--arg appearance "$_IOS_APP_ICON_APPEARANCE_LUMINOSITY" \
|
||||||
|
--arg value "$luminosity_value" \
|
||||||
|
'
|
||||||
|
.images |= map(select((.appearances[0].value // "") != $value))
|
||||||
|
| .images += [{
|
||||||
|
"appearances": [{
|
||||||
|
"appearance": $appearance,
|
||||||
|
"value": $value
|
||||||
|
}],
|
||||||
|
"filename": $filename,
|
||||||
|
"idiom": "universal",
|
||||||
|
"platform": "ios",
|
||||||
|
"size": "1024x1024"
|
||||||
|
}]
|
||||||
|
' "$contents_json" > "$tmp_file"; then
|
||||||
|
rm -f "$tmp_file"
|
||||||
|
log_error "Failed to update AppIcon Contents.json for appearance: $luminosity_value"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mv "$tmp_file" "$contents_json"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install one appearance variant when its source PNG exists.
|
||||||
|
_apply_ios_app_icon_appearance_variant() {
|
||||||
|
local appiconset_dir="$1"
|
||||||
|
local contents_json="$2"
|
||||||
|
local source_file="$3"
|
||||||
|
local luminosity_value="$4"
|
||||||
|
local dest_filename="$5"
|
||||||
|
|
||||||
|
if [ ! -f "$source_file" ]; then
|
||||||
|
log_info "iOS app icon appearance variant not found ($source_file) — skipping"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d "$appiconset_dir" ]; then
|
||||||
|
log_warn "AppIcon.appiconset not found — skipping appearance variant ($luminosity_value)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! cp "$source_file" "$appiconset_dir/$dest_filename"; then
|
||||||
|
log_error "Failed to copy $source_file to $appiconset_dir/$dest_filename"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Installed iOS app icon appearance variant: $luminosity_value ($dest_filename)"
|
||||||
|
_update_appicon_contents_for_appearance "$contents_json" "$dest_filename" "$luminosity_value"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Post-process capacitor-assets iOS icons: copy optional Dark/Tinted sources and
|
||||||
|
# register them in AppIcon.appiconset/Contents.json.
|
||||||
|
apply_ios_app_icon_appearances() {
|
||||||
|
local appiconset_dir="ios/App/App/Assets.xcassets/AppIcon.appiconset"
|
||||||
|
local contents_json="$appiconset_dir/Contents.json"
|
||||||
|
|
||||||
|
if [ ! -f "$contents_json" ]; then
|
||||||
|
log_info "AppIcon Contents.json not found — skipping appearance variants"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v jq &> /dev/null; then
|
||||||
|
log_error "jq is required to install iOS app icon appearance variants (install with: brew install jq)"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local variant source_file luminosity_value dest_filename
|
||||||
|
for variant in "${_IOS_APP_ICON_APPEARANCE_VARIANTS[@]}"; do
|
||||||
|
IFS='|' read -r source_file luminosity_value dest_filename <<< "$variant"
|
||||||
|
_apply_ios_app_icon_appearance_variant \
|
||||||
|
"$appiconset_dir" "$contents_json" \
|
||||||
|
"$source_file" "$luminosity_value" "$dest_filename"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate iOS assets (capacitor-assets), then apply optional appearance variants.
|
||||||
|
generate_ios_assets() {
|
||||||
|
ensure_ios_capacitor_asset_directories
|
||||||
|
if [ -d "assets" ]; then
|
||||||
|
log_warn "@capacitor/assets prioritizes the top-level assets/ directory over resources/."
|
||||||
|
log_warn "This project intentionally uses resources/ as the canonical asset source."
|
||||||
|
log_warn "Remove the legacy assets/ directory if it is empty or obsolete."
|
||||||
|
fi
|
||||||
|
npx capacitor-assets generate --ios
|
||||||
|
apply_ios_app_icon_appearances
|
||||||
|
}
|
||||||
|
|
||||||
# Function to clean iOS build
|
# Function to clean iOS build
|
||||||
clean_ios_build() {
|
clean_ios_build() {
|
||||||
log_info "Cleaning iOS build artifacts..."
|
log_info "Cleaning iOS build artifacts..."
|
||||||
@@ -424,8 +536,7 @@ fi
|
|||||||
# Handle assets-only mode
|
# Handle assets-only mode
|
||||||
if [ "$ASSETS_ONLY" = true ]; then
|
if [ "$ASSETS_ONLY" = true ]; then
|
||||||
log_info "Assets-only mode: generating assets"
|
log_info "Assets-only mode: generating assets"
|
||||||
ensure_ios_capacitor_asset_directories
|
safe_execute "Generating assets" "generate_ios_assets" || exit 7
|
||||||
safe_execute "Generating assets" "npx capacitor-assets generate --ios" || exit 7
|
|
||||||
log_success "Assets generation completed successfully!"
|
log_success "Assets generation completed successfully!"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
@@ -574,8 +685,7 @@ safe_execute "Installing CocoaPods dependencies" "run_pod_install_with_workaroun
|
|||||||
safe_execute "Syncing with Capacitor" "run_cap_sync_with_workaround" || exit 6
|
safe_execute "Syncing with Capacitor" "run_cap_sync_with_workaround" || exit 6
|
||||||
|
|
||||||
# Step 7: Generate assets
|
# Step 7: Generate assets
|
||||||
ensure_ios_capacitor_asset_directories
|
safe_execute "Generating assets" "generate_ios_assets" || exit 7
|
||||||
safe_execute "Generating assets" "npx capacitor-assets generate --ios" || exit 7
|
|
||||||
|
|
||||||
# Step 8: Build iOS app
|
# Step 8: Build iOS app
|
||||||
safe_execute "Building iOS app" "build_ios_app" || exit 5
|
safe_execute "Building iOS app" "build_ios_app" || exit 5
|
||||||
|
|||||||