import streamlit as st import os, zipfile, subprocess, shutil st.set_page_config(page_title="Android Build Server", layout="centered") st.title("📱 Android APK Generator") st.markdown("Flutter ya Native Android — dono projects ka APK banayega aur **Auto-Sign** karega.") def setup_java_env(): # Automatically detect valid JAVA_HOME path from system java binary current_jh = os.environ.get("JAVA_HOME", "") if not current_jh or not os.path.exists(os.path.join(current_jh, "bin", "java")): java_bin = shutil.which("java") if java_bin: real_path = os.path.realpath(java_bin) detected_jh = os.path.dirname(os.path.dirname(real_path)) os.environ["JAVA_HOME"] = detected_jh def generate_keystore(): kp = "debug.keystore" if not os.path.exists(kp): subprocess.run([ "keytool","-genkey","-v","-keystore",kp,"-storepass","android", "-alias","androiddebugkey","-keypass","android","-keyalg","RSA", "-keysize","2048","-validity","10000", "-dname","CN=AndroidDebug,O=Android,C=US" ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) return kp def find_apk(d): for r,_,fs in os.walk(d): for f in fs: if f.endswith(".apk") and "release" in f.lower(): return os.path.join(r,f) return None def sign_apk(unsigned): al = "aligned.apk"; sg = "Installable_App.apk" try: subprocess.run(["zipalign","-v","-p","4",unsigned,al], stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL,check=True) target = al except: target = unsigned generate_keystore() r = subprocess.run([ "apksigner","sign","--ks","debug.keystore","--ks-pass","pass:android", "--out",sg,target ], capture_output=True, text=True) return sg if r.returncode == 0 else None f = st.file_uploader("Project ZIP Upload Karein", type=["zip"]) if f is not None: if st.button("🔨 Create & Sign APK"): setup_java_env() # Auto detect and set JAVA_HOME sts = st.empty(); bar = st.progress(0) if os.path.exists("project_extract"): shutil.rmtree("project_extract") os.makedirs("project_extract") sts.info("📦 ZIP extract ho raha hai...") with open("uploaded_project.zip","wb") as w: w.write(f.getbuffer()) with zipfile.ZipFile("uploaded_project.zip","r") as z: z.extractall("project_extract") bar.progress(15) flutter_root = None; native_root = None for r,_,fs in os.walk("project_extract"): if "pubspec.yaml" in fs and not flutter_root: flutter_root = r if "gradlew" in fs and not native_root: native_root = r unsigned = None if flutter_root: sts.info("🟦 Flutter project — flutter build apk chal raha hai...") bar.progress(20) android_dir = os.path.join(flutter_root, "android") if not os.path.exists(android_dir): os.makedirs(android_dir) sdk_dir = os.environ.get('ANDROID_HOME', os.environ.get('ANDROID_SDK_ROOT', '/sdk')) flutter_dir = os.environ.get('FLUTTER_HOME', '/opt/flutter') with open(os.path.join(android_dir, "local.properties"), "w") as lf: lf.write(f"sdk.dir={sdk_dir}\n") lf.write(f"flutter.sdk={flutter_dir}\n") lf.write("flutter.buildMode=release\n") r1 = subprocess.run(["flutter","pub","get"], cwd=flutter_root, capture_output=True, text=True) if r1.returncode != 0: st.error("❌ flutter pub get fail!"); st.text(r1.stderr[-2000:]) else: bar.progress(35) r2 = subprocess.run(["flutter","build","apk","--release"], cwd=flutter_root, capture_output=True, text=True) bar.progress(85) if r2.returncode == 0: apk_dir = os.path.join(flutter_root,"build","app","outputs","flutter-apk") unsigned = find_apk(apk_dir) else: st.error("❌ Flutter Build Failed!") st.text_area("Error Log", r2.stderr[-3000:], height=250) elif native_root: sts.info("🟩 Native Android project — gradlew assembleRelease chal raha hai...") bar.progress(20) sdk_dir = os.environ.get('ANDROID_HOME', os.environ.get('ANDROID_SDK_ROOT', '/sdk')) with open(os.path.join(native_root, "local.properties"), "w") as lf: lf.write(f"sdk.dir={sdk_dir}\n") subprocess.run(["chmod","+x",os.path.join(native_root,"gradlew")]) bar.progress(25) r = subprocess.run(["./gradlew","assembleRelease","--no-daemon","--stacktrace"], cwd=native_root, capture_output=True, text=True) bar.progress(85) if r.returncode == 0: unsigned = find_apk(native_root) else: st.error("❌ Gradle Build Failed!") st.text_area("Error Log", r.stderr[-3000:], height=250) else: st.error("❌ ZIP mein na pubspec.yaml mila, na gradlew.") if unsigned and os.path.exists(unsigned): sts.info("🔐 APK sign ho raha hai...") sg = sign_apk(unsigned) if sg: bar.progress(100); sts.success("🎉 APK Ready!") with open(sg,"rb") as dl: st.download_button("⬇️ Download APK", data=dl, file_name=sg, mime="application/vnd.android.package-archive") else: st.error("Signing fail ho gayi.") if os.path.exists("uploaded_project.zip"): os.remove("uploaded_project.zip")