最近收到一个小伙伴的私信,Android平台帮忙编译一个Native C++项目,这个项目中用到了Protobuf 和OpenCV两个C++库,其中OpenCV有现成的动态库.so了,但是Protobuf并没有现成的,需要自己拿源码编译!废话不多说,直接上干货...
首先,准备编译所需要的工具
在 macOS M4(ARM 架构)上为 Android 交叉编译 Protobuf (如v3.19.6版本)的 .so 动态库,需要使用 Android NDK 配置交叉编译环境,针对不同的 Android CPU 架构(如 arm64-v8a、armeabi-v7a、x86_64 等)生成对应版本的库。
-
安装依赖工具
确保已安装基础编译工具cmake 和版本控制工具git,使用brew安装即可。
-
下载 Android NDK
交叉编译 Android 库需要 NDK 提供的工具链,可以直接去官网下载, 也可以在Android Studio的SDK Manager中下载。下载完成解压到指定目录,这个目录我们称为NDK_PATH,也可以将它配置环境变量中
-
下载 Protobuf 3.19.6 源码
bash
git clone https://github.com/protocolbuffers/protobuf.git
cd protobuf
git checkout v3.19.6
git submodule update --init --recursive # 拉取子模块(如 googletest)
接着,交叉编译 Protobuf 到 Android .so(核心步骤)
Protobuf 支持 CMake 交叉编译,需为每个目标架构(如 arm64-v8a、armeabi-v7a)单独配置编译参数。
1. 定义编译参数(通用配置
先设置通用变量,方便后续复用:
bash
# NDK 路径(替换为你的实际路径)
export NDK_PATH=/Users/xxx/Library/Android/sdk/ndk/26.1.10909125
# Protobuf 源码根目录(当前目录)
export PROTOBUF_SRC=$(pwd)
# 输出目录(所有架构的 .so 最终会放到这里)
export OUTPUT_DIR=$(pwd)/android_build
mkdir -p $OUTPUT_DIR
2. 针对不同架构编译(以 arm64-v8a 为例)
Android 主流架构包括: arm64-v8a(64 位 ARM,主流新设备) armeabi-v7a(32 位 ARM,老旧设备) x86_64(64 位 x86,模拟器常用) 以下以 arm64-v8a 为例,其他架构仅需修改对应参数即可。
步骤 1:设置当前架构的参数
ini
# 目标架构(根据需要替换为 armeabi-v7a、x86_64 等)
TARGET_ARCH=arm64-v8a
# NDK 对应的工具链架构(arm64-v8a 对应 aarch64,armeabi-v7a 对应 arm,x86_64 对应 x86_64)
TOOLCHAIN_ARCH=aarch64
# Android 最小支持版本(根据需求修改,如 21 及以上支持 64 位)
MIN_SDK_VERSION=21
# 构建目录(每个架构单独一个目录,避免冲突)
BUILD_DIR=$(pwd)/build_$TARGET_ARCH
mkdir -p $BUILD_DIR
cd $BUILD_DIR
步骤 2:生成 CMake 交叉编译配置
使用 NDK 提供的 build/cmake/android.toolchain.cmake 工具链文件,指定交叉编译参数:
ini
cmake \
-DCMAKE_SYSTEM_NAME=Android \ # 目标系统为 Android
-DCMAKE_SYSTEM_VERSION=$MIN_SDK_VERSION \ # 最小 SDK 版本
-DCMAKE_ANDROID_ARCH_ABI=$TARGET_ARCH \ # 目标 ABI
-DCMAKE_ANDROID_NDK=$NDK_PATH \ # NDK 路径
-DCMAKE_ANDROID_STL_TYPE=c++_shared \ # 使用 C++ 共享库(需与应用一致)
-DCMAKE_BUILD_TYPE=Release \ # Release 模式(优化编译)
-DCMAKE_INSTALL_PREFIX=$OUTPUT_DIR/$TARGET_ARCH \ # 安装路径(按架构区分)
-DBUILD_SHARED_LIBS=ON \ # 编译动态库(.so)
-DBUILD_STATIC_LIBS=OFF \ # 不需要静态库
-Dprotobuf_BUILD_TESTS=OFF \ # 禁用测试(加速编译)
-Dprotobuf_BUILD_EXAMPLES=OFF \ # 禁用示例
$PROTOBUF_SRC/cmake # cmakelist.txt 所在目录
步骤 3:编译并安装
bash
# 编译(-j 后面的数字为并行线程数,根据 CPU 核心数调整,如 8)
make -j8
# 安装到指定的输出目录($OUTPUT_DIR/$TARGET_ARCH)
make install
编译完成后,OUTPUT_DIR/TARGET_ARCH/lib*** 目录下会生成 libprotobuf.so 和 libprotobuf-lite.so(轻量版)。
3. 编译其他架构
替换 TARGET_ARCH 和 TOOLCHAIN_ARCH 重复上述步骤即可:
armeabi-v7a:
ini
TARGET_ARCH=armeabi-v7a
TOOLCHAIN_ARCH=arm
MIN_SDK_VERSION=16 # 32 位最低支持 16
x86_64:
ini
TARGET_ARCH=x86_64
TOOLCHAIN_ARCH=x86_64
MIN_SDK_VERSION=21

最后,将以上步骤写成一个脚本文件,只需要在一个空文件夹下执行脚本即可。
protobuf_android.sh
bash
#!/bin/bash
# 配置参数(请根据实际环境修改)
NDK_PATH="/Users/xxx/Library/Android/sdk/ndk/26.1.10909125" # Android NDK 路径
PROTOBUF_VERSION="v3.19.6" # Protobuf 版本
OUTPUT_ROOT="$PWD/protobuf-android-build" # 输出目录根路径
MIN_SDK_ARM64=21 # arm64-v8a 最小支持 SDK 版本
MIN_SDK_ARM32=21 # armeabi-v7a 最小支持 SDK 版本
MIN_SDK_X86=21 # x86_64 最小支持 SDK 版本
THREADS=4 # 并行编译线程数(根据 CPU 核心数调整)
# 检查 NDK 是否存在
if [ ! -d "$NDK_PATH" ]; then
echo "错误:NDK 路径不存在,请检查 NDK_PATH 配置"
exit 1
fi
# 检查依赖工具
check_dependency() {
if ! command -v $1 &> /dev/null; then
echo "错误:未找到 $1,请先安装(可通过 brew install $1)"
exit 1
fi
}
check_dependency "git"
check_dependency "cmake"
check_dependency "make"
# 添加vpn终端代理命令,加速从github上下载代码
#export https_proxy=http://xxx:端口 http_proxy=http://xxx:端口 all_proxy=socks5://xxx:端口
# 克隆并准备 Protobuf 源码
echo "===== 下载 Protobuf $PROTOBUF_VERSION 源码 ====="
if [ ! -d "protobuf" ]; then
git clone https://github.com/protocolbuffers/protobuf.git || exit 1
fi
cd protobuf || exit 1
git checkout $PROTOBUF_VERSION || exit 1
git submodule update --init --recursive || exit 1
PROTOBUF_SRC=$(pwd)
cd .. || exit 1
# 创建输出目录
mkdir -p "$OUTPUT_ROOT"
# 交叉编译函数(参数:目标架构 工具链架构 最小 SDK 版本)
build_arch() {
local TARGET_ARCH=$1
local TOOLCHAIN_ARCH=$2
local MIN_SDK=$3
local BUILD_DIR="$PWD/build_$TARGET_ARCH"
local INSTALL_DIR="$OUTPUT_ROOT/$TARGET_ARCH"
echo -e "\n===== 开始编译 $TARGET_ARCH 架构 ====="
echo "构建目录: $BUILD_DIR"
echo "安装目录: $INSTALL_DIR"
# 创建并进入构建目录
mkdir -p "$BUILD_DIR" && cd "$BUILD_DIR" || exit 1
# 运行 CMake 配置
cmake \
-DCMAKE_SYSTEM_NAME=Android \
-DCMAKE_SYSTEM_VERSION=$MIN_SDK \
-DCMAKE_ANDROID_ARCH_ABI=$TARGET_ARCH \
-DCMAKE_ANDROID_NDK=$NDK_PATH \
-DCMAKE_ANDROID_STL_TYPE=c++_shared \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX="$INSTALL_DIR" \
-DBUILD_SHARED_LIBS=ON \
-DBUILD_STATIC_LIBS=OFF \
-Dprotobuf_BUILD_TESTS=OFF \
-Dprotobuf_BUILD_EXAMPLES=OFF \
"$PROTOBUF_SRC/cmake" || {
echo "CMake 配置 $TARGET_ARCH 失败"
exit 1
}
# 编译并安装
make -j$THREADS || {
echo "编译 $TARGET_ARCH 失败"
exit 1
}
make install || {
echo "安装 $TARGET_ARCH 失败"
exit 1
}
# 返回上层目录
cd .. || exit 1
echo "===== $TARGET_ARCH 编译完成 ====="
}
# 编译各架构(按需求注释不需要的架构)
build_arch "arm64-v8a" "aarch64" $MIN_SDK_ARM64
build_arch "armeabi-v7a" "arm" $MIN_SDK_ARM32
build_arch "x86_64" "x86_64" $MIN_SDK_X86
echo -e "\n===== 所有架构编译完成 ====="
echo "输出目录: $OUTPUT_ROOT"
echo "各架构 .so 文件路径:"
find "$OUTPUT_ROOT" -name "libprotobuf.so"