File size: 9,278 Bytes
1ac6b7e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
df87679
1ac6b7e
 
 
8854bb1
1ac6b7e
df87679
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7f17202
 
 
 
 
 
 
 
 
 
1ac6b7e
7f17202
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1ac6b7e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7f17202
1ac6b7e
 
 
 
 
 
 
 
 
df87679
1ac6b7e
 
 
 
 
 
 
 
 
 
 
 
b2167f3
1ac6b7e
 
 
 
8854bb1
b2167f3
1ac6b7e
b2167f3
1ac6b7e
 
 
 
 
 
 
376857e
b6111ab
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
376857e
 
 
 
 
 
 
1ac6b7e
376857e
1ac6b7e
 
 
 
b6111ab
 
 
 
1ac6b7e
 
 
376857e
b6111ab
1ac6b7e
 
 
 
 
 
 
 
 
 
 
3bb2b11
 
 
 
1ac6b7e
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
#!/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"