
用 Bazel 9 构建 LiteRT-LM Android 演示应用UI 布局与状态机实现指南【免费下载链接】LiteRT-LMLiteRT-LM is Googles production-ready, high-performance, open-source inference framework for deploying Large Language Models on edge devices.项目地址: https://gitcode.com/GitHub_Trending/li/LiteRT-LMLiteRT-LM 是 Google 面向边缘设备部署大语言模型的高性能开源推理框架本文聚焦于其 Android 演示应用litert_lm_android_sample_app的 UI 布局、界面状态机与 Bazel 9Bzlmod构建配置内容以仓库内 ui_layout_and_state.md 为骨架并结合仓库源码与依赖集成文档补充底层依据。读完本文你将掌握如何用 Bazel 9 Bzlmod 搭建可编译的 Android 工程、如何实现模型选择 → 后端选择 → 推理的严格 UI 状态机、如何处理 Android 15 Edge-to-Edge 与多模态文件选择以及如何在无 AppCompat 的环境下规避崩溃。一、文档定位与适用场景该规范文档是仓库中create-litert-lm-android-demo-app技能见 SKILL.md的核心参考之一专门用于指导 Agent 在首轮即一次性完成 LiteRT-LM Android 演示应用的 UI 与状态机实现并满足无模拟器/无真机环境下的静态合规审计Pass (Static/Build Only)。它的作用边界很明确只覆盖 UI 布局、控件状态与构建配置不含真实推理调用推理规则见 inference_implementation.md默认构建路径为Bazel 9 BzlmodGradle、Bazel 7 等其他工具链可能可用但不在本文覆盖范围依赖获取分两种场景本地源码构建dependency_source_build.md与 Maven AAR 集成dependency_maven_integration.md。二、Workspace 设置目录即 Bazel 工作区根规范要求新建一个名为litert_lm_android_sample_app的目录直接位于指定的根目录之下并满足所有 Android 应用源码、MODULE.bazel与BUILD文件必须位于该目录内该目录即 Bazel workspace root整个示例应用不得在其外散落文件。[!NOTE] 在 Bazel 9 下MODULE.bazel是唯一的依赖声明入口严禁创建WORKSPACE文件这是技能中的硬性约束之一参见 SKILL.md 的 WORKSPACE Modification Ban。三、Bazel 9 构建配置详解3.1 目标版本边界在MODULE.bazel中配置依赖映射时应使用以下经过验证的版本组合依赖版本边界用途rules_android~0.7.1Android 构建规则rules_kotlin~2.3.20Kotlin 编译kt_android_libraryrules_java~7.12.2Java 规则如java_importrules_jvm_external~6.2Maven 依赖解析Bzlmod 扩展仓库自身 Kotlin 绑定层的构建即是典型印证kotlin/java/com/google/ai/edge/litertlm/BUILD中同时定义了kt_jvm_librarylitertlm-jvm与kt_android_librarylitertlm-android后者依赖org_jetbrains_kotlinx_kotlinx_coroutines_android这解释了演示应用为何必须通过rules_jvm_external拉取协程与 JSON 等传递依赖。3.2 SDK 版本与 Edge-to-Edge 强制要求示例应用AndroidManifest.xml中targetSdkVersion必须为 API 35以满足 Android 15 强制启用的 Edge-to-Edge 行为状态栏/导航栏透明化后内容可能绘制到系统栏下方代码中必须处理 window insets例如通过ViewCompat.setOnApplyWindowInsetsListener为根布局设置padding避免控件被系统栏遮挡为此需引入androidx.core:core-ktx这也是两个依赖集成文档中唯一被反复标注Required的 UI 依赖。3.3 Bzlmod 结构要求Bazel 9 专属Bazel 版本管理始终在目标目录内通过bazelisk运行以确保正确的本地.bazelversion生效避免直接调用裸bazel命令。禁止 WORKSPACEBazel 9 示例应用不得创建WORKSPACE文件依赖全部经MODULE.bazel的 Bzlmod 机制声明。ARM64 目标架构针对 Pixel 8 等设备禁用旧式--fat_apk_cpu等遗留 flag使用平台 flag--android_platformsrules_android//:arm64-v8a该 flag 必须被持久记录到task.md的 Environment, Tools Reference Paths 章节并追加到每一条bazel build/bazel test命令中设置此 flag 有两个目的Option A保证 fat AAR 中的 native 库被正确抽取Option B保证 C 代码按正确架构编译。Java 规则若java_import在BUILD中无法解析需显式加载load(rules_java//java:defs.bzl, java_import)。这与源码构建场景下litert_lm_prebuilt/BUILD的写法完全一致见 dependency_source_build.md。C17构建执行时传递--cxxopt-stdc17 --host_cxxopt-stdc17。这与仓库 Android 交叉编译工具链的定位一致cmake/toolchains/litertlm_android.toolchain.cmake中默认ANDROID_STLc_shared说明 native 层以共享 STL 方式链接宿主与目标必须使用一致的 C 标准。Load 路径BUILD文件中的 Android 规则必须从rules_android//rules:rules.bzl加载而不是rules_android//android:rules.bzl。3.4 AAR 依赖与maven.install配置通过rules_jvm_external引入 AAR 依赖如 Markwon时必须配置use_starlark_android_rules使用 Starlark Android 规则否则会报name aar_import is not defined错误maven.install( artifacts [ androidx.core:core-ktx:1.12.0, # Required to handle Edge-to-Edge system window insets in Kotlin # Add other application UI dependencies here (e.g. io.noties.markwon:core:4.6.2) ], version_conflict_policy pinned, use_starlark_android_rules True, aar_import_bzl_label rules_android//rules:rules.bzl, )其中version_conflict_policy pinned用于固定冲突依赖版本详见下文 Troubleshootingaar_import_bzl_label与 3.3 节的 load 路径保持一致。在 Maven 集成场景中还需加入 LiteRT-LM 预编译坐标com.google.ai.edge.litertlm:litertlm-android:latest.release并声明maven.google.com与repo1.maven.org两个仓库参见 dependency_maven_integration.md。3.5 SDK 扩展配置必须在MODULE.bazel中显式配置 Android SDKandroid_sdk_repository_extension use_extension( rules_android//rules/android_sdk_repository:rule.bzl, android_sdk_repository_extension ) android_sdk_repository_extension.configure( path /path/to/Android/Sdk, api_level 35, build_tools_version 35.0.0, ) use_repo(android_sdk_repository_extension, androidsdk) # Add androidsdk//:sdk-toolchain and androidsdk//:all to register_toolchains in MODULE.bazel该配置同时作为自动 SDK 探测失败时的兜底方案见合规清单 Bzlmod SDK Configuration Fallback 一项。若目标设备架构与宿主不同还需通过rules_android_ndk~0.1.5的android_ndk_repository_extension.configure(path ...)提供 native C 编译工具链技能要求 NDK 版本严格为27.3.13750724。四、UI 状态机五个状态的严格流转状态机是整个界面交互的核心约束其设计与 LiteRT-LM 引擎的初始化过程一一对应引擎初始化耗时长见下文源码佐证状态行为Initial仅 Model Picker 可用Backend Selector、Message Inputs 全部禁用。注意要禁用每一个RadioButton本身而不是只禁用RadioGroupModel Picked禁用 Model Picker复制模型文件到 cache 期间显示加载动画完成后启用 Backend SelectorBackend Selected禁用 Backend Selector初始化 mock/真实引擎期间显示加载动画Model Loaded停止加载动画。按模型类型分两种情况多模态模型启用全部输入Image、Audio、Text input、Send纯文本模型只启用 Text input 和 SendImage 与 Audio 按钮必须保持禁用Inference显示加载动画禁用全部消息输入以防止并发请求完成后成功或出错恢复输入可用关键要求所有加载状态必须复用同一个加载动画辅助函数如startLoadingAnimation保证动画样式与速度完全一致loading.、loading..、loading...每点 500ms 延迟并且动画要显示在对话显示区Conversation Display中。从源码角度看状态机与 Engine.kt 的初始化语义高度吻合Engine.initialize()内部调用LiteRtLmJni.nativeCreateEngine(...)其注释明确警告初始化可能耗时数秒到十余秒必须放到后台线程执行——这正是 Backend Selected → 显示加载动画 → 引擎初始化完成 状态迁移存在的直接原因。五、UI 组件细节规范5.1 按钮与 Model PickerPick Model、Image、Audio 三个按钮应共享同一视觉风格保证 UI 一致性点击 Pick Model 必须唤起真实系统文件选择器Intent(Intent.ACTION_GET_CONTENT)MIME 类型*/*以兼容各类模型文件扩展名文件选择器通过startActivityForResult在按钮点击监听器中启动所选模型文件名必须水平显示在 Pick Model 按钮右侧且显示真实解析出的文件名见 5.4 文件名解析严禁硬编码别名如model.bin。5.2 Backend SelectorCPU / GPU 两个 RadioButtonBackend: 标签必须位于左侧左对齐默认不选中任何选项。5.3 Conversation Display 与输入区使用垂直LinearLayout嵌于ScrollView之内ScrollView必须分配 ID如id/sv_conversation以便编程式滚动图片设置adjustViewBounds true文本消息必须支持 Markdown 渲染如io.noties.markwon:core:4.6.2Text Input 应可滚动以容纳长查询发送按钮位于输入框右侧。5.4 媒体输入与文件名解析Image PickerIntent(Intent.ACTION_GET_CONTENT)MIME 类型image/*Audio PickerIntent(Intent.ACTION_GET_CONTENT)MIME 类型audio/*文件名解析处理content://URI 时禁止依赖Uri.lastPathSegment必须通过ContentResolver查询OpenableColumns.DISPLAY_NAME获取真实文件名合规清单中 Audio Filename Resolution 一栏同样强制此项扩展名与缓存保留所有选中的文件模型、视频、音频流必须复制到context.cacheDir并解析、保留原始文件扩展名严禁将原始content://URI 直接传给 native API——因为 native 引擎与编解码器会检查扩展名以验证格式兼容性。这一约束与仓库 runtime 层的实现逻辑相互印证runtime/util/litert_lm_loader.cc等加载器通过路径/文件格式工具判断模型文件格式见 file_format_util.ccnative 侧对文件扩展名敏感因此 Kotlin 层必须先落地为真实文件再交给 JNI。六、UI 布局图垂直顺序强制约束各组件的相对垂直位置必须严格遵循以下顺序|--------------| | Pick Model | Model Name |--------------| Backend: ( ) CPU ( ) GPU |-----------------------------| | | | Conversation | | Display | | (ScrollView) | | | | [loading...] | |-----------------------------| |-------| |-------| | Image | | Audio | |-------| |-------| |---------------------| | | |-------| | Text input | | Send | | | |-------| |---------------------|细节要求对话容器需使用weight布局参数填满垂直剩余空间见合规清单 Conversation Display Layout Weight即使在文本模型降级场景下Image / Audio 按钮也必须始终完整声明在布局 XML 与 Kotlin 视图中禁止动态隐藏或移除仅通过代码置为 disabled见 compliance_checklist_ui.md 的 Multi-modal UI 小节。七、约束与实现规则共享加载动画所有加载状态模型选取、引擎初始化、等待响应复用同一辅助函数startLoadingAnimation样式与速度一致500ms/点并显示在对话区内主线程 UI 更新UI 更新与动画状态必须显式派发到主线程例如withContext(Dispatchers.Main)自动滚动新增内容及流式响应更新文本时用.post {}包裹fullScroll(View.FOCUS_DOWN)保证最新内容始终可见显式 UI 对比度防止动态主题对比度缺陷在 Activity 根布局上设置android:forceDarkAllowedfalse禁用 Force Dark为所有组件——包括按钮、对话显示、文本输入、标签、单选选择器——显式设置对比明显的文本色与背景/容器色确保完全可读。后台文件操作要求模型与媒体的复制、读取全部在后台线程执行不得阻塞 UI 线程合规清单 Background File Operations。八、TroubleshootingCoursier 重复工件版本若构建日志出现 Coursier 重复工件版本警告如com.google.code.gson:gson has multiple versions说明不同模块引入了不同版本解决方案在maven.install中设置version_conflict_policy pinned将冲突版本固定为单一版本。该警告在仓库自身也具备现实背景kotlin/java/com/google/ai/edge/litertlm/BUILD中litertlm-jvm与litertlm-android均依赖com.google.code.gson:gson与 kotlinx-coroutines 系列当演示应用同时引入预编译绑定与自有依赖时极易出现版本分叉pinned 策略可一劳永逸地消除这类不确定性。九、合规审计清单与静态验证方法实现完成后需对照 compliance_checklist_ui.md 生成compliance_review_ui.md并逐项审计。该清单覆盖四大板块、数十个检查项要点包括Setup Build目录名、minSdkVersion 24、targetSdkVersion 35、无 WORKSPACE、ARM64 平台 flag、Activity 直连非 AppCompat、SDK 配置兜底、Edge-to-Edge 处理UI State Flow初始态/选模型/选后端/推理态/推理后态的完整流转、CPUGPU 双选项、无默认选中、共享动画助手、动画必须跟踪真实后台操作禁止模拟固定时长Layout Components真实文件选择器、模型名水平对齐、布局顺序与 ASCII 图一致、weight填充、adjustViewBounds、Markdown、自动滚动证据必须引用fullScroll调用行号、forceDarkAllowedfalse与显式对比色Multi-modal UI File Handling媒体按钮常驻、文本模型降级禁用、图片视觉渲染、音频以文件名/图标标识、OpenableColumns解析、后台文件操作、扩展名与缓存保留。审计证据必须给出带行号的文件链接或精确的终端日志块禁止 verified 之类的空泛描述任何代码改动后必须将所有状态重置为Pending后完整重跑审计。十、集成到 LiteRT-LM 依赖体系UI 状态机中的 Model Loaded 状态依赖底层绑定库就绪两种依赖场景各有固化流程源码构建编译//kotlin/java/com/google/ai/edge/litertlm:litertlm-android得到 Kotlin Class JAR并将 native.so按lib/abi/结构打包为litertlm_native.jar放入litert_lm_prebuilt/后经java_import引入严禁使用cc_import否则.so可能被打入 APK 错误路径加速库如libLiteRtGpuAccelerator.so见仓库 prebuilt/android_arm64/BUILD应一并打入 Native JARMaven 集成直接声明com.google.ai.edge.litertlm:litertlm-android:latest.release在BUILD的deps中引用maven//:com_google_ai_edge_litertlm_litertlm_android详见 dependency_maven_integration.md。无论走哪条路径UI 层的状态机、加载动画与文件缓存逻辑均保持一致先复制模型到cacheDir再初始化引擎后台线程最后按模型能力文本/多模态决定可用的输入控件——这正是第四章状态机与第七章实现规则的最终落点。结语本文以 ui_layout_and_state.md 为骨架完整覆盖了 LiteRT-LM Android 演示应用的 Bazel 9 构建配置、五态 UI 状态机、组件级布局约束、文件处理与合规审计方法。无论你是手工实现还是希望交给 Agent 按技能规范自动生成这套规则都能保证应用在 Android 15API 35上不因 Edge-to-Edge、主题对比度或 AppCompat 缺失而崩溃并让多模态交互图像/音频输入与文本对话流畅共存于同一界面。【免费下载链接】LiteRT-LMLiteRT-LM is Googles production-ready, high-performance, open-source inference framework for deploying Large Language Models on edge devices.项目地址: https://gitcode.com/GitHub_Trending/li/LiteRT-LM创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考