Androidlanat2 / app.py
Akwbw's picture
Create app.py
068c3e6 verified
from flask import Flask, request, send_file, Response
import os
import zipfile
import subprocess
import shutil
app = Flask(__name__)
# --- HELPER: GENERATE KEY (Same as before) ---
def generate_keystore():
keystore_path = "debug.keystore"
if not os.path.exists(keystore_path):
cmd = [
"keytool", "-genkey", "-v",
"-keystore", keystore_path,
"-storepass", "android",
"-alias", "androiddebugkey",
"-keypass", "android",
"-keyalg", "RSA",
"-keysize", "2048",
"-validity", "10000",
"-dname", "CN=AndroidDebug,O=Android,C=US"
]
subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
return keystore_path
# --- ROUTE: HOME (HTML FORM FOR TESTING) ---
@app.route('/')
def index():
return '''
<!doctype html>
<title>Android Build Server</title>
<h1>Upload Project ZIP</h1>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" required>
<input type="submit" value="Build & Sign APK">
</form>
'''
# --- ROUTE: API ENDPOINT ---
@app.route('/upload', methods=['POST'])
def upload_file():
if 'file' not in request.files:
return "No file part", 400
file = request.files['file']
if file.filename == '':
return "No selected file", 400
if file:
# 1. Cleanup & Save
if os.path.exists("project_extract"):
shutil.rmtree("project_extract")
os.makedirs("project_extract", exist_ok=True)
zip_path = "uploaded_project.zip"
file.save(zip_path)
# 2. Extract
try:
with zipfile.ZipFile(zip_path, "r") as zip_ref:
zip_ref.extractall("project_extract")
except Exception as e:
return f"Error extracting ZIP: {str(e)}", 400
# 3. Find Root
project_root = None
for root, dirs, files in os.walk("project_extract"):
if "gradlew" in files:
project_root = root
break
if not project_root:
return "Error: ZIP file mein 'gradlew' nahi mila.", 400
# 4. Permissions
gradlew_path = os.path.join(project_root, "gradlew")
subprocess.run(["chmod", "+x", gradlew_path])
# 5. Build
# Hum assembleRelease chala rahe hain
build_cmd = ["./gradlew", "assembleRelease", "--no-daemon", "--stacktrace"]
try:
result = subprocess.run(
build_cmd,
cwd=project_root,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
if result.returncode == 0:
# 6. Find Unsigned APK
unsigned_apk = None
for root, dirs, files in os.walk(project_root):
for f in files:
if f.endswith(".apk") and "release" in f:
unsigned_apk = os.path.join(root, f)
break
if unsigned_apk:
# 7. SIGNING
keystore = generate_keystore()
signed_apk_name = "Installable_App.apk"
aligned_apk = "aligned.apk"
# Full path for output
output_apk_path = os.path.abspath(signed_apk_name)
# Step A: ZipAlign
try:
subprocess.run(["zipalign", "-v", "-p", "4", unsigned_apk, aligned_apk],
stdout=subprocess.DEVNULL, check=True)
apk_to_sign = aligned_apk
except:
apk_to_sign = unsigned_apk
# Step B: APKSigner
sign_cmd = [
"apksigner", "sign",
"--ks", keystore,
"--ks-pass", "pass:android",
"--out", output_apk_path,
apk_to_sign
]
sign_result = subprocess.run(sign_cmd, capture_output=True, text=True)
if sign_result.returncode == 0:
# CLEANUP ZIP before sending
if os.path.exists(zip_path):
os.remove(zip_path)
# RETURN THE SIGNED APK
return send_file(
output_apk_path,
as_attachment=True,
download_name=signed_apk_name,
mimetype="application/vnd.android.package-archive"
)
else:
# Signing Failed - Show Logs
logs = sign_result.stderr.splitlines()[:200]
return Response("\n".join(logs), status=500, mimetype="text/plain")
else:
return "Build Success but APK file not found.", 500
else:
# BUILD FAILED - RETURN FIRST 200 LINES OF LOGS
# Combining stdout and stderr to capture full context
full_log = result.stdout + "\n" + result.stderr
logs = full_log.splitlines()[:200]
error_message = "BUILD FAILED. LOGS (First 200 lines):\n\n" + "\n".join(logs)
return Response(error_message, status=500, mimetype="text/plain")
except Exception as e:
return f"System Error: {str(e)}", 500
if __name__ == '__main__':
# Hugging Face Spaces port 7860 use karta hai
app.run(host='0.0.0.0', port=7860)