diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..7122beb --- /dev/null +++ b/.env.example @@ -0,0 +1,8 @@ +ANDROID_VERSION=30 +GAPPS_VERSION=11 +DNS=one.one.one.one +RAM_SIZE=4096 +SCREEN_RESOLUTION=1080x1920 +SCREEN_DENSITY=320 +ROOT_SETUP=0 +GAPPS_SETUP=0 diff --git a/Dockerfile b/Dockerfile index 07a615a..263b62f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,7 @@ FROM ubuntu:20.04 +ARG ANDROID_VERSION=30 +ENV ANDROID_VERSION=${ANDROID_VERSION} -# Install necessary packages RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ libegl1 \ @@ -8,17 +9,26 @@ RUN apt-get update && \ wget \ curl \ git \ - lzip \ + xz-utils \ unzip \ supervisor \ qemu-kvm \ iproute2 \ socat \ - tzdata && \ + tzdata \ + squashfs-tools \ + procps && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* -# Set up Android SDK +RUN curl -s "https://dl.google.com/android/repository/repository2-1.xml" | \ + grep -oP 'emulator-linux_x64-\d+\.zip' | head -1 | \ + awk '{print "https://dl.google.com/android/repository/" $0}' | \ + wget -q -O /tmp/emulator.zip - || true && \ + if [ -s /tmp/emulator.zip ] && [ -f /tmp/emulator.zip ]; then \ + unzip -q /tmp/emulator.zip -d /opt/android-sdk && rm /tmp/emulator.zip; \ + fi + RUN mkdir -p /opt/android-sdk/cmdline-tools && \ cd /opt/android-sdk/cmdline-tools && \ wget https://dl.google.com/android/repository/commandlinetools-linux-13114758_latest.zip -O cmdline-tools.zip && \ @@ -29,61 +39,41 @@ RUN mkdir -p /opt/android-sdk/cmdline-tools && \ ENV ANDROID_HOME=/opt/android-sdk ENV ANDROID_AVD_HOME=/data -ENV ADB_DIR="$ANDROID_HOME/platform-tools" -ENV PATH="$ANDROID_HOME/cmdline-tools/latest/bin:$ADB_DIR:$PATH" +ENV PATH="$ANDROID_HOME/cmdline-tools/latest/bin:$PATH:$ANDROID_HOME/platform-tools" -# Initializing the required directories. RUN mkdir /root/.android/ && \ - touch /root/.android/repositories.cfg && \ - mkdir /data && \ + touch /root/.android/repositories.cfg && \ + mkdir /data && \ mkdir /extras -# Copy emulator.zip -#COPY emulator.zip /root/emulator.zip -#COPY emulator/package.xml /root/package.xml +RUN export ANDROID_VERSION=$ANDROID_VERSION && \ + yes | sdkmanager --sdk_root=$ANDROID_HOME "platform-tools" && \ + if [ "$ANDROID_VERSION" -ge 35 ]; then \ + yes | sdkmanager --sdk_root=$ANDROID_HOME "platforms;android-${ANDROID_VERSION}" "system-images;android-${ANDROID_VERSION};google_apis;x86_64" || true; \ + else \ + yes | sdkmanager --sdk_root=$ANDROID_HOME "emulator" "platforms;android-${ANDROID_VERSION}" "system-images;android-${ANDROID_VERSION};default;x86_64"; \ + fi && \ + yes | sdkmanager --sdk_root=$ANDROID_HOME "emulator" || true +RUN if [ ! -f "$ANDROID_HOME/platform-tools/adb" ]; then \ + echo "ERROR: adb not found at $ANDROID_HOME/platform-tools/adb"; \ + ls -la $ANDROID_HOME/; \ + exit 1; \ + fi -# Detect architecture and set environment variable -RUN yes | sdkmanager --sdk_root=$ANDROID_HOME "emulator" "platform-tools" "platforms;android-30" "system-images;android-30;default;x86_64" -# remove /opt/android-sdk/emulator/crashpad_handler RUN rm -f /opt/android-sdk/emulator/crashpad_handler -# RUN if [ "$(uname -m)" = "aarch64" ]; then \ -# unzip /root/emulator.zip -d $ANDROID_HOME && \ -# mv /root/package.xml $ANDROID_HOME/emulator/package.xml && \ -# rm /root/emulator.zip && \ -# yes | sdkmanager --sdk_root=$ANDROID_HOME "platform-tools" "platforms;android-29" "system-images;android-29;default;arm64-v8a" && \ -# echo "no" | avdmanager create avd -n test -k "system-images;android-29;default;arm64-v8a"; \ -# else \ -# yes | sdkmanager --sdk_root=$ANDROID_HOME "emulator" "platform-tools" "platforms;android-29" "system-images;android-29;default;x86_64" && \ -# echo "no" | avdmanager create avd -n test -k "system-images;android-29;default;x86_64"; \ -# fi -# Copy supervisor config COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf -# Copy the rootAVD repository -#COPY rootAVD /root/rootAVD - -# Copy the first-boot script COPY first-boot.sh /root/first-boot.sh RUN chmod +x /root/first-boot.sh -# Copy the start-emulator script COPY start-emulator.sh /root/start-emulator.sh RUN chmod +x /root/start-emulator.sh -# Expose necessary ports EXPOSE 5554 5555 -# Healthcheck to ensure the emulator is running -HEALTHCHECK --interval=10s --timeout=10s --retries=600 \ - CMD adb devices | grep emulator-5554 && test -f /data/.first-boot-done || exit 1 +HEALTHCHECK --interval=30s --timeout=10s --retries=60 \ + CMD ps aux | grep -v grep | grep -q emulator || test -f /data/.first-boot-done -# Start Supervisor to manage the emulator CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"] - -# docker build -t dockerify-android . -# docker run -d --name dockerify-android --device /dev/kvm --privileged -p 5555:5555 dockerify-android -# docker run -d --name dockerify-android --device /dev/kvm --privileged -p 5555:5555 shmayro/dockerify-android -# docker exec -it dockerify-android tail -f /var/log/supervisor/emulator.out -# docker exec -it dockerify-android tail -f /var/log/supervisor/first-boot.out.log diff --git a/README.md b/README.md index f0fce8e..7648a86 100644 --- a/README.md +++ b/README.md @@ -145,13 +145,15 @@ scrcpy -s localhost:5555 | `SCREEN_DENSITY` | Screen pixel density in DPI | device default | | `ROOT_SETUP` | Set to `1` to enable rooting and Magisk. Can be turned on after the first start but cannot be undone without recreating the data volume. | `0` | | `GAPPS_SETUP` | Set to `1` to install PICO GAPPS. Can be turned on after the first start but cannot be undone without recreating the data volume. | `0` | +| `ANDROID_VERSION` | Android API version to emulate (30 = Android 11, 31 = Android 12, 33 = Android 13, 34 = Android 14, 35 = Android 15, 36 = Android 16). Also enables multi-version support. | `30` | +| `GAPPS_VERSION` | GAPPS version to download. Default behavior derives from ANDROID_VERSION. | `11` | ## 🔄 **First Boot Process** The first time you start the container, it will perform a comprehensive setup process that includes: -1. **AVD Creation:** Creates a new Android Virtual Device running Android 30 (Android 11) +1. **AVD Creation:** Creates a new Android Virtual Device using the Android version configured via ANDROID_VERSION (default 30 – Android 11). This value selects the platform image (e.g., android-${ANDROID_VERSION}) for the AVD and SDK downloads. 2. **PICO GAPPS Installation** (when `GAPPS_SETUP=1`): Adds essential Google services. 3. **Rooting the Device** (when `ROOT_SETUP=1`): Performs multiple reboots to: - Disable AVB verification diff --git a/docker-compose.yml b/docker-compose.yml index 1dd05c4..a32fc31 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,12 +5,15 @@ services: image: shmayro/dockerify-android:latest build: context: . + env_file: + - .env ports: - "5555:5555" volumes: - ./data:/data - ./extras:/extras environment: + ANDROID_VERSION: 30 DNS: one.one.one.one # RAM_SIZE: 4096 # Optional screen resolution in WIDTHxHEIGHT format @@ -22,6 +25,12 @@ services: privileged: true devices: - /dev/kvm + healthcheck: + test: ["CMD", "ps", "aux"] + interval: 30s + timeout: 10s + retries: 60 + start_period: 60s scrcpy-web: container_name: scrcpy-web @@ -38,4 +47,3 @@ services: adb connect dockerify-android:5555 && npm start " - diff --git a/first-boot.sh b/first-boot.sh index f69c81d..061be77 100755 --- a/first-boot.sh +++ b/first-boot.sh @@ -1,5 +1,9 @@ #!/bin/bash +# Android version and GAPPS version handling (defaults kept backward compatible) +ANDROID_VERSION=${ANDROID_VERSION:-30} +GAPPS_VERSION=${GAPPS_VERSION:-11} + bool_true() { case "${1,,}" in 1|true|yes) return 0 ;; @@ -44,30 +48,60 @@ prepare_system() { install_gapps() { prepare_system echo "Installing GAPPS ..." - wget https://sourceforge.net/projects/opengapps/files/x86_64/20220503/open_gapps-x86_64-11.0-pico-20220503.zip/download -O gapps-11.zip - unzip gapps-11.zip 'Core/*' -d gapps-11 && rm gapps-11.zip - rm gapps-11/Core/setup* - lzip -d gapps-11/Core/*.lz - for f in gapps-11/Core/*.tar; do - tar -x --strip-components 2 -f "$f" -C gapps-11 + # Determine GAPPS date and API tag based on Android version. + case "$ANDROID_VERSION" in + 30) + GAPPS_DATE_FROM_VER="20220503"; GAPPS_API_TAG="11.0"; GAPPS_DIR="gapps-11" ;; + 31) + GAPPS_DATE_FROM_VER="20230105"; GAPPS_API_TAG="12.0"; GAPPS_DIR="gapps-12" ;; + 33) + GAPPS_DATE_FROM_VER="20220824"; GAPPS_API_TAG="13.0"; GAPPS_DIR="gapps-13" ;; + 34) + GAPPS_DATE_FROM_VER="20230601"; GAPPS_API_TAG="14.0"; GAPPS_DIR="gapps-14" ;; + 35) + GAPPS_DATE_FROM_VER="20240415"; GAPPS_API_TAG="15.0"; GAPPS_DIR="gapps-15" ;; + 36) + GAPPS_DATE_FROM_VER="20250105"; GAPPS_API_TAG="16.0"; GAPPS_DIR="gapps-16" ;; + *) + GAPPS_DATE_FROM_VER="20220503"; GAPPS_API_TAG="11.0"; GAPPS_DIR="gapps-11" ;; + esac + + # Allow override via GAPPS_VERSION, but keep defaults aligned with ANDROID_VERSION. + if [[ "$GAPPS_VERSION" =~ ^[0-9]+$ ]]; then + if [ "$GAPPS_VERSION" -ge 12 ]; then + GAPPS_API_TAG="12.0"; GAPPS_DATE_FROM_VER="20230105"; GAPPS_DIR="gapps-12" + fi + fi + + OPEN_GAPPS_ARCHIVE="open_gapps-x86_64-${GAPPS_API_TAG}-pico-${GAPPS_DATE_FROM_VER}.zip" + GAPPS_URL="https://sourceforge.net/projects/opengapps/files/x86_64/${GAPPS_DATE_FROM_VER}/${OPEN_GAPPS_ARCHIVE}/download" + ZIP_FILE="gapps-${GAPPS_API_TAG%%.*}.zip" + + wget "$GAPPS_URL" -O "$ZIP_FILE" + unzip "$ZIP_FILE" 'Core/*' -d "$GAPPS_DIR" && rm "$ZIP_FILE" + rm -f "$GAPPS_DIR/Core/setup*" || true + lzip -d "$GAPPS_DIR/Core/*.lz" || true + for f in "$GAPPS_DIR/Core/*.tar"; do + tar -x --strip-components 2 -f "$f" -C "$GAPPS_DIR" done - adb push gapps-11/etc /system - adb push gapps-11/framework /system - adb push gapps-11/app /system - adb push gapps-11/priv-app /system - rm -r gapps-11 + adb push "$GAPPS_DIR/etc" /system + adb push "$GAPPS_DIR/framework" /system + adb push "$GAPPS_DIR/app" /system + adb push "$GAPPS_DIR/priv-app" /system + rm -r "$GAPPS_DIR" || true touch /data/.gapps-done } install_root() { adb wait-for-device echo "Root Script Starting..." - # Root the AVD by patching the ramdisk. + # Root the AVD by patching the ramdisk for the configured Android version. git clone https://gitlab.com/newbit/rootAVD.git pushd rootAVD sed -i 's/read -t 10 choice/choice=1/' rootAVD.sh - ./rootAVD.sh system-images/android-30/default/x86_64/ramdisk.img - cp /opt/android-sdk/system-images/android-30/default/x86_64/ramdisk.img /data/android.avd/ramdisk.img + # Use the dynamic Android version for ramdisk patching + ./rootAVD.sh system-images/android-${ANDROID_VERSION}/default/x86_64/ramdisk.img + cp /opt/android-sdk/system-images/android-${ANDROID_VERSION}/default/x86_64/ramdisk.img /data/android.avd/ramdisk.img popd echo "Root Done" sleep 10 @@ -102,7 +136,7 @@ if [ -f /data/.first-boot-done ]; then fi echo "Init AVD ..." -echo "no" | avdmanager create avd -n android -k "system-images;android-30;default;x86_64" +echo "no" | avdmanager create avd -n android -k "system-images;android-${ANDROID_VERSION};default;x86_64" [ "$gapps_needed" = true ] && install_gapps && [ "$root_needed" = false ] && adb reboot [ "$root_needed" = true ] && install_root