Automating APK Customization: A Bash Script for Rebranding Android Apps
When working on Android apps, there are times when you need to customize an existing APK — maybe to modify branding elements like app colors, icons, or names. Doing this manually can be tedious. That’s where automation comes in.
In this blog, I’ll walk you through a Bash script that automates the process of:
✅ Decompiling an APK
✅ Modifying colors, app name, and icons
✅ Recompiling, signing, and installing the APK
This script is particularly useful when you need to distribute white-labeled apps for multiple clients with different branding.
1️⃣ What Does the Script Do?
This Bash script:
📌 Takes branding elements (colors, app name, icons) as arguments.
📌 Decompiles the APK using apktool
.
📌 Modifies colors.xml
and strings.xml
with new values.
📌 Replaces the app logo and icon (decoded from Base64).
📌 Recompiles and signs the modified APK.
📌 Installs the customized APK on a connected Android device.
2️⃣ Prerequisites
Before running the script, ensure you have:
✔️ apktool installed (brew install apktool
on macOS) or use apktool’s website.
✔️ ADB (Android Debug Bridge) installed (brew install android-platform-tools
).
✔️ Android SDK Build Tools (v35.0.0 in this case).
✔️ Java Keystore (JKS) file for signing the APK.
3️⃣ The Script Breakdown
🔍 Step 1: Decompile the APK
We use apktool
to extract the APK into a readable format.
apktool d app-release.apk -o modified_apk
If an old modified_apk
folder exists, it gets deleted first.
🎨 Step 2: Modify Colors and Strings
Using sed
, the script updates the colors.xml
and strings.xml
files.
Example:
sed -i '' "s|<color name=\"primaryBackgroundColor\">.*</color>|<color name=\"primaryBackgroundColor\">$PRIMARY_BACKGROUND_COLOR</color>|g" modified_apk/res/values/colors.xml
Similarly, the app name is updated in strings.xml
:
sed -i '' "s|<string name=\"app_name\">.*</string>|<string name=\"app_name\">$NEW_APP_NAME</string>|g" modified_apk/res/values/strings.xml
🖼️ Step 3: Replace App Icons and Logo
The script decodes Base64-encoded images and saves them as new icons/logos.
echo "$ICON_BASE64" | base64 --decode > modified_apk/res/drawable/ic_launcher.png
Icons are resized using ImageMagick’s convert
tool:
convert modified_apk/res/drawable/ic_launcher.png -resize 48x48 modified_apk/res/mipmap-mdpi/ic_launcher.png
This ensures icons are available in all required resolutions.
🔧 Step 4: Recompile the APK
Once the modifications are done, the script rebuilds the APK:
apktool b modified_apk -o app-recompiled.apk
This generates an unsigned APK.
🔑 Step 5: Sign the APK
A Java keystore (.jks
file) is used to sign the APK:
$BUILD_TOOLS_PATH/apksigner sign --ks $JKS_PATH --ks-pass pass:$JKS_PASSWORD --out app-signed.apk app-recompiled.apk
Signing ensures the APK can be installed on Android devices.
📱 Step 6: Install APK on Device
Finally, the script uninstalls any existing version and installs the modified APK:
adb uninstall com.appName
adb install -r app-signed.apk
Here’s the complete code:
#!/bin/bash
# Define paths (modify these as needed)
APK_NAME="path-to-your-signed-apk"
OUTPUT_APK="app-recompiled.apk"
SIGNED_APK="app-signed.apk"
JKS_PATH="path-to-your-JKS-file"
BUILD_TOOLS_PATH="path-to-your-build-tools"
JKS_PASSWORD="your-JKS-password" # ⚠️ Store securely or prompt user
APKTOOL="apktool"
ADB="adb"
COLORS_FILE="modified_apk/res/values/colors.xml"
STRINGS_FILE="modified_apk/res/values/strings.xml"
PROJECT_DIR="modified_apk/res"
MIPMAP_FOLDERS=("mipmap-mdpi" "mipmap-hdpi" "mipmap-xhdpi" "mipmap-xxhdpi" "mipmap-xxxhdpi")
SIZES=("48" "72" "96" "144" "192") # Sizes for mdpi, hdpi, xhdpi, xxhdpi, xxxhdpi
# Get parameters from command-line arguments
NEW_APP_NAME="$1"
PRIMARY_BACKGROUND_COLOR="$2"
SECONDARY_BACKGROUND_COLOR="$3"
PRIMARY_TEXT_COLOR="$4"
LOGO_BACKGROUND_COLOR="$5"
SIDE_MENU_HEADER_COLOR="$6"
MSP_LOGO_BASE64="$7" # Base64 string for the logo
ICON_BASE64="$8" # Base64 string for the icon
# Validate required arguments
if [ -z "$NEW_APP_NAME" ] || [ -z "$PRIMARY_BACKGROUND_COLOR" ] || [ -z "$SECONDARY_BACKGROUND_COLOR" ] ||
[ -z "$PRIMARY_TEXT_COLOR" ] || [ -z "$LOGO_BACKGROUND_COLOR" ] || [ -z "$SIDE_MENU_HEADER_COLOR" ] ||
[ -z "$MSP_LOGO_BASE64" ] || [ -z "$ICON_BASE64" ]; then
echo "❌ Error: Missing arguments!"
echo "Usage: $0 <app_name> <primary_bg_color> <secondary_bg_color> <primary_text_color> <logo_bg_color> <side_menu_header_color> <msp_logo_base64> <icon_base64>"
exit 1
fi
# Step 1: Decode APK
echo "🔍 Decoding APK..."
if [ -d "modified_apk" ]; then
echo "🗑️ Deleting existing 'modified_apk' folder..."
rm -rf modified_apk
fi
$APKTOOL d $APK_NAME -o modified_apk
echo "" # Line break
# Step 2: Modify colors.xml
if [ -f "$COLORS_FILE" ]; then
echo "🎨 Modifying colors.xml with user-provided colors..."
sed -i '' "s|<color name=\"primaryBackgroundColor\">.*</color>|<color name=\"primaryBackgroundColor\">$PRIMARY_BACKGROUND_COLOR</color>|g" "$COLORS_FILE"
sed -i '' "s|<color name=\"secondaryBackgroundColor\">.*</color>|<color name=\"secondaryBackgroundColor\">$SECONDARY_BACKGROUND_COLOR</color>|g" "$COLORS_FILE"
sed -i '' "s|<color name=\"primaryTextColor\">.*</color>|<color name=\"primaryTextColor\">$PRIMARY_TEXT_COLOR</color>|g" "$COLORS_FILE"
sed -i '' "s|<color name=\"logoBackgroundColor\">.*</color>|<color name=\"logoBackgroundColor\">$LOGO_BACKGROUND_COLOR</color>|g" "$COLORS_FILE"
sed -i '' "s|<color name=\"sideMenuHeaderColor\">.*</color>|<color name=\"sideMenuHeaderColor\">$SIDE_MENU_HEADER_COLOR</color>|g" "$COLORS_FILE"
echo "✅ Colors updated successfully."
else
echo "⚠️ colors.xml file not found! Skipping modifications."
fi
# Step 3: Modify strings.xml
if [ -f "$STRINGS_FILE" ]; then
echo "📝 Updating app_name in strings.xml..."
sed -i '' "s|<string name=\"app_name\">.*</string>|<string name=\"app_name\">$NEW_APP_NAME</string>|g" "$STRINGS_FILE"
echo "✅ App name updated to '$NEW_APP_NAME' in strings.xml."
else
echo "⚠️ strings.xml file not found! Skipping app name update."
fi
# Step 4: Decode Base64 logo and icon
echo "🖼️ Replacing MSP logo with the new Base64-decoded logo..."
echo "$MSP_LOGO_BASE64" | base64 --decode > "$PROJECT_DIR/drawable/msp_logo.png"
echo "✅ MSP Logo replaced successfully."
# Decoding icon Base64
DECODED_ICON="$PROJECT_DIR/drawable/ic_launcher.png"
echo "🔄 Decoding Base64 icon to PNG..."
echo "$ICON_BASE64" | base64 --decode > "$DECODED_ICON"
if [ $? -eq 0 ]; then
echo "✅ Base64 icon decoded successfully to $DECODED_ICON"
else
echo "❌ Error decoding Base64 icon!"
exit 1
fi
# Step 5: Replace and resize the app icon in mipmap folders
resize_and_copy_all_icons() {
input_file=$1
output_folder=$2
size=$3
echo "🗑️ Removing old icons from $output_folder..."
# Delete any existing versions of the icon
rm -f "$output_folder/ic_launcher.png" \
"$output_folder/ic_launcher_foreground.png" \
"$output_folder/ic_launcher_round.png" \
"$output_folder/ic_launcher.webp" \
"$output_folder/ic_launcher_foreground.webp" \
"$output_folder/ic_launcher_round.webp"
# Ensure the directory exists
mkdir -p "$output_folder"
echo "🔄 Resizing and copying icons for $output_folder ..."
# Resize and copy all required icons
convert "$input_file" -resize ${size}x${size} "$output_folder/ic_launcher.png"
convert "$input_file" -resize ${size}x${size} "$output_folder/ic_launcher_foreground.png"
convert "$input_file" -resize ${size}x${size} "$output_folder/ic_launcher_round.png"
echo "✅ All icons resized and placed in $output_folder"
}
for i in "${!MIPMAP_FOLDERS[@]}"; do
MIPMAP_DIR="$PROJECT_DIR/${MIPMAP_FOLDERS[$i]}"
if [ -d "$MIPMAP_DIR" ]; then
echo "Replacing icons in ${MIPMAP_FOLDERS[$i]}..."
resize_and_copy_all_icons "$DECODED_ICON" "$MIPMAP_DIR" ${SIZES[$i]}
else
echo "⚠️ Folder $MIPMAP_DIR does not exist!"
fi
done
# Step 6: Recompile APK
echo "🔧 Recompiling APK..."
$APKTOOL b modified_apk -o $OUTPUT_APK
# Step 7: Sign APK
echo "🔑 Signing APK..."
$BUILD_TOOLS_PATH/apksigner sign --ks $JKS_PATH --ks-pass pass:$JKS_PASSWORD --out $SIGNED_APK $OUTPUT_APK
# Step 8: Verify APK Signature
echo "✅ Verifying APK Signature..."
$BUILD_TOOLS_PATH/apksigner verify $SIGNED_APK
# Step 9: Install APK
PACKAGE_NAME="com.edfapay"
echo "📱 Checking if app is installed..."
$ADB shell pm list packages | grep $PACKAGE_NAME
if [ $? -eq 0 ]; then
echo "🔄 Uninstalling existing app..."
$ADB uninstall $PACKAGE_NAME
fi
echo "📱 Installing new APK..."
$ADB install -r $SIGNED_APK
# Cleanup
rm -f "$PROJECT_DIR/drawable/ic_launcher.png"
echo "🗑️ Cleanup complete."
echo "🎉 Done! Check your installed app."
Make sure to add all the required paths and values i.e:
APK_NAME, JKS_PATH, BUILD_TOOLS_PATH, JKS_PASSWORD.
Also you need to convert your logo and other icons to base64.
If you have more than two icons that needs to be changed during rebranding, simple you can define it as $9,$10… and then repeat the step 4 & step 5, as per your requirements.
You can also change other colors and strings as per step 2 and step 3.
4️⃣ Running the Script
To use this script, provide the required branding values as arguments:
./modify_apk.sh "MyApp" "#FF0000" "#00FF00" "#FFFFFF" "#CCCCCC" "#222222" "base64_logo" "base64_icon"
This will update the app with:
✔️ App name = MyApp
✔️ Primary background color = #FF0000
✔️ Secondary background color = #00FF00
✔️ Primary text color = #FFFFFF
✔️ Logo background color = #CCCCCC
✔️ Side menu header color = #222222
✔️ New logo and icon (decoded from Base64).
5️⃣ Why This is Useful
🔥 Saves time — No manual APK modifications.
🔥 Automates branding — Easily create different branded versions.
🔥 Ensures consistency — Branding elements are updated across the app.
🔥 Works with multiple devices — Installs the APK via ADB.
This approach is perfect for developers working with white-label apps that need frequent branding changes.
Final Thoughts
If you frequently modify and redistribute APKs, automating the process with a script like this eliminates repetitive work and reduces errors.
Want to customize your APKs effortlessly? Give this script a try and make your Android development workflow smarter! 🚀