#!/system/bin/sh # bc-build — compile Android project from source on-device # Supports: single Java/Kotlin file, Gradle project, or raw aapt2+javac+d8 pipeline # # Usage: # bc-build Compile single Java file to APK # bc-build Compile single Kotlin file to APK # bc-build Run gradle assembleDebug # bc-build --raw Manual aapt2+javac+d8 pipeline CONFIG_DIR="/data/adb/buildchain" MODDIR=$(cat "$CONFIG_DIR/moddir" 2>/dev/null) TOOLS="$MODDIR/tools" AAPT2="$TOOLS/build-tools/aapt2" AIDL="$TOOLS/build-tools/aidl" ZIPALIGN="$TOOLS/build-tools/zipalign" TBIN="/data/data/com.termux/files/usr/bin" ANDROID_JAR="/data/data/com.termux/files/home/android-sdk/platforms/android-35/android.jar" # Fallback android.jar location [ ! -f "$ANDROID_JAR" ] && ANDROID_JAR="/system/framework/framework.jar" die() { echo "ERROR: $1"; exit 1; } build_single_java() { local src="$1" local name=$(basename "$src" .java) local outdir="${2:-./build}" echo "=== Building $name.java ===" mkdir -p "$outdir/classes" "$outdir/dex" "$outdir/apk" echo "[1/5] Compiling Java..." "$TBIN/javac" -source 11 -target 11 -cp "$ANDROID_JAR" -d "$outdir/classes" "$src" || die "javac failed" echo "[2/5] Converting to DEX..." "$TBIN/d8" --min-api 28 --output "$outdir/dex/" "$outdir/classes"/*.class 2>/dev/null \ || "$TBIN/java" -jar "$TBIN/../share/d8/d8.jar" --min-api 28 --output "$outdir/dex/" "$outdir/classes"/*.class \ || die "d8/dex conversion failed" echo "[3/5] Packaging APK..." # Create minimal AndroidManifest.xml cat > "$outdir/AndroidManifest.xml" << MANIFEST MANIFEST "$AAPT2" link -o "$outdir/apk/$name.unsigned.apk" \ --manifest "$outdir/AndroidManifest.xml" \ -I "$ANDROID_JAR" 2>/dev/null || die "aapt2 link failed" # Add DEX to APK cd "$outdir/dex" && zip -u "../apk/$name.unsigned.apk" classes.dex 2>/dev/null && cd - >/dev/null echo "[4/5] Aligning..." "$ZIPALIGN" -f 4 "$outdir/apk/$name.unsigned.apk" "$outdir/apk/$name.aligned.apk" || die "zipalign failed" echo "[5/5] Signing..." bc-sign "$outdir/apk/$name.aligned.apk" "$outdir/$name.apk" echo "" echo "Output: $outdir/$name.apk" ls -la "$outdir/$name.apk" 2>/dev/null } build_single_kotlin() { local src="$1" local name=$(basename "$src" .kt) local outdir="${2:-./build}" echo "=== Building $name.kt ===" mkdir -p "$outdir/classes" "$outdir/dex" "$outdir/apk" echo "[1/5] Compiling Kotlin..." "$TBIN/kotlinc" -cp "$ANDROID_JAR" -d "$outdir/classes" "$src" || die "kotlinc failed" echo "[2/5] Converting to DEX..." find "$outdir/classes" -name "*.class" | xargs "$TBIN/d8" --min-api 28 --output "$outdir/dex/" 2>/dev/null \ || die "d8 failed" echo "[3/5] Packaging..." cat > "$outdir/AndroidManifest.xml" << MANIFEST MANIFEST "$AAPT2" link -o "$outdir/apk/$name.unsigned.apk" \ --manifest "$outdir/AndroidManifest.xml" \ -I "$ANDROID_JAR" 2>/dev/null || die "aapt2 link failed" cd "$outdir/dex" && zip -u "../apk/$name.unsigned.apk" classes.dex 2>/dev/null && cd - >/dev/null echo "[4/5] Aligning..." "$ZIPALIGN" -f 4 "$outdir/apk/$name.unsigned.apk" "$outdir/apk/$name.aligned.apk" echo "[5/5] Signing..." bc-sign "$outdir/apk/$name.aligned.apk" "$outdir/$name.apk" echo "" echo "Output: $outdir/$name.apk" } build_gradle_project() { local projdir="$1" echo "=== Building Gradle project: $projdir ===" if [ ! -f "$projdir/build.gradle" ] && [ ! -f "$projdir/build.gradle.kts" ]; then die "No build.gradle found in $projdir" fi cd "$projdir" # Set ANDROID_HOME for Gradle export ANDROID_HOME="/data/data/com.termux/files/home/android-sdk" export ANDROID_SDK_ROOT="$ANDROID_HOME" if [ -f "./gradlew" ]; then chmod +x ./gradlew ./gradlew assembleDebug || die "Gradle build failed" elif command -v gradle >/dev/null 2>&1; then gradle assembleDebug || die "Gradle build failed" else die "No gradlew and gradle not installed. Run: buildchain setup" fi echo "" echo "Output APKs:" find . -name "*.apk" -path "*/build/outputs/*" 2>/dev/null } # Main case "$1" in --help|-h|"") echo "bc-build — compile Android projects on-device" echo "" echo "Usage:" echo " bc-build MyApp.java Compile Java to APK" echo " bc-build MyApp.kt Compile Kotlin to APK" echo " bc-build ./my-project/ Run Gradle assembleDebug" echo " bc-build MyApp.java ./out/ Specify output directory" ;; *.java) build_single_java "$1" "$2" ;; *.kt) build_single_kotlin "$1" "$2" ;; *) if [ -d "$1" ]; then build_gradle_project "$1" else die "Unknown input: $1 (expected .java, .kt, or directory)" fi ;; esac