from flask import Flask, request, jsonify, send_file from flask_cors import CORS import os, zipfile, subprocess, shutil, uuid, requests app = Flask(__name__) # Enable CORS for external HTML Requests calling this build system ! CORS(app) # NOTE: Get this Free from appetize.io/docs APPETIZE_API_KEY = "tok_hu46b6i3qxcxijamjmczaqdbv4" def generate_keystore(work_dir): keystore_path = os.path.join(work_dir, "debug.keystore") 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 def push_to_appetize(apk_path): """ Upload to appetize platform to stream App inside the web lightweight layer """ url = "https://api.appetize.io/v1/apps" with open(apk_path, "rb") as app_file: files = {"file": app_file} headers = {"Authorization": f"Bearer {APPETIZE_API_KEY}"} # Data stream params config data = { "platform": "android" } resp = requests.post(url, headers=headers, files=files, data=data) if resp.status_code == 200: json_data = resp.json() public_key = json_data.get("publicKey", "") # Returns Web UI Iframe Player configured natively (Bijli ki trha speed aur Exact App replica) stream_link = f"https://appetize.io/embed/{public_key}?device=pixel7&scale=80&autoplay=true&language=en" return stream_link else: return None @app.route('/', methods=['GET']) def index(): # Calling Custom HTML Design return send_file('index.html') @app.route('/upload_project', methods=['POST']) def build_and_preview_app(): if 'file' not in request.files: return jsonify({'success': False, 'message': 'Project Zip Error!'}), 400 file = request.files['file'] run_id = str(uuid.uuid4())[:8] work_dir = f"/app/build_{run_id}" os.makedirs(work_dir, exist_ok=True) zip_location = os.path.join(work_dir, "android_code.zip") extract_path = os.path.join(work_dir, "src") file.save(zip_location) try: with zipfile.ZipFile(zip_location, "r") as zip_ref: zip_ref.extractall(extract_path) project_folder = next((r for r, _, f in os.walk(extract_path) if "gradlew" in f), None) if not project_folder: return jsonify({'success': False, 'message': 'Invalid Android source, missing gradlew'}), 400 # Execute build permission sets and Start Lightning Compile Build subprocess.run(["chmod", "+x", "gradlew"], cwd=project_folder) result = subprocess.run(["./gradlew", "assembleRelease", "--no-daemon", "--stacktrace"], cwd=project_folder, capture_output=True, text=True) if result.returncode == 0: final_unsigned_apk = next((os.path.join(path, fi) for path, _, fsi in os.walk(project_folder) for fi in fsi if fi.endswith(".apk") and "release" in fi), None) if final_unsigned_apk: ks = generate_keystore(work_dir) apk_done = os.path.abspath(os.path.join(work_dir, f"Final_App_{run_id}.apk")) # Signing to enable live android deploy logic! subprocess.run(["apksigner", "sign", "--ks", ks, "--ks-pass", "pass:android", "--out", apk_done, final_unsigned_apk]) # Cloud Live Stream Step iframe_url = push_to_appetize(apk_done) if iframe_url: return jsonify({'success': True, 'preview_url': iframe_url}) else: return jsonify({'success': False, 'message': 'Compilation worked but Emulator Connection Failed. (Check APPETIZE Token)'}) else: return jsonify({'success': False, 'message': 'Gradle process built 0 Apps inside folders!'}) return jsonify({'success': False, 'message': f"Compile failure on server! Msg:\n{result.stderr[-400:]}"}) except Exception as e: return jsonify({'success': False, 'message': f"An issue raised handling system code. {str(e)}"}) finally: # Save container limits from exceeding memory & size caps free hugs limit! try: shutil.rmtree(work_dir) except: pass if __name__ == '__main__': # Listen actively within docker Hugging limits Space 7860 mapping setup limits ! app.run(host='0.0.0.0', port=7860)