Android NDK 编译 protobuf

最近收到一个小伙伴的私信,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 等)生成对应版本的库。

  1. 安装依赖工具

    确保已安装基础编译工具cmake 和版本控制工具git,使用brew安装即可。

  2. 下载 Android NDK

    交叉编译 Android 库需要 NDK 提供的工具链,可以直接去官网下载, 也可以在Android Studio的SDK Manager中下载。下载完成解压到指定目录,这个目录我们称为NDK_PATH,也可以将它配置环境变量中

  3. 下载 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.solibprotobuf-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"
相关推荐
沐怡旸3 小时前
【底层机制】ART虚拟机深度解析:Android运行时的架构革命
android·面试
小禾青青3 小时前
uniapp安卓打包遇到报错:Uncaught SyntaxError: Invalid regular expression: /[\p{L}\p{N}]/
android·uni-app
studyForMokey4 小时前
【Kotlin内联函数】
android·开发语言·kotlin
2501_915921436 小时前
iOS 抓不到包怎么办?工程化排查与替代抓包方案(抓包/HTTPS/Charles代理/tcpdump)
android·ios·小程序·https·uni-app·iphone·tcpdump
诸神黄昏EX7 小时前
Android Init 系列专题【篇六:reboot & shutdown】
android
sTone873757 小时前
Android核心概念(一)minSdkVersion targetSdkVersion compileSdkVersion
android·前端
wuweikai06177 小时前
在Android设备上打开Perfetto调试日志开关
android·性能优化·perfetto
Meteors.7 小时前
安卓进阶——多媒体
android