Files

320 lines
8.4 KiB
Bash
Raw Permalink Normal View History

#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
# --- Colors ---
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
BOLD='\033[1m'
DIM='\033[2m'
NC='\033[0m'
# --- Config ---
KEYSTORE_DIR="keystore"
KEYSTORE_FILE="$KEYSTORE_DIR/radio247-release.jks"
KEY_ALIAS="radio247"
DIST_DIR="dist"
GRADLE_BUILD_FILE="app/build.gradle.kts"
banner() {
echo ""
echo -e "${CYAN}╔══════════════════════════════════╗${NC}"
echo -e "${CYAN}${BOLD} Radio 247 Build Tool ${NC}${CYAN}${NC}"
echo -e "${CYAN}╚══════════════════════════════════╝${NC}"
echo ""
}
info() { echo -e "${BLUE}${NC} $1"; }
success() { echo -e "${GREEN}${NC} $1"; }
warn() { echo -e "${YELLOW}${NC} $1"; }
error() { echo -e "${RED}${NC} $1"; }
get_version_name() {
if [[ ! -f "$GRADLE_BUILD_FILE" ]]; then
error "Build file not found: $GRADLE_BUILD_FILE"
exit 1
fi
local v
v=$(grep 'versionName' "$GRADLE_BUILD_FILE" | head -1 | sed 's/.*"\([^"]*\)".*/\1/')
if [[ -z "$v" ]]; then
error "Could not extract version from $GRADLE_BUILD_FILE"
exit 1
fi
echo "$v"
}
preflight_check() {
local ok=true
if ! command -v java &>/dev/null && [[ -z "${JAVA_HOME:-}" ]]; then
error "Java not found. Install JDK 17+ or set JAVA_HOME."
ok=false
fi
if ! command -v keytool &>/dev/null; then
error "keytool not found. It ships with the JDK — check your JAVA_HOME/PATH."
ok=false
fi
if [[ ! -x "./gradlew" ]]; then
error "Gradle wrapper not found or not executable."
ok=false
fi
if [[ "$ok" != true ]]; then
exit 1
fi
}
ensure_dist_dir() {
mkdir -p "$DIST_DIR"
}
main_menu() {
echo -e "${BOLD}What would you like to do?${NC}"
echo ""
echo -e " ${BOLD}1)${NC} Build Release APK ${DIM}(signed, shareable)${NC}"
echo -e " ${BOLD}2)${NC} Build Debug APK ${DIM}(quick, for testing)${NC}"
echo -e " ${BOLD}3)${NC} Manage Keystore ${DIM}(create or check signing key)${NC}"
echo -e " ${BOLD}4)${NC} Clean ${DIM}(remove build artifacts)${NC}"
echo -e " ${BOLD}5)${NC} Exit"
echo ""
local choice
read -rp "> " choice
case $choice in
1) build_release ;;
2) build_debug ;;
3) manage_keystore ;;
4) clean_build ;;
5) echo ""; exit 0 ;;
*) warn "Invalid choice. Pick 1-5." ;;
esac
}
read_keystore_password() {
local password
read -rsp "Keystore password: " password
echo >&2
echo "$password"
}
create_keystore() {
echo -e "${BOLD}No keystore found. Let's create one.${NC}"
echo ""
local cn org password password_confirm
read -rp "Your name (for the certificate): " cn
[[ -z "$cn" ]] && { error "Name is required."; return 1; }
read -rp "Organization (optional, Enter to skip): " org
while true; do
read -rsp "Password (min 6 chars): " password
echo
if [[ ${#password} -lt 6 ]]; then
warn "Password must be at least 6 characters."
continue
fi
read -rsp "Confirm password: " password_confirm
echo
if [[ "$password" != "$password_confirm" ]]; then
warn "Passwords don't match. Try again."
continue
fi
break
done
mkdir -p "$KEYSTORE_DIR"
local dname="CN=$cn"
[[ -n "$org" ]] && dname="$dname, O=$org"
info "Creating keystore..."
local keytool_err
keytool_err=$(mktemp)
keytool -genkeypair \
-alias "$KEY_ALIAS" \
-keyalg RSA \
-keysize 2048 \
-validity 10000 \
-keystore "$KEYSTORE_FILE" \
-storepass "$password" \
-keypass "$password" \
-dname "$dname" \
2>"$keytool_err" || true
if [[ -f "$KEYSTORE_FILE" ]]; then
rm -f "$keytool_err"
echo ""
success "Keystore created at ${BOLD}$KEYSTORE_FILE${NC}"
echo ""
warn "IMPORTANT: Back up this file and remember your password."
warn "If you lose either, you cannot update the app on devices"
warn "that already have this version installed."
else
error "Keystore creation failed."
if [[ -s "$keytool_err" ]]; then
echo -e "${DIM}$(cat "$keytool_err")${NC}" >&2
fi
rm -f "$keytool_err"
return 1
fi
}
manage_keystore() {
if [[ -f "$KEYSTORE_FILE" ]]; then
success "Keystore exists at ${BOLD}$KEYSTORE_FILE${NC}"
echo ""
info "Keystore details:"
keytool -list -keystore "$KEYSTORE_FILE" -alias "$KEY_ALIAS" \
-storepass "$(read_keystore_password)" 2>/dev/null \
|| warn "Could not read keystore (wrong password?)"
return
fi
create_keystore
}
copy_apk() {
local build_type="$1"
local version
version="$(get_version_name)"
local source_apk="app/build/outputs/apk/$build_type/app-$build_type.apk"
if [[ ! -f "$source_apk" ]]; then
error "APK not found at $source_apk"
return 1
fi
ensure_dist_dir
local dest_name="radio247-v${version}-${build_type}.apk"
local dest_path="$DIST_DIR/$dest_name"
cp "$source_apk" "$dest_path"
local size
size="$(du -h "$dest_path" | cut -f1 | xargs)"
echo ""
success "Build complete!"
echo ""
echo -e " ${BOLD}APK:${NC} $dest_path"
echo -e " ${BOLD}Size:${NC} $size"
echo ""
echo -e " ${DIM}Share this file with anyone — they can install it${NC}"
echo -e " ${DIM}on Android 9+ by opening the APK on their device.${NC}"
}
build_release() {
info "Preparing release build..."
echo ""
if [[ ! -f "$KEYSTORE_FILE" ]]; then
warn "No keystore found. You need one to sign a release APK."
echo ""
local yn
read -rp "Create one now? (y/n) " yn
case $yn in
[Yy]*) create_keystore || return 1 ;;
*) return 0 ;;
esac
echo ""
fi
local password
read -rsp "Keystore password: " password
echo ""
echo ""
info "Building release APK... (this may take a minute)"
echo ""
local store_file build_log exit_code
store_file="$(cd "$(dirname "$KEYSTORE_FILE")" && pwd)/$(basename "$KEYSTORE_FILE")"
build_log=$(mktemp)
set +e
./gradlew assembleRelease \
-Pandroid.injected.signing.store.file="$store_file" \
-Pandroid.injected.signing.store.password="$password" \
-Pandroid.injected.signing.key.alias="$KEY_ALIAS" \
-Pandroid.injected.signing.key.password="$password" 2>&1 | tee "$build_log"
exit_code=${PIPESTATUS[0]}
set -e
if [[ $exit_code -eq 0 ]]; then
rm -f "$build_log"
copy_apk "release"
else
echo ""
echo -e "${RED}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
error "BUILD FAILED"
echo -e "${RED}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo ""
echo -e "${DIM}Last 20 lines of build output:${NC}"
tail -20 "$build_log"
rm -f "$build_log"
return 1
fi
}
build_debug() {
info "Building debug APK..."
echo ""
local build_log exit_code
build_log=$(mktemp)
set +e
./gradlew assembleDebug 2>&1 | tee "$build_log"
exit_code=${PIPESTATUS[0]}
set -e
if [[ $exit_code -eq 0 ]]; then
rm -f "$build_log"
copy_apk "debug"
else
echo ""
echo -e "${RED}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
error "BUILD FAILED"
echo -e "${RED}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo ""
echo -e "${DIM}Last 20 lines of build output:${NC}"
tail -20 "$build_log"
rm -f "$build_log"
return 1
fi
}
clean_build() {
info "Cleaning build artifacts..."
./gradlew clean
if [[ -d "$DIST_DIR" ]]; then
rm -rf "$DIST_DIR"
success "Removed $DIST_DIR/"
fi
success "Clean complete."
}
# --- Main ---
preflight_check
banner
while true; do
main_menu
echo ""
done