- 开发工具
- CLI
【免费下载链接】devenv
Fast, Declarative, Reproducible, and Composable Developer Environments using Nix
导读
本文围绕 devenv 的android.enable集成模块,讲解如何在 Nix 驱动的开发环境中一键构建可复现的 Android 开发环境:包括完整可复制的devenv.nix配置、SDK 版本选择策略(nixpkgs androidenv 与 android-nixpkgs 两套来源的取舍)、模拟器创建的正确姿势,以及 React Native 与 Flutter 的专用配置。读完本文,你将能独立写出适用于 Android 原生、RN、Flutter 项目的 devenv 配置,并理解底层ANDROID_HOME、NDK、Gradle 参数是如何被 Nix 模块组装起来的。
最小可用配置:三行开启 Android 环境
在项目根目录创建devenv.nix,写入如下内容即可获得一套完整可用的 Android 开发环境:
{ pkgs, ... }: { android.enable = true; }android.enable是 src/modules/integrations/android.nix 中定义的总开关。开启后,该模块会自动完成一系列环境搭建工作:
- 向
packages注入完整 SDK 组合(SDK、platform-tools、模拟器等,具体来源见下文); - 自动开启 Java 语言支持(
java.enable = lib.mkDefault true,见 src/modules/integrations/android.nix); - 设置
ANDROID_HOME、ANDROID_NDK_ROOT环境变量; - 通过
GRADLE_OPTS让 Gradle 使用 SDK 自带的 patched aapt2; - 进入 shell 时自动生成
local.properties(写入sdk.dir与ndk.dir),并设置ANDROID_USER_HOME/ANDROID_AVD_HOME到当前目录的.android/下(见 src/modules/integrations/android.nix)。
也就是说,android.enable = true不只是"装上几个包",而是把 JDK、SDK 路径、Gradle 参数和本地属性文件全部一次性配置到位。
仓库还提供了一个精简的参考示例 examples/android/devenv.nix,它在默认配置基础上显式关闭了 Android Studio:
{ pkgs, ... }: { android.enable = true; android.android-studio.enable = false; }定制化配置:完整选项清单与默认值
如果默认组合不满足需求,可以按需指定各组件版本。官方文档给出了一份覆盖几乎所有选项的完整配置:
{ pkgs, ... }: { android = { enable = true; platforms.version = [ "32" "34" ]; systemImageTypes = [ "google_apis_playstore" ]; abis = [ "arm64-v8a" "x86_64" ]; cmake.version = [ "3.22.1" ]; cmdLineTools.version = "11.0"; tools.version = "26.1.1"; # platformTools.version defaults to latest from nixpkgs buildTools.version = [ "30.0.3" ]; emulator = { enable = true; # version defaults to latest from nixpkgs }; sources.enable = false; systemImages.enable = true; ndk.enable = true; googleAPIs.enable = true; googleTVAddOns.enable = true; extras = [ "extras;google;gcm" ]; extraLicenses = [ "android-sdk-preview-license" "android-googletv-license" "android-sdk-arm-dbt-license" "google-gdk-license" "intel-android-extra-license" "intel-android-sysimage-license" "mips-android-sysimage-license" ]; android-studio = { enable = true; package = pkgs.android-studio; }; }; }对照 src/modules/integrations/android.nix 中的选项定义,各选项的真实默认值如下表:
| 选项 | 默认值 | 说明 |
|---|---|---|
platforms.version | [ "32" "34" "36" ] | 要安装的 Android 平台(API level)列表 |
systemImageTypes | [ "google_apis_playstore" ] | 系统镜像类型 |
abis | [ "arm64-v8a" "x86_64" ] | 目标 ABI 列表 |
cmake.version | [ "3.22.1" ] | 随 SDK 安装的 CMake 版本 |
cmdLineTools.version | "11.0"(若启用 Flutter 则为"8.0") | 命令行工具版本 |
tools.version | "26.1.1" | 旧版 SDK tools 版本 |
platformTools.version | nixpkgs 中最新版本 | 由 nixpkgs 的repo.json动态解析 |
buildTools.version | [ "34.0.0" ](若启用 Flutter 则为[ "35.0.0" "33.0.2" "30.0.3" ]) | Build Tools 版本列表 |
emulator.enable | true | 是否包含模拟器 |
emulator.version | nixpkgs 中最新版本 | 动态解析 |
sources.enable | false | 是否包含 Android 源码 |
systemImages.enable | true | 是否包含系统镜像 |
ndk.enable | true | 是否包含 NDK |
ndk.version | [ "26.1.10909125" ](Flutter 下为[ "28.2.13676358" ]) | NDK 版本列表 |
googleAPIs.enable | true | 是否使用 Google APIs |
googleTVAddOns.enable | true | 是否使用 Google TV Add-Ons |
extras | [ "extras;google;gcm" ] | 额外组件 |
extraLicenses | 上表所列 7 个 license 的默认集合 | 自动接受的额外许可证 |
android-studio.enable/.package | false/pkgs.android-studio | 是否安装 Android Studio 及使用的包 |
flutter.enable/.package | false/pkgs.flutter | 是否包含 Flutter 工具 |
reactNative.enable | false | 是否包含 React Native 工具 |
默认值的底层来源
需要特别说明:platformTools.version与emulator.version的默认值并不是写死的字符串,而是从 nixpkgs 的 androidenv 仓库 JSON 中动态读取的。源码实现如下(src/modules/integrations/android.nix):
repoJson = builtins.fromJSON (builtins.readFile "${toString pkgs.path}/pkgs/development/mobile/androidenv/repo.json"); availableVersions = package: builtins.attrNames repoJson.packages.${package}; latestVersion = package: lib.last (builtins.sort lib.lessThan (availableVersions package));这就是文档中"platformTools.version和emulator.version默认使用 nixpkgs 中的最新版本"这一说法的实现依据。因此,这两个选项的可用版本完全取决于你所引用的 nixpkgs 快照——如果你尝试构建一个不存在的版本,构建报错信息里会列出所有可用版本。
环境变量与 Gradle 的底层联动
开启模块后,以下环境变量会被自动注入(src/modules/integrations/android.nix):
ANDROID_HOME:指向组装好的 SDK 根目录;ANDROID_NDK_ROOT:指向ndk-bundle(nixpkgs 来源)或ndk/<version>(android-nixpkgs 来源);GRADLE_OPTS:-Dorg.gradle.project.android.aapt2FromMavenOverride=<ANDROID_HOME>/build-tools/<首个 buildTools 版本>/aapt2,强制 Gradle 使用 SDK 中打过补丁的 aapt2,避免与从 Maven 拉取的版本产生不兼容;- 启用 Flutter 时还会设置
FLUTTER_ROOT与DART_ROOT。
进入 shell 时还会把tools、platform-tools、cmdline-tools/latest/bin、emulator目录加入PATH,并导出ANDROID_USER_HOME、ANDROID_AVD_HOME指向项目目录下的.android/,确保 AVD 状态不污染全局用户目录。
关于 unfree 包的重要前提
Android SDK 包含大量 unfree 软件包(如 Google Play Store 系统镜像、部分闭源组件),因此必须在devenv.yaml中允许 unfree 包,否则构建会直接失败:
nixpkgs: allow_unfree: true选择 SDK 版本:nixpkgs androidenv 的滞后问题
platforms.version、buildTools.version、ndk.version等选项所能选择的版本,全部来自 nixpkgs 内置的androidenv包集合。由于 androidenv 的更新节奏落后于 Google 的官方发布,一个刚发布的新版本(例如platforms;android-36)在 androidenv 中可能还不可用,此时选择它会导致构建失败。
注意:这里说的"不可用"是相对于你当前锁定的 nixpkgs 版本而言的。当前仓库默认的platforms.version已经是[ "32" "34" "36" ],说明该 nixpkgs 快照已包含 API 36——但这并不改变 androidenv 整体滞后于 Google 官方发布的客观事实。
切换到 android-nixpkgs:获得每日更新的完整版本集
要选取完整且最新的版本集合,官方推荐引入android-nixpkgsinput。该项目基于 Google 的 SDK 仓库每日重新生成,因此新平台、新 Build Tools 版本的可用性远超 nixpkgs androidenv。
添加 input 的命令如下:
$ devenv inputs add android-nixpkgs github:tadfisher/android-nixpkgs --follows nixpkgs这条命令会修改项目根目录的devenv.yaml。从 CLI 实现看,devenv inputs add是早期分发的命令之一,会先定位到外层项目根再编辑其devenv.yaml,避免在子目录中误建游离的配置文件(见 devenv/src/main.rs)。
发布轨道(release track)的选择
android-nixpkgs 的发布轨道由 input 的 URL ref 决定,默认是stable。如需其他轨道,把 URL 指向对应分支即可:
github:tadfisher/android-nixpkgs(默认stable)github:tadfisher/android-nixpkgs/betagithub:tadfisher/android-nixpkgs/previewgithub:tadfisher/android-nixpkgs/canary
切换后的行为变化
一旦android-nixpkgsinput 存在,模块会自动把 SDK 来源切换为 android-nixpkgs。源码中的判定逻辑非常直接(src/modules/integrations/android.nix):
android-nixpkgs = inputs.android-nixpkgs or null; useAndroidNixpkgs = android-nixpkgs != null;切换后:
platforms.version、buildTools.version、ndk.version以及emulator.enable会被自动映射到 android-nixpkgs 的对应 SDK 包(映射规则见 src/modules/integrations/android.nix:版本号中的.会被转换为-,例如35.0.0→build-tools-35-0-0、36→platforms-android-36);ANDROID_HOME指向share/android-sdk,NDK 目录布局变为ndk/<version>(与 nixpkgs 来源的ndk-bundle不同);- 系统镜像、源码、CMake、extras 不在自动映射范围内,需要把这些组件直接加入 devenv 的顶层
packages。
组合示例:同时使用两套配置
以下配置展示了切换到 android-nixpkgs 后选择新版本,并手工安装系统镜像的完整写法:
{ inputs, pkgs, ... }: { android = { enable = true; platforms.version = [ "34" "35" "36" ]; buildTools.version = [ "35.0.0" ]; }; packages = [ (inputs.android-nixpkgs.sdk.${pkgs.system} (sdkPkgs: with sdkPkgs; [ system-images-android-36-google-apis-playstore-x86-64 ])) ]; }注意:android-nixpkgs 目前支持
x86_64-linux、x86_64-darwin与aarch64-darwin三个平台(见 src/modules/integrations/android.nix 中android-nixpkgs.sdk.${pkgs.system}的调用方式,实际可用平台以 android-nixpkgs 自身声明为准)。
模拟器:绕过 Android Studio GUI,用 CLI 创建 AVD
由于 Nix 的不可变 store 路径与 Android Studio 对可变路径的要求存在冲突,直接在 Android Studio 的 GUI 中创建模拟器可能无法正常工作。官方推荐的做法是先用命令行创建 AVD,再在 Android Studio 中开发。
创建 AVD
使用avdmanager(位于 cmdline-tools 中,进入 devenv shell 后已在PATH中)创建:
avdmanager create avd --force --name my-android-emulator-name --package 'system-images;android-32;google_apis_playstore;x86_64'创建完成后即可用任意文本编辑器进行 Android 开发。官方文档记录的真实测试场景是:先在外部用上述命令创建好模拟器,然后在 Android Studio 自带的终端里运行一个 React Native 项目,能够成功运行。
需要注意,AVD 的存放位置由ANDROID_AVD_HOME决定——模块在进入 shell 时已将其指向项目目录下的.android/avd/,因此每个项目的模拟器状态是相互隔离的。
React Native:一行开启 RN 工具链
android.reactNative.enable会额外启用 JavaScript 与 npm 工具链,并把 JDK 固定为pkgs.jdk17(与 reactnative.dev 的环境设置文档)。该配置已通过 React Native starter 项目验证:
{ pkgs, ... }: { android = { enable = true; reactNative.enable = true; }; }Flutter:一行开启 Flutter 工具链
android.flutter.enable会额外启用 Dart 语言支持、安装 Flutter 包,并把 JDK 固定为pkgs.jdk17(与 developer.android.com 的 JDK 版本建议)。该配置已通过 Flutter starter 项目验证:
{ pkgs, ... }: { android = { enable = true; flutter.enable = true; }; }Flutter 的自动路径同步任务
开启 Flutter 后,模块还会注册一个名为devenv:android:flutter:sync-properties的 task(src/modules/integrations/android.nix),在每次进入 shell(before = [ "devenv:enterShell" ])之前自动运行,负责:
- 更新
android/local.properties与各级子目录中的同名文件:写入sdk.dir=$ANDROID_HOME、ndk.dir=$ANDROID_NDK_ROOT、flutter.sdk=$FLUTTER_ROOT; - 更新
ios/Flutter/Generated.xcconfig中的FLUTTER_ROOT; - 更新
ios/flutter_export_environment.sh中的FLUTTER_ROOT导出。
这个 task 的存在意味着:即使你手动改动了local.properties,每次进入 devenv shell 时这些路径都会被重新纠正为当前环境值,从机制上杜绝了"换机器后 Flutter 找不到 SDK"的经典问题。
总结:配置速查与常见问题
| 场景 | 需要做什么 |
|---|---|
| 仅 Android 原生开发 | android.enable = true+devenv.yaml中nixpkgs.allow_unfree = true |
| 需要 Android Studio | 追加android.android-studio.enable = true |
| 需要最新 SDK 版本 | devenv inputs add android-nixpkgs github:tadfisher/android-nixpkgs --follows nixpkgs,并按需指定platforms.version等 |
| 需要新版本系统镜像 | 通过 android-nixpkgs 的sdk函数加入顶层packages |
| React Native | android.reactNative.enable = true |
| Flutter | android.flutter.enable = true |
常见问题速查:
- 构建报"版本不可用":说明所选版本在当前 nixpkgs androidenv(或 android-nixpkgs 轨道)中不存在。查看报错信息列出的可用版本列表,或切换到 android-nixpkgs 获取更新版本。
- 构建报 unfree 包被拒绝:检查
devenv.yaml中是否已设置nixpkgs.allow_unfree = true。 - Android Studio 中无法创建 AVD:改用
avdmanager create avd命令行方式创建,再在 IDE 中连接使用。 - Gradle 报 aapt2 相关错误:确认
GRADLE_OPTS中aapt2FromMavenOverride指向的 SDK 路径存在且 build-tools 版本已安装。
本文全部配置项均可在 src/modules/integrations/android.nix 中找到实现定义,参考示例见 examples/android/devenv.nix,原始文档见 docs/src/content/docs/integrations/android.md。
- 开发工具
- CLI
【免费下载链接】devenv
Fast, Declarative, Reproducible, and Composable Developer Environments using Nix
相关推荐
Nixpkgs Android 开发环境(androidenv)完全指南:从 SDK 组合到模拟器与 Ant 构建
Nixpkgs Android 开发环境(androidenv)完全指南:从 SDK 组合到模拟器与 Ant 构建 本篇技术指南围绕 nixpkgs 仓库中 a
包管理器操作系统devenv 0.2 版本解析:可组合的开发环境、`devenv search` 搜索命令与本地覆盖机制
devenv 0.2 版本解析:可组合的开发环境、 devenv search 搜索命令与本地覆盖机制 导读:devenv 是一款基于 Nix 构建的「快速、声
开发工具CLI小米手环SDK Android版开发指南
小米手环SDK Android版开发指南 本教程将指导您如何理解和使用 pangliang/miband sdk android 这一开源项目,它提供了与早期版
智能硬件物联网
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考