# To AI Agent: Implement Server-Hosted Android APK Download Button and Automated Build Deployment Pipeline ## 1. Context & Feature Objective We are adding a native Android app distribution workflow directly from our self-hosted server backend. Instead of relying purely on app stores, users visiting the web version from an Android device must be able to download the official compiled `.apk` file directly. **Objective:** 1. **Backend Asset Exposure:** Configure a secure, static file directory on the Node.js/Express server to host the production `.apk` binary. 2. **Build Pipeline Link Automation:** Create a post-build deployment shell script. Every time a new production Android APK is generated (`release`), the script must automatically rename and copy it to the backend's public distribution folder under a persistent file pointer name (`yotrip-latest.apk`). 3. **Frontend Action Button:** Add an interactive "Tải ứng dụng Android" action row with a download icon inside both the Member and Guest profile menu sheets. --- ## 2. Technical Architecture & Implementation Steps [Android Build Output] ➔ [deploy-apk.sh Script] ➔ [Backend public/downloads/yotrip-latest.apk] ▲ [Frontend UI Button] ➔ ➔ ➔ [Triggers HTTP GET Request] ➔ ➔ ➔ ➔ ➔ ┛ ### Step 1: Configure Backend Static Asset Folder Locate the core server setup file (e.g., `server.ts`, `app.ts`, or `index.js`). Ensure a dedicated folder path named `public/downloads` is created and mapped to express static file serving handlers: ```typescript import express from 'express'; import path from 'path'; const app = express(); // Ensure the directory exists: public/downloads/ const downloadsDir = path.join(__dirname, '../public/downloads'); /* ✅ BACKEND STATIC MIDDLEWARE REGISTRATION This exposes the file at: [https://yourdomain.com/downloads/yotrip-latest.apk](https://yourdomain.com/downloads/yotrip-latest.apk) */ app.use('/downloads', express.static(downloadsDir, { setHeaders: (res) => { // Force browser engines to download the file directly instead of trying to parse it res.set('Content-Type', 'application/vnd.android.package-archive'); res.set('Content-Disposition', 'attachment; filename="yotrip-latest.apk"'); } })); ### Step 2: Automate APK Release Mapping Link (Post-Build Script) Create an automation script file named scripts/deploy-apk.sh in the root environment. This script runs instantly after your Android compiler output is generated (e.g., via Gradle ./gradlew assembleRelease or Capacitor/Cordova build actions): #!/bin/bash # Define relative path coordinates ANDROID_OUTPUT_PATH="./android/app/build/outputs/apk/release/app-release.apk" BACKEND_TARGET_DIR="./backend/public/downloads" TARGET_FILE_NAME="yotrip-latest.apk" echo "🚀 Starting automated post-build Android deployment pipeline..." # 1. Verify compiler target exists if [ -f "$ANDROID_OUTPUT_PATH" ]; then # 2. Ensure target storage folder structure is active mkdir -p "$BACKEND_TARGET_DIR" # 3. Copy and force overwrite the old production bundle with the updated version cp -f "$ANDROID_OUTPUT_PATH" "$BACKEND_TARGET_DIR/$TARGET_FILE_NAME" echo "✅ Success! New build copied safely to $BACKEND_TARGET_DIR/$TARGET_FILE_NAME" echo "🔗 Direct Download Link Active: /downloads/$TARGET_FILE_NAME" else echo "❌ Critical Error: Android build output artifact not found at $ANDROID_OUTPUT_PATH" exit 1 fi Add "build:android": "cd android && ./gradlew assembleRelease && cd .. && sh scripts/deploy-apk.sh" inside package.json scripts matrix for unified execution hooks. ### Step 3: Add Download Trigger into Frontend UI (MapProfileDropdown.tsx) Locate the unified dropdown menu component created in the previous layout consolidation phase. Inject the direct-download operational action rows: // Define the static destination asset link helper const APK_DOWNLOAD_URL = `${process.env.REACT_APP_API_BASE_URL || ''}/downloads/yotrip-latest.apk`; /* --- INSIDE AUTHENTICATED MEMBER STACK SECTION --- */