{ config, pkgs, lib, ... }: let cfg = config.modules.android; in { options.modules.android = { enable = lib.mkEnableOption "Android development environment with emulator support"; enableEmulator = lib.mkOption { type = lib.types.bool; default = true; description = "Enable Android emulator for testing Flutter and Android apps"; }; apiLevel = lib.mkOption { type = lib.types.int; default = 34; description = "Default Android API level for the emulator"; }; enableFlutterSupport = lib.mkOption { type = lib.types.bool; default = true; description = "Enable Flutter SDK and related tools"; }; }; config = lib.mkIf cfg.enable { home.packages = with pkgs; [ # Android Studio Full with FHS environment (recommended for NixOS) # This includes SDK, emulator, and all necessary tools android-studio-full # Core Android command-line tools android-tools # Build and compilation tools gradle maven ninja cmake gnumake pkg-config # Java/Kotlin development jdk jdk21 kotlin # Flutter SDK for app development (if cfg.enableFlutterSupport then flutter else null) # Flutter Version Manager (if cfg.enableFlutterSupport then fvm else null) # Additional Android tools scrcpy # Screen sharing for Android devices apksigner # Sign APKs ]; # Environment variables for Android development home.sessionVariables = lib.mkIf cfg.enable { ANDROID_HOME = "$HOME/.android"; ANDROID_SDK_ROOT = "$HOME/Android/Sdk"; ANDROID_USER_HOME = "$HOME/.android"; JAVA_HOME = "${pkgs.jdk}/lib/openjdk"; # For Flutter development ANDROID_JAVA_HOME = "${pkgs.jdk}"; }; # Create a script to launch the Android emulator # Note: This works with the NixOS androidenv setup home.file.".local/share/bin/android-emulator" = lib.mkIf cfg.enableEmulator { executable = true; text = '' #!/usr/bin/env bash # Android Emulator launcher script for NixOS # Uses android-studio-full's built-in tools set -e EMULATOR_NAME="''${1:-flutter-dev}" API_LEVEL="''${2:-${toString cfg.apiLevel}}" echo "Starting Android Emulator: $EMULATOR_NAME (API $API_LEVEL)" # Check if AVD exists, if not create it if ! grep -q "^[^#]*name=$EMULATOR_NAME" ~/.android/avd/devices.txt 2>/dev/null; then echo "Creating AVD: $EMULATOR_NAME..." # Try using avdmanager from Android Studio if command -v avdmanager &> /dev/null; then echo "no" | avdmanager create avd \ --name "$EMULATOR_NAME" \ --package "system-images;android-$API_LEVEL;google_apis;x86_64" \ --device "pixel_6" \ --force 2>&1 || { echo "Error: Could not create AVD" echo "Try running: android-studio to set up SDK from the IDE" exit 1 } else echo "Error: avdmanager not found" echo "Please open Android Studio and complete the SDK setup:" echo " android-studio" echo "" echo "Then use SDK Manager to download system images for API $API_LEVEL" exit 1 fi fi # Launch emulator with optimizations for NixOS emulator -avd "$EMULATOR_NAME" \ -memory 2048 \ -partition-size 4096 \ -dns-server 8.8.8.8 \ -no-snapshot-load \ -no-snapshot-save \ -gpu auto \ -no-boot-anim \ & EMULATOR_PID=$! echo "Emulator starting in background (PID: $EMULATOR_PID)" echo "Waiting for boot..." # Wait for emulator to boot for i in {1..90}; do if adb shell getprop sys.boot_completed 2>/dev/null | grep -q "1"; then echo "✓ Emulator fully booted!" exit 0 fi echo -n "." sleep 2 done echo "" echo "⚠ Timeout waiting for emulator to boot" exit 1 ''; }; # Create a setup script to initialize Android environment on first use home.file.".local/share/bin/android-setup" = lib.mkIf cfg.enable { executable = true; text = '' #!/usr/bin/env bash # One-time setup script for Android development on NixOS echo "Setting up Android development environment..." echo "" # Check if sdkmanager is available if ! command -v sdkmanager &> /dev/null; then echo "Warning: sdkmanager not found in PATH" echo "This is normal on NixOS. You'll need to use Android Studio to manage SDKs." echo "" echo "Opening Android Studio for SDK setup..." android-studio & echo "" echo "In Android Studio:" echo " 1. Go to Tools → SDK Manager" echo " 2. Select API levels you want to download" echo " 3. Click 'Apply' and 'OK'" echo " 4. Close Android Studio when done" exit 0 fi # Accept Android licenses echo "Accepting Android licenses..." yes | sdkmanager --licenses 2>&1 | tail -10 echo "" echo "✓ Android environment setup complete!" echo "" echo "Next steps:" echo " 1. Run: android-emulator (to create and start emulator)" echo " 2. For Flutter: flutter doctor" echo " 3. For Android Studio: android-studio" echo "" ''; }; # Optional: Add udev rules for Android devices # This allows debugging on physical devices without root home.file.".config/udev/rules.d/51-android.rules" = lib.mkIf cfg.enable { text = '' # Android debug bridge - allows USB debugging without sudo SUBSYSTEM=="usb", ATTR{idVendor}=="0bb4", MODE="0666", GROUP="adbusers" SUBSYSTEM=="usb", ATTR{idVendor}=="0e79", MODE="0666", GROUP="adbusers" SUBSYSTEM=="usb", ATTR{idVendor}=="0502", MODE="0666", GROUP="adbusers" SUBSYSTEM=="usb", ATTR{idVendor}=="0b05", MODE="0666", GROUP="adbusers" SUBSYSTEM=="usb", ATTR{idVendor}=="413c", MODE="0666", GROUP="adbusers" SUBSYSTEM=="usb", ATTR{idVendor}=="0489", MODE="0666", GROUP="adbusers" SUBSYSTEM=="usb", ATTR{idVendor}=="091e", MODE="0666", GROUP="adbusers" SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", MODE="0666", GROUP="adbusers" SUBSYSTEM=="usb", ATTR{idVendor}=="0d4d", MODE="0666", GROUP="adbusers" SUBSYSTEM=="usb", ATTR{idVendor}=="05c6", MODE="0666", GROUP="adbusers" SUBSYSTEM=="usb", ATTR{idVendor}=="04e8", MODE="0666", GROUP="adbusers" SUBSYSTEM=="usb", ATTR{idVendor}=="04da", MODE="0666", GROUP="adbusers" SUBSYSTEM=="usb", ATTR{idVendor}=="04b7", MODE="0666", GROUP="adbusers" SUBSYSTEM=="usb", ATTR{idVendor}=="04b8", MODE="0666", GROUP="adbusers" SUBSYSTEM=="usb", ATTR{idVendor}=="04b9", MODE="0666", GROUP="adbusers" SUBSYSTEM=="usb", ATTR{idVendor}=="0bed", MODE="0666", GROUP="adbusers" SUBSYSTEM=="usb", ATTR{idVendor}=="1d4d", MODE="0666", GROUP="adbusers" ''; }; }; }