PAYATHON 2026

gomobile bind 构建 Android AAR 时找不到 bind 包怎么办?

数据小许

结论

可以先按 Go 模块依赖解析问题排查这个错误。即使安装了 gomobile 和 gobind 可执行文件,当前项目也不一定能解析 golang.org/x/mobile/bind。执行 go get 后,如果项目没有保留对相关依赖的引用,接着运行 go mod tidy 时,这些依赖可能被移除。

现有信息还不足以确定唯一原因,需要检查实际使用的 go.mod、工作区、模块替换和工具版本。当前日志也无法证明 NDK 29.x 或 16 KB page size 是这次失败的原因。

如果仍需要通过 Java/Kotlin 调用 Go,保留少量入口并继续使用 gomobile bind 通常更省事。已有 C/JNI 调用层且需要自行控制共享库接口时,可以考虑 -buildmode=c-shared。

为什么安装工具后仍然找不到 bind 包?

下面的命令安装的是命令行工具:

go install golang.org/x/mobile/cmd/gomobile@latest
go install golang.org/x/mobile/cmd/gobind@latest

带版本后缀的 go install 不会向当前项目的 go.mod 添加依赖。即使工具能在终端中运行,项目也不一定能导入生成绑定所需的包。参见 go install 文档。

gomobile bind 需要在当前模块上下文中解析 golang.org/x/mobile/bind。Go Mobile 官方说明也提醒,绑定所需的间接依赖可能被 go mod tidy 删除。gomobile init 不能替代项目中的依赖声明。参见 Go Mobile 指南。

先在执行绑定命令的同一目录检查:

go version
go env GOMOD GOWORK GOFLAGS
go list -m golang.org/x/mobile
go list golang.org/x/mobile/bind

重点看以下结果:

  • GOMOD 是否指向目标项目的 go.mod。
  • GOWORK 是否启用了其他工作区配置。
  • golang.org/x/mobile 是否存在于当前依赖图中。
  • go list golang.org/x/mobile/bind 能否成功解析包。

如果模块存在但包仍无法解析,继续检查 replace 是否指向不完整的本地副本、vendor 是否同步,以及 GOFLAGS 是否设置了影响依赖解析的选项。模块下载成功也不能说明绑定环境已经正确。

如何让依赖在 go mod tidy 后保留?

Go 1.24 及以上:声明工具依赖

在目标项目的模块目录中执行:

go get -tool golang.org/x/mobile/cmd/gomobile golang.org/x/mobile/cmd/gobind
go mod tidy
go list golang.org/x/mobile/bind

-tool 会在 go.mod 中记录工具依赖,让 go mod tidy 保留它们需要的模块。这个机制从 Go 1.24 开始提供;当前 gomobile 源码也在缺少模块依赖时给出了 go get -tool 提示。参见 Go 工具依赖文档和 gomobile 依赖检查代码。

随后可以不带版本后缀安装工具,使用当前模块解析出的版本:

go install golang.org/x/mobile/cmd/gomobile golang.org/x/mobile/cmd/gobind

确认 PATH 中实际执行的是这些工具,然后重新构建:

gomobile bind -v -target=android -androidapi 21 -o output.aar ./mypackage

选择的 golang.org/x/mobile 版本必须与 Go 工具链兼容。排查成功后,应固定依赖版本并保存 go.mod、go.sum,避免持续使用 @latest 导致重建环境变化。

较旧的 Go:使用 tools.go 保留引用

如果不能使用 -tool,可以在模块内添加一个仅用于依赖管理的 tools.go:

//go:build tools
// +build tools

package tools

import _ "golang.org/x/mobile/bind"

然后执行:

go get golang.org/x/mobile/bind
go mod tidy
go list golang.org/x/mobile/bind

这里空白导入的是普通包 golang.org/x/mobile/bind。构建约束使文件不参与默认构建,但 go mod tidy 仍会考虑这类受构建标签约束的引用,因此可以保留依赖。文件名 tools.go 本身没有特殊作用;依赖能否保留取决于文件所在位置、构建约束和导入关系。

这种方式也需要选择兼容的 golang.org/x/mobile 版本,无法解决工具链版本不满足依赖要求的问题。

不向 Java 暴露函数,还适合使用 gomobile bind 吗?

gomobile bind 用于生成语言绑定。Android 输出的 AAR 包含 Java API 类、共享库等内容,适合通过一个较小的绑定层调用内部 Go 逻辑。参见 gomobile bind 命令说明。

“内部使用”也可以采用绑定:大部分实现可以保持私有,只向应用提供必要的启动、执行或停止入口。使用这种方式时,业务包通常不需要自己编写 import "C" 和 //export;它们不是普通 Go 包参与 gomobile 绑定的前提。

如果完全没有 Java/Kotlin、JNI 或其他调用入口,需要先明确逻辑如何触发。代码放进 AAR 后不会自动执行;将 package main 改成普通包后,原来的 main() 也不会继续作为程序入口运行。未被引用的代码还可能被链接器裁剪,因此不能把 AAR 当成保存全部 Go 函数的容器。

什么时候应该改用 -buildmode=c-shared?

如果需要向已有 C/C++ 或 JNI 层提供 C ABI,或者必须自行控制加载方式和接口,-buildmode=c-shared 更符合需求。

这种方式需要一个独立的 package main 入口包,由它导入现有的 mypackage,不能直接把普通库包作为 c-shared 的构建入口。需要从 C 调用的 Go 函数通过 cgo 的 //export 暴露;生成的 C 接口也不会自动变成 Java native 方法。参见 Go build modes 文档。

采用这种方式还需要负责:

  1. 为需要的 Android ABI 配置交叉编译和 NDK 编译器。
  2. 生成各 ABI 对应的 .so。
  3. 按需实现 JNI 桥接和库加载代码。
  4. 将共享库放入 Android Library 模块的 src/main/jniLibs/<ABI>/,再由 Android 构建工具生成 AAR。

仅为了绕过一次模块解析错误而迁移,通常会增加维护工作。可以先修复依赖,再根据实际调用边界决定是否更换方案。

16 KB page size 应如何验证?

依赖错误解决后,还要单独验证产物。NDK r28 及以上默认采用支持 16 KB 的链接对齐设置,但 Go 构建还涉及 Go 工具链和实际链接过程,不能仅凭安装了 NDK 29.x 就认定最终应用兼容。

至少需要检查三件事:

  • AAR 中各 ABI 的 .so 是否具有兼容的 ELF LOAD 段对齐。
  • 最终 APK 中未压缩共享库的 ZIP 对齐是否满足要求。
  • 应用在 16 KB page size 设备或模拟器上能否正常加载并执行相关逻辑。

Android 官方建议使用 APK Analyzer 和 ELF 检查工具检查产物,并在 16 KB 环境中测试。-androidapi 21 指定 Android API 级别,不能代替内存页对齐配置或验证。参见 Android 16 KB page size 指南。

备注:内容仅供参考。