htstudio-builder-apk / build_java_apk.sh
CrimsonSorcerer's picture
Update build_java_apk.sh
b6111ab verified
Raw
History Blame Contribute Delete
9.28 kB
#!/bin/bash
# build_java_apk.sh <work_dir> <app_name> <pkg_name> <keystore>
# Java kodunu Android APK'ya derler
set -e
WORK_DIR="$1"
APP_NAME="$2"
PKG_NAME="$3"
KEYSTORE="$4"
ANDROID_SDK=/opt/android-sdk
BUILD_TOOLS=$ANDROID_SDK/build-tools/33.0.0
PLATFORM=$ANDROID_SDK/platforms/android-33
echo "[HtStudio Java APK] Başlıyor: $APP_NAME ($PKG_NAME)"
# Klasör yapısı
mkdir -p "$WORK_DIR/src/$( echo $PKG_NAME | tr '.' '/' )"
mkdir -p "$WORK_DIR/res/layout"
mkdir -p "$WORK_DIR/res/values"
mkdir -p "$WORK_DIR/res/mipmap-mdpi" "$WORK_DIR/res/mipmap-hdpi" "$WORK_DIR/res/mipmap-xhdpi" "$WORK_DIR/res/mipmap-xxhdpi" "$WORK_DIR/res/mipmap-xxxhdpi"
mkdir -p "$WORK_DIR/bin"
mkdir -p "$WORK_DIR/obj"
mkdir -p "$WORK_DIR/gen"
mkdir -p "$WORK_DIR/assets"
# İkon: kullanıcının logosu varsa onu kullan (process_logo tarafından
# $WORK_DIR/icons/mipmap-*/ic_launcher.png içine kaydedilmiş olur), yoksa
# varsayılan ikonu kullan. Bu adım eskiden hiç yapılmıyordu, o yüzden Java
# APK'lar her zaman sistem varsayılan (Android robotu) ikonuyla çıkıyordu.
if [ -f "$WORK_DIR/has_logo" ]; then
echo "[HtStudio Java APK] Kullanıcı logosu kullanılıyor"
cp "$WORK_DIR/icons/mipmap-mdpi/ic_launcher.png" "$WORK_DIR/res/mipmap-mdpi/ic_launcher.png"
cp "$WORK_DIR/icons/mipmap-hdpi/ic_launcher.png" "$WORK_DIR/res/mipmap-hdpi/ic_launcher.png"
cp "$WORK_DIR/icons/mipmap-xhdpi/ic_launcher.png" "$WORK_DIR/res/mipmap-xhdpi/ic_launcher.png"
cp "$WORK_DIR/icons/mipmap-xxhdpi/ic_launcher.png" "$WORK_DIR/res/mipmap-xxhdpi/ic_launcher.png"
cp "$WORK_DIR/icons/mipmap-xxxhdpi/ic_launcher.png" "$WORK_DIR/res/mipmap-xxxhdpi/ic_launcher.png"
else
echo "[HtStudio Java APK] Varsayılan ikon kullanılıyor"
cp /opt/default_icons/mdpi/ic_launcher.png "$WORK_DIR/res/mipmap-mdpi/ic_launcher.png"
cp /opt/default_icons/hdpi/ic_launcher.png "$WORK_DIR/res/mipmap-hdpi/ic_launcher.png"
cp /opt/default_icons/xhdpi/ic_launcher.png "$WORK_DIR/res/mipmap-xhdpi/ic_launcher.png"
cp /opt/default_icons/xxhdpi/ic_launcher.png "$WORK_DIR/res/mipmap-xxhdpi/ic_launcher.png"
cp /opt/default_icons/xxxhdpi/ic_launcher.png "$WORK_DIR/res/mipmap-xxxhdpi/ic_launcher.png"
fi
# Kullanıcının Java kodunu yerleştir.
# İki mod var:
# 1) "Tam Activity modu" - kullanıcı kendi MainActivity/View/onDraw vs. kodunu
# yazmışsa (gerçek Android UI), kodunu direkt MainActivity.java olarak
# kullanıyoruz, hiçbir wrapper üretmiyoruz (aksi halde "duplicate class"
# hatası alınır çünkü iki MainActivity çakışır).
# 2) "Konsol modu" - kullanıcı basit `class Main { main(...) }` yazmışsa,
# eskisi gibi çıktısını TextView'da gösteren bir wrapper MainActivity
# otomatik üretilir.
SRC_DIR="$WORK_DIR/src/$( echo $PKG_NAME | tr '.' '/' )"
# Kullanıcının kodundaki `package ...;` satırı proje ayarındaki gerçek paket
# adından farklıysa derleme patlar (paket/klasör uyuşmazlığı). Otomatik
# eşitliyoruz ki kullanıcı hangi paket adını yazdıysa yazsın çalışsın.
if grep -q "^package " "$WORK_DIR/Main.java"; then
sed -i "s/^package .*/package ${PKG_NAME};/" "$WORK_DIR/Main.java"
else
sed -i "1i package ${PKG_NAME};" "$WORK_DIR/Main.java"
fi
if grep -qE "class[[:space:]]+MainActivity\b" "$WORK_DIR/Main.java"; then
echo "[HtStudio Java APK] Tam Activity modu (kullanıcı kendi MainActivity'sini yazmış)"
cp "$WORK_DIR/Main.java" "$SRC_DIR/MainActivity.java"
else
echo "[HtStudio Java APK] Konsol modu (Main.main() çıktısı sarmalanıyor)"
cp "$WORK_DIR/Main.java" "$SRC_DIR/Main.java"
cat > "$SRC_DIR/MainActivity.java" << JAVA
package $PKG_NAME;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ScrollView;
import android.widget.TextView;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ScrollView sv = new ScrollView(this);
TextView tv = new TextView(this);
tv.setPadding(32, 32, 32, 32);
tv.setTextSize(14f);
tv.setTextColor(0xFFCDD6F4);
tv.setBackgroundColor(0xFF1E1E2E);
tv.setTypeface(android.graphics.Typeface.MONOSPACE);
sv.addView(tv);
setContentView(sv);
sv.setBackgroundColor(0xFF1E1E2E);
// Kullanıcının main metodunu çalıştır, stdout'u yakala
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos);
PrintStream old = System.out;
System.setOut(ps);
try {
Main.main(new String[]{});
} catch (Exception e) {
System.out.println("Hata: " + e.getMessage());
} finally {
System.out.flush();
System.setOut(old);
}
tv.setText(baos.toString());
}
}
JAVA
fi
# AndroidManifest.xml
cat > "$WORK_DIR/AndroidManifest.xml" << XML
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="$PKG_NAME"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="33"/>
<application android:label="$APP_NAME" android:icon="@mipmap/ic_launcher" android:allowBackup="true">
<activity android:name=".MainActivity" android:exported="true"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
XML
# R.java oluştur (aapt2)
$BUILD_TOOLS/aapt2 compile --dir "$WORK_DIR/res" -o "$WORK_DIR/res_compiled.zip" 2>&1
$BUILD_TOOLS/aapt2 link \
--manifest "$WORK_DIR/AndroidManifest.xml" \
-I "$PLATFORM/android.jar" \
--java "$WORK_DIR/gen" \
-A "$WORK_DIR/assets" \
-o "$WORK_DIR/resources.apk" \
"$WORK_DIR/res_compiled.zip" \
--auto-add-overlay 2>&1
echo "[HtStudio Java APK] javac ile derleniyor..."
# Java kaynaklarını derle
find "$WORK_DIR/src" -name "*.java" > "$WORK_DIR/sources.txt"
find "$WORK_DIR/gen" -name "*.java" >> "$WORK_DIR/sources.txt" 2>/dev/null || true
# Projeye eklenen kütüphaneler (process_libraries() tarafından $WORK_DIR/libs/
# altına konuluyor). İki formatta gelebilir:
# - .jar -> direkt kullanılır
# - .aar -> Android Archive, içinde classes.jar + kaynaklar var. Burada
# sadece classes.jar'ı çıkarıp kullanıyoruz (kaynak/manifest
# birleştirme yapmıyoruz - çoğu kod kütüphanesi için yeterli,
# ama kütüphane kendi layout/drawable gibi Android
# kaynaklarına ihtiyaç duyuyorsa bu basit çıkarma yetmez).
mkdir -p "$WORK_DIR/libs_extracted"
for AAR in "$WORK_DIR"/libs/*.aar; do
[ -e "$AAR" ] || continue
AAR_NAME=$(basename "$AAR" .aar)
echo "[HtStudio Java APK] AAR açılıyor: $AAR_NAME"
TMP_EXTRACT="$WORK_DIR/libs_extracted/${AAR_NAME}_tmp"
mkdir -p "$TMP_EXTRACT"
unzip -o -q "$AAR" classes.jar -d "$TMP_EXTRACT" 2>&1 || true
if [ -f "$TMP_EXTRACT/classes.jar" ]; then
mv "$TMP_EXTRACT/classes.jar" "$WORK_DIR/libs_extracted/${AAR_NAME}.jar"
else
echo "[UYARI] $AAR_NAME.aar içinde classes.jar bulunamadı, atlanıyor"
fi
rm -rf "$TMP_EXTRACT"
done
LIB_JARS=$(find "$WORK_DIR/libs" "$WORK_DIR/libs_extracted" -name "*.jar" 2>/dev/null | tr '\n' ':')
if [ -n "$LIB_JARS" ]; then
echo "[HtStudio Java APK] Kütüphaneler classpath'e ekleniyor: $LIB_JARS"
CLASSPATH="$PLATFORM/android.jar:${LIB_JARS}"
else
CLASSPATH="$PLATFORM/android.jar"
fi
javac -source 8 -target 8 \
-cp "$CLASSPATH" \
-d "$WORK_DIR/obj" \
@"$WORK_DIR/sources.txt" 2>&1
echo "[HtStudio Java APK] d8 ile dex oluşturuluyor..."
# NOT: Kütüphane jar'ları (aar'dan çıkarılanlar dahil) burada da d8'e
# veriliyor - sadece derleme classpath'inde olmaları yeterli değil,
# kütüphanenin kendi bytecode'unun da dex'lenip APK'ya gömülmesi lazım,
# yoksa runtime'da ClassNotFoundException alınır.
$BUILD_TOOLS/d8 \
--lib "$PLATFORM/android.jar" \
--output "$WORK_DIR/bin" \
$(find "$WORK_DIR/obj" -name "*.class") \
$(find "$WORK_DIR/libs" "$WORK_DIR/libs_extracted" -name "*.jar" 2>/dev/null) 2>&1
echo "[HtStudio Java APK] APK paketleniyor..."
cd "$WORK_DIR"
cp resources.apk unsigned.apk 2>/dev/null || $BUILD_TOOLS/aapt package -f \
-M AndroidManifest.xml \
-I "$PLATFORM/android.jar" \
-F unsigned.apk 2>&1
# classes.dex ekle
zip -j unsigned.apk bin/classes.dex 2>&1
echo "[HtStudio Java APK] Hizalanıyor (zipalign)..."
$BUILD_TOOLS/zipalign -f -p 4 unsigned.apk aligned.apk 2>&1
mv aligned.apk unsigned.apk
echo "[HtStudio Java APK] İmzalanıyor..."
$BUILD_TOOLS/apksigner sign \
--ks "$KEYSTORE" \
--ks-pass pass:android \
--key-pass pass:android \
--ks-key-alias androiddebugkey \
--out output.apk \
unsigned.apk 2>&1
echo "[HtStudio Java APK] Başarılı: $WORK_DIR/output.apk"