无需Android Studio,脱离复杂的Gradle构建系统,仅用命令行工具完成OpenCV Android .so库的编译
前言
最近在开发一个需要集成OpenCV的Android项目时,我发现传统的Android Studio集成方式存在一些限制:构建流程不透明、难以自定义模块、集成到CI/CD流程复杂。经过一番探索,我成功找到了一种纯命令行编译OpenCV Android库的方法,整个过程完全掌控,非常适合需要自定义构建或自动化集成的场景。
本文将详细介绍我在Windows 11环境下,使用Git Bash、Android NDK、CMake和Ninja,从源码编译OpenCV 4.11.0 Android原生库的完整过程。
环境准备
在开始之前,需要确保你的系统已安装以下工具:
工具 版本要求 作用
Android NDK ≥ r21(推荐r26) Android原生开发工具链
CMake ≥ 3.18 跨平台构建系统
Git for Windows 最新版 提供Bash环境
Ninja 最新版 高性能构建系统
工具路径示例
我的实际环境配置如下:
· OpenCV源码:D:\opencv-4.11.0
· Android NDK:D:\AndroidSDK\ndk\26.3.11579264
· CMake:D:\AndroidSDK\cmake\3.22.1\bin\cmake
· Ninja:D:\ndkTest\ninja-win\ninja.exe
核心编译脚本
经过多次调试和优化,我总结出了以下可靠的编译脚本。这个脚本成功编译出了15个OpenCV Android动态库,总大小约300MB。
bash
#!/bin/bash
# ============================================
# OpenCV 4.11.0 Android 纯命令行编译脚本
# ============================================
set -e # 出错即停止
# === 配置 ===
OPENCV_SRC="/d/opencv-4.11.0"
NDK_PATH="/d/AndroidSDK/ndk/26.3.11579264"
CMAKE_BIN="/d/AndroidSDK/cmake/3.22.1/bin/cmake"
NINJA_BIN="/d/ndkTest/ninja-win/ninja.exe"
# === 编译选项 ===
ABI="arm64-v8a" # 目标架构
API_LEVEL=24 # Android API级别
BUILD_TYPE="Release" # 构建类型
BUILD_DIR="/d/opencv_build_${ABI}" # 构建目录
INSTALL_DIR="/d/opencv-android-output" # 输出目录
echo "========================================"
echo "🚀 OpenCV 4.11.0 Android 纯命令行编译"
echo "========================================"
# 环境检查
check_environment() {
echo "🔍 环境检查..."
[ -d "$OPENCV_SRC" ] || { echo "❌ OpenCV源码不存在: $OPENCV_SRC"; exit 1; }
[ -f "$OPENCV_SRC/CMakeLists.txt" ] || {
echo "❌ OpenCV/CMakeLists.txt不存在"; exit 1;
}
[ -f "$CMAKE_BIN" ] || { echo "❌ CMake不存在: $CMAKE_BIN"; exit 1; }
[ -f "$NINJA_BIN" ] || { echo "❌ Ninja不存在: $NINJA_BIN"; exit 1; }
[ -f "$NDK_PATH/build/cmake/android.toolchain.cmake" ] || {
echo "❌ NDK android.toolchain.cmake不存在"; exit 1;
}
echo "✅ 环境检查通过"
}
# 清理构建目录
clean_build_dir() {
echo "🧹 清理构建目录..."
rm -rf "$BUILD_DIR"
mkdir -p "$BUILD_DIR"
cd "$BUILD_DIR"
}
# CMake配置
configure_cmake() {
echo "⚙️ CMake配置..."
echo " 构建目录: $BUILD_DIR"
echo " 源码目录: $OPENCV_SRC"
"$CMAKE_BIN" \
"$OPENCV_SRC" \
-G "Ninja" \
-DCMAKE_MAKE_PROGRAM="$NINJA_BIN" \
-DCMAKE_TOOLCHAIN_FILE="$NDK_PATH/build/cmake/android.toolchain.cmake" \
-DANDROID_ABI="$ABI" \
-DANDROID_PLATFORM="android-$API_LEVEL" \
-DANDROID_STL="c++_shared" \
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
-DBUILD_JAVA=OFF \
-DBUILD_opencv_java=OFF \
-DBUILD_SHARED_LIBS=ON \
-DBUILD_opencv_core=ON \
-DBUILD_opencv_imgproc=ON \
-DBUILD_opencv_imgcodecs=ON \
-DBUILD_TESTS=OFF \
-DBUILD_EXAMPLES=OFF \
-DBUILD_PERF_TESTS=OFF \
-DBUILD_ANDROID_EXAMPLES=OFF \
-DBUILD_ANDROID_PROJECTS=OFF
[ $? -eq 0 ] && echo "✅ CMake配置成功" || {
echo "❌ CMake配置失败"; exit 1
}
}
# 编译OpenCV
compile_opencv() {
echo "🔨 开始编译..."
"$CMAKE_BIN" --build . --parallel 8
[ $? -eq 0 ] && echo "✅ 编译成功" || {
echo "❌ 编译失败"; exit 1
}
}
# 整理输出文件
collect_output() {
echo "📦 整理输出文件..."
rm -rf "$INSTALL_DIR"
mkdir -p "$INSTALL_DIR/libs/$ABI"
mkdir -p "$INSTALL_DIR/include"
# 复制.so文件
echo " 复制.so文件..."
if [ -d "lib" ]; then
SO_PATHS=("lib/$ABI/*.so" "lib/*.so" "*.so" "bin/*.so")
for pattern in "${SO_PATHS[@]}"; do
if ls $pattern 1>/dev/null 2>&1; then
echo " 找到文件: $pattern"
cp $pattern "$INSTALL_DIR/libs/$ABI/" 2>/dev/null || true
fi
done
fi
# 复制头文件
echo " 复制头文件..."
cp -r "$OPENCV_SRC/include/opencv2" "$INSTALL_DIR/include/" 2>/dev/null || true
# 统计结果
local SO_COUNT=$(ls "$INSTALL_DIR/libs/$ABI/"*.so 2>/dev/null | wc -l)
echo ""
echo "========================================"
echo "🎉 编译完成!"
echo "========================================"
echo "📊 结果统计:"
echo " 架构:$ABI"
echo " API Level:$API_LEVEL"
echo " 构建类型:$BUILD_TYPE"
echo " 库文件数量:$SO_COUNT 个"
echo " 输出目录:$INSTALL_DIR"
}
# 主流程
main() {
check_environment
clean_build_dir
configure_cmake
compile_opencv
collect_output
}
main "$@"
编译过程详解
- 关键配置项解析
脚本中的CMake配置选项是编译成功的关键:
bash
# 禁用Java绑定 - 避免与Android构建系统冲突
-DBUILD_JAVA=OFF
-DBUILD_opencv_java=OFF
# 禁用Android示例项目 - 简化构建流程
-DBUILD_ANDROID_EXAMPLES=OFF
-DBUILD_ANDROID_PROJECTS=OFF
# 启用动态库构建
-DBUILD_SHARED_LIBS=ON
# 使用c++_shared STL - 确保运行时兼容性
-DANDROID_STL="c++_shared"
# 仅启用核心模块(可按需添加更多)
-DBUILD_opencv_core=ON
-DBUILD_opencv_imgproc=ON
-DBUILD_opencv_imgcodecs=ON
- 编译输出结果
执行脚本后,成功编译出15个OpenCV动态库:
库文件 大小 核心功能
libopencv_core.so 23MB 核心数据结构与算法
libopencv_imgproc.so 25MB 图像处理(滤波、变换等)
libopencv_dnn.so 87MB 深度学习模块
libopencv_imgcodecs.so 23MB 图像编解码(JPEG、PNG等)
libopencv_calib3d.so 20MB 相机标定与3D重建
libopencv_features2d.so 6.2MB 特征检测与匹配
libopencv_gapi.so 76MB 图像处理流水线框架
其他8个模块 总计~40MB ML、视频处理等
- 编译耗时统计
· CMake配置阶段:约2-3分钟
· 编译阶段:约20-30分钟(1340个构建任务)
· 总计:约25-35分钟(取决于CPU性能)
在Android项目中的使用
- CMake集成示例
在Android项目的CMakeLists.txt中添加以下配置:
cmake
cmake_minimum_required(VERSION 3.18.1)
project("MyOpenCVApp")
# 设置OpenCV路径
set(OPENCV_ANDROID_DIR "/d/opencv-android-output")
# 包含头文件
include_directories(${OPENCV_ANDROID_DIR}/include)
# 添加你的原生库
add_library(native-lib SHARED
native-lib.cpp
)
# 链接OpenCV库
target_link_libraries(native-lib
${OPENCV_ANDROID_DIR}/libs/${ANDROID_ABI}/libopencv_core.so
${OPENCV_ANDROID_DIR}/libs/${ANDROID_ABI}/libopencv_imgproc.so
# ... 其他需要的库
log
android
)
- JNI简单测试
创建一个简单的JNI函数测试OpenCV功能:
cpp
#include <jni.h>
#include <android/log.h>
#include <opencv2/opencv.hpp>
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_app_MainActivity_testOpenCV(
JNIEnv* env,
jobject /* this */) {
// 创建测试图像
cv::Mat testMat(100, 100, CV_8UC3, cv::Scalar(0, 255, 0));
// 转换为灰度
cv::Mat grayMat;
cv::cvtColor(testMat, grayMat, cv::COLOR_BGR2GRAY);
std::string result = "OpenCV 4.11.0工作正常!\n";
result += "图像尺寸: " + std::to_string(testMat.cols) +
"x" + std::to_string(testMat.rows);
return env->NewStringUTF(result.c_str());
}
常见问题与解决方案
问题1:CMake配置失败
症状:CMake Error: The source directory does not appear to contain CMakeLists.txt
解决:
bash
# 验证OpenCV源码路径
ls -la "/d/opencv-4.11.0/CMakeLists.txt"
# 确保使用的是正确的路径格式(Git Bash使用正斜杠)
问题2:编译时内存不足
症状:编译过程卡住或编译器被杀死
解决:
bash
# 减少并行编译线程数
"$CMAKE_BIN" --build . --parallel 4 # 改为4线程
# 关闭其他内存占用大的程序
问题3:生成的.so文件找不到
症状:编译成功但输出目录为空
解决:
bash
# 手动查找.so文件
find "/d/opencv_build_arm64-v8a" -name "*.so" -type f
# 检查lib目录结构
ls -la "/d/opencv_build_arm64-v8a/lib/"
进阶优化
- 多ABI架构支持
修改脚本支持批量编译多个架构:
bash
#!/bin/bash
# 批量编译多个ABI
ABI_LIST=("arm64-v8a" "armeabi-v7a" "x86_64")
for ABI in "${ABI_LIST[@]}"; do
echo "开始编译 $ABI ..."
# 修改ABI变量并重新执行编译逻辑
BUILD_DIR="/d/opencv_build_${ABI}"
# ... 编译流程
done
- 模块化定制
根据项目需求选择编译的模块:
bash
# 基础图像处理配置(最小化)
-DBUILD_LIST="core,imgproc,imgcodecs"
# 计算机视觉项目配置
-DBUILD_opencv_calib3d=ON
-DBUILD_opencv_features2d=ON
-DBUILD_opencv_objdetect=ON
# 禁用不需要的模块以减少体积
-DBUILD_opencv_dnn=OFF
-DBUILD_opencv_gapi=OFF
总结
通过纯命令行方式编译OpenCV Android库,我获得了以下优势:
- 完全掌控构建过程:可以精确控制编译选项和模块
- 脱离Android Studio依赖:适合CI/CD自动化流程
- 定制化程度高:按需编译,减少应用体积
- 学习价值大:深入理解OpenCV构建系统
这种编译方式特别适合:
· 需要特定OpenCV配置的项目
· 对应用体积敏感的生产环境
· 自动化构建和部署流程
· 学习和研究OpenCV内部结构
希望这篇记录能帮助到有类似需求的开发者。如果在实践过程中遇到问题,欢迎留言讨论。
相关资源:
· OpenCV官方源码
· Android NDK下载
· 完整脚本下载
编译环境:Windows 11 + Git Bash + Android NDK r26 + OpenCV 4.11.0