AI Agent人工智能大模型AI 应用工具调用本地部署MCP ClientsAgent 记忆【免费下载链接】OperitThe most powerful AI agent and AI chat software on Android/Operit是一款Android上能力最为强大、发展最久的AI Agent项目地址https://gitcode.com/gh_mirrors/op/Operit点击查看免费下载导读本文基于 Operit 仓库中 android_ci_cache_optimization_20260815 这一已通过验证的 TODO 文档系统还原一次针对 Android CI 的缓存与构建优化改造包括 Gradle 依赖/Wrapper/Build Cache 的复用、CMake 源码树source tree与二进制树binary tree的差异化缓存、native ripgrep 缓存 key 的编译环境覆盖以及 DragonBones native 模块 ABI 过滤器的收敛。读完本文你将掌握一套可直接迁移到其他 Android 项目的 CI 缓存设计方法论并理解 Operit 仓库中.github/workflows/*.yml、cmake/operit_git_source.cmake与各build.gradle.kts之间的协作方式。原本状况CI 缓存为何几乎全部失效在优化之前Operit 的 Android CI 存在四类典型的缓存浪费问题文档在「原本状况」一节做了精炼概括Gradle 构建缓存被显式关闭Android CI 显式使用--no-build-cache同时 JDK setup 阶段没有启用 Gradle 依赖与 Wrapper 缓存导致每次 runner 都要重新下载依赖、重新执行可复用任务。CMake 依赖每次全量重下CMake 依赖的 source 位于各模块的.cxx/operit_deps目录每个 runner 启动后都重新下载源码与重新配置。native ripgrep 缓存 key 覆盖不足缓存 key 只包含系统与Cargo.lock没有绑定 NDK、Rust、Android API 或 runner 架构任何一处工具链变化都可能产生失效或不正确的缓存复用。DragonBones 的 ABI 范围不一致DragonBones native module 没有声明 ABI 过滤器而应用和其他 native module 只支持arm64-v8a导致 CI 可能编译多余的 ABI拉长构建时间。修改意图四类目标对应上述四个问题文档明确了四个修改意图让 Gradle 复用依赖、Wrapper 和可复用的 build cache让 CMake 只复用带工具链和源码配置 key 的 source tree不复用带绝对路径的 binary tree让 native ripgrep cache key 覆盖实际编译环境让 DragonBones 的 native 编译范围与应用支持的arm64-v8a一致。下面分别从三个 workflow 与两个 Gradle 文件的实际实现来展开。作用域改动落点本次改动的作用域集中在五个位置与文档「作用域」一节完全对应.github/workflows/android-build.yml.github/workflows/android-tests.yml.github/workflows/pr-check.ymlavator/dragonbones/build.gradle.ktsapp/build.gradle.kts其中前三个是 CI 缓存策略的载体后两个是 ABI 收敛与构建产物校验的载体。下面逐个拆解。Gradle 层依赖、Wrapper 与 Build Cache 的复用JDK setup 启用 Gradle 缓存在 android-build.yml 中JDK 阶段由actions/setup-java承担关键参数是cache: gradle- name: Set up JDK uses: actions/setup-java03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 # v5 with: distribution: temurin java-version: ${{ env.JAVA_VERSION }} cache: gradlecache: gradle会缓存 Gradle Wrapper、依赖缓存~/.gradle/caches等这是文档所说「让 Gradle 复用依赖、Wrapper 和可复用的 build cache」中依赖与 Wrapper 部分的最直接实现。android-tests.yml 与 pr-check.yml 中同样配置了cache: gradle三个 workflow 保持一致。环境变量层面android-build.yml 顶部统一定义了工具链版本env: JAVA_VERSION: 21 NODE_VERSION: 22 ANDROID_NDK_VERSION: 25.1.8937393 ANDROID_CMAKE_VERSION: 3.22.1 ANDROID_API_LEVEL: 26 RUST_VERSION: 1.88.0 MANUAL_DEPS_DIR: manual-deps这些版本号同时被用于 CMake 与 native ripgrep 的缓存 key是后面两个缓存策略正确性的基础。Gradle 构建命令三个 workflow 的最终 Gradle 命令统一为--stacktrace --no-daemon./gradlew $gradle_task --stacktrace --no-daemon保留--no-daemon是为了避免 CI runner 上残留的 daemon 进程带来的不确定性构建缓存复用则交给setup-java的 Gradle cache 与 task 层面的 up-to-date 判定不再需要每次显式传入--build-cache之外的多余参数。CMake 层只缓存源码树不缓存二进制树为什么源码树可缓存、二进制树不可缓存在 cmake/operit_git_source.cmake 中operit_declare_git_source函数为每个依赖生成了两个目录set(deps_root ${CMAKE_SOURCE_DIR}/.cxx/operit_deps) set(source_dir ${deps_root}/${source_token}-src) set(binary_dir ${deps_root}/${source_token}-build)其中source_dir是依赖源码的下载与解压位置内容只由依赖名与 resolved SHA 决定因此可以安全缓存而binary_dir是 CMake 的构建产物目录里面会包含绝对路径、编译缓存等与具体 runner 环境强绑定的内容跨 runner 复用会引发路径失效。这正是文档「只复用带工具链和源码配置 key 的 source tree不复用带绝对路径的 binary tree」的底层原因。operit_declare_git_source通过operit_resolve_git_ref将 tag/branch 解析成 40 位 commit SHA再用operit_normalize_source_token生成依赖名-SHA形态的目录 token最终形成*.cxx/operit_deps/xxx-sha-src的目录结构avator/dragonbones/CMakeLists.txt、avator/fbx/CMakeLists.txt、avator/mmd/CMakeLists.txt 都通过include(${CMAKE_CURRENT_LIST_DIR}/../../cmake/operit_git_source.cmake)引入该函数族并调用operit_prepare_git_source。CMake 源码缓存的实际 keyandroid-build.yml 中对应步骤为- name: Restore Android CMake source cache uses: actions/cachecaa296126883cff596d87d8935842f9db880ef25 # v5 with: path: | **/.cxx/operit_deps/*-src key: android-cmake-sources-${{ runner.os }}-${{ runner.arch }}-arm64-v8a-ndk-${{ env.ANDROID_NDK_VERSION }}-cmake-${{ env.ANDROID_CMAKE_VERSION }}-${{ hashFiles(cmake/**, **/CMakeLists.txt, **/*.cmake, **/build.gradle.kts, gradle.properties) }}这里值得注意的细节path 只匹配*-src即只缓存源码树目录*-build目录被刻意排除key 包含 runner 架构${{ runner.arch }}、NDK 版本${{ env.ANDROID_NDK_VERSION }}、CMake 版本${{ env.ANDROID_CMAKE_VERSION }}以及arm64-v8aABI 标签hashFiles 覆盖cmake/**、所有CMakeLists.txt、*.cmake、build.gradle.kts与gradle.properties任何影响 CMake 配置的内容变更都会使 key 失效从而保证缓存与当前构建配置严格一致。pr-check.yml的android_buildjob 中使用了完全相同的 cache stepRestore Android CMake source cache。这套设计直接呼应文档的修改意图CMake source 缓存可以命中并保存约337 MB详见「验证与结果」一节。native ripgrep 层缓存 key 绑定完整编译环境native ripgrep 位于 tools/native_ripgrep是一个crate-type [cdylib]的 Rust 工程见 Cargo.toml依赖 globset、grep-*、ignore、jni 等。改造前缓存 key 只含系统与Cargo.lock无法区分 NDK、Rust 工具链与目标架构。改造后的 cache step三个 workflow 中完全一致为- name: Restore native ripgrep cache uses: actions/cachecaa296126883cff596d87d8935842f9db880ef25 # v5 with: path: | ~/.cargo/registry ~/.cargo/git tools/native_ripgrep/target key: native-ripgrep-arm64-${{ runner.os }}-${{ runner.arch }}-ndk-${{ env.ANDROID_NDK_VERSION }}-api-${{ env.ANDROID_API_LEVEL }}-rust-${{ env.RUST_VERSION }}-${{ hashFiles(tools/native_ripgrep/Cargo.toml, tools/native_ripgrep/Cargo.lock, tools/native_ripgrep/**/*.rs, tools/native_ripgrep/build_native_ripgrep.ps1) }}cache 的 path 覆盖三部分~/.cargo/registrycrates.io 依赖的注册表缓存~/.cargo/gitgit 依赖缓存tools/native_ripgrep/targetRust 编译产物目录含aarch64-linux-android/release下的liboperit_ripgrep.so。key 的组成对比改造前新增了runner.arch架构、ANDROID_NDK_VERSIONNDK 版本、ANDROID_API_LEVELAndroid API 级别与RUST_VERSIONRust 工具链版本四个维度再叠加对Cargo.toml、Cargo.lock、全部*.rs源文件与构建脚本build_native_ripgrep.ps1的 hashFiles。这样任何影响最终.so的输入变化都会精确触发 key 失效同时避免了只按 Cargo.lock 缓存却换了个 NDK 导致产物不匹配的隐患。对应的构建步骤三个 workflow 一致展示了完整的交叉编译链路export ANDROID_NDK_HOME$ANDROID_HOME/ndk/$ANDROID_NDK_VERSION export CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android${ANDROID_API_LEVEL}-clang rustup toolchain install $RUST_VERSION --profile minimal rustup target add --toolchain $RUST_VERSION aarch64-linux-android cargo $RUST_VERSION build \ --manifest-path tools/native_ripgrep/Cargo.toml \ --release \ --target aarch64-linux-android \ --locked install -Dm755 \ tools/native_ripgrep/target/aarch64-linux-android/release/liboperit_ripgrep.so \ app/src/main/jniLibs/arm64-v8a/liboperit_ripgrep.so test -s app/src/main/jniLibs/arm64-v8a/liboperit_ripgrep.so构建产物最终被安装到app/src/main/jniLibs/arm64-v8a/与应用的 ABI 过滤范围对齐。--locked保证严格按Cargo.lock解析依赖避免 CI 环境下依赖漂移。ABI 收敛DragonBones 与应用对齐到 arm64-v8a改造前 DragonBones native module 没有声明 ABI 过滤器CMake 会为所有默认 ABI 编译而应用与其他 native module 都只支持arm64-v8a。改造后在 avator/dragonbones/build.gradle.kts 的defaultConfig中加入ndk { abiFilters.addAll(listOf(arm64-v8a)) }同时该模块还保留了 CMake 配置externalNativeBuild { cmake { path file(CMakeLists.txt) version 3.22.1 } }version 3.22.1与 workflow 中ANDROID_CMAKE_VERSION环境变量、以及 CMake source cache key 中的cmake-3.22.1严格对应形成了workflow 安装的 CMake 版本 模块要求的 CMake 版本 缓存 key 中的版本三方一致。应用侧 app/build.gradle.kts 同样只保留arm64-v8andk { abiFilters.addAll(listOf(arm64-v8a)) }此外应用还对外部构建的原生库做了打包前校验verifyExternallyBuiltNativeLibraries任务它要求src/main/jniLibs/arm64-v8a/liboperit_ripgrep.so存在且非空并要求本地libs/ffmpeg-kit-local.aar内包含jni/arm64-v8a/下 libavcodec、libavdevice、libffmpegkit 等 10 个 so 条目。这些校验确保最终 APK 的原生打包路径只会出现lib/arm64-v8a/与文档验证清单中「构建日志中的 native packaging 路径仅使用lib/arm64-v8a/」一致。Android 依赖与 STT 资产的二级缓存除了上述三条主线workflow 还包含另外两类动作缓存共同构成完整的缓存矩阵手动依赖缓存manual-deps- name: Restore Android dependency cache id: cache-manual-deps uses: actions/cachecaa296126883cff596d87d8935842f9db880ef25 # v5 with: path: ${{ env.MANUAL_DEPS_DIR }} key: android-full-deps-${{ runner.os }}-${{ hashFiles(ci/script/download_android_dependencies.sh, ci/script/prepare_android_dependencies.py) }}配合if: steps.cache-manual-deps.outputs.cache-hit ! true条件只有未命中时才执行bash ci/script/download_android_dependencies.sh full $MANUAL_DEPS_DIR下载随后由 prepare_android_dependencies.py 以--profile full解包到仓库。pr-check.yml 中 JVM 测试 job 还区分了android-jvm-deps-*与android-full-deps-*两个 key按需复用。STT 模型资产缓存- name: Restore generated STT asset cache uses: actions/cachecaa296126883cff596d87d8935842f9db880ef25 # v5 with: path: app/build/generated/stt-model-assets key: stt-model-assets-${{ runner.os }}-${{ hashFiles(app/config/stt-model-assets.properties) }}key 绑定 app/config/stt-model-assets.properties 的哈希避免重复下载与生成体积较大的 STT 模型资产。验证与结果数据说话文档「验证」清单列出了完整验收路径通过 workflow YAML、仓库门禁check_repo_hygiene.py 等与 diff 检查推送ci/android-cache-optimization分支到 fork在 fork PR 中验证 Android build 与 Android JVM tests连续运行确认 Gradle、CMake source 与 native ripgrep cache 均命中确认构建日志中 native packaging 路径仅使用lib/arm64-v8a/。文档「结果」一节给出了 fork run31875454511的实测数据阶段首次第二次Android buildGradle24m31s329个 actionable tasks 中29个来自 cacheCMake source cache 首次 miss保存约337 MB15m46sjob 总耗时约17m51s329个 actionable tasks 中116个来自 cacheAndroid JVM tests约11m04s约2m28s第二次日志同时确认了 Gradle wrapper/dependency、CMake source 与 native ripgrep cache 三项均命中。两轮结果直观反映了缓存策略的价值构建时间从24m31s压缩到15m46s来自 cache 的任务数从29提升到116JVM 测试更是从11m04s降到2m28s接近 4.5 倍提速。小结可迁移的缓存设计清单从本次改造可以提炼出一套通用的 Android CI 缓存设计原则Gradle 依赖与 Wrapper 必须开缓存actions/setup-java的cache: gradle是最低成本、最高收益的一步CMake 只缓存 source tree源码树按工具链版本 ABI 配置哈希生成 keybinary tree 因含绝对路径而排除Rust 交叉编译缓存 key 要覆盖完整工具链至少包含 NDK、Android API、Rust 版本与 runner 架构再叠加源码哈希ABI 范围全局收敛各 native module 与应用保持同一abiFilters既省编译时间也避免多余产物进入 APK为体积较大的生成资产单独建缓存如 STT 模型资产绑定其配置文件的哈希。这套方案在 Operit 仓库中已经过完整验证相关实现均可直接查阅android-build.yml、android-tests.yml、pr-check.yml、cmake/operit_git_source.cmake 与 avator/dragonbones/build.gradle.kts。赞分享AI Agent人工智能大模型AI 应用工具调用本地部署MCP ClientsAgent 记忆【免费下载链接】OperitThe most powerful AI agent and AI chat software on Android/Operit是一款Android上能力最为强大、发展最久的AI Agent项目地址https://gitcode.com/gh_mirrors/op/Operit点击查看免费下载相关推荐ILC高级路由模式动态路由、嵌套路由和特殊路由的完整解析ILC高级路由模式动态路由、嵌套路由和特殊路由的完整解析 你是否正在构建企业级微前端架构却为复杂的路由管理而头疼 本文将为你详细解析ILC框架中的高级如何用Claude Code Hooks打造你的AI编程助手完整指南如何用Claude Code Hooks打造你的AI编程助手完整指南 如果你正在寻找一种方法让AI编程助手更智能、更安全、更可控那么Claude CodeNES.css构建优化缓存策略与长期缓存NES.css构建优化缓存策略与长期缓存 NES.css作为一款NES风格的CSS框架在前端开发中广受欢迎。然而随着项目规模的扩大如何优化构建流程并实现前端UI组件上一篇Wox 窗口布局与工作区恢复完全指南从窗口吸附到多应用工作区一键还原下一篇Simple Live 直播聚合应用教程一个 App 看完 B站、抖音、斗鱼、虎牙创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
