软件版本
SDK、NDK 和 CMake 都是使用 Android Studio 的 SDK Manager 下载的。
- 操作系统:macOS Big Sur Beta
- Android Studio: 4.0.1
- ASSIMP:5.0.1,官网下载地址:The 5.0.1 bugfix release
- SDK:30.0.1
- NDK:21.0.6113669
- CMake:3.10.2.4988404
- Gradle:6.1.1(Android Gradle Plugin Version 是 4.0.1)
交叉编译工具Toolchain
根据NDK版本设定其路径,这里我使用的是 21.0.6113669。NDK提供的standalone_toolchain的路径如下:
$NDK_PATH/build/tools/make-standalone-toolchain.sh
设置环境变量
export NDK_PATH=/Users/zhuxiaoyang/Library/Android/sdk/ndk/21.0.6113669
创建Toolchain 工具
sh make-standalone-toolchain.sh –platform=android-8 –ndk-dir=$NDK_PATH –install-dir=/Users/zhuxiaoyang/Library/Android/sdk/android-toolchain –toolchain=arm-linux-androideabi-4.4.3
安装成功后,提示如下:
到这个目录下会发现名为arm-linux-androideabi.tar.bz2的压缩文件,请把它解压,并放到/Users/zhuxiaoyang/Library/Android/sdk/android-toolchain下。在Mac下是这样的,其他平台应该会直接生成到/Users/zhuxiaoyang/Library/Android/sdk/android-toolchain目录下。
解压后放好,如下图所示。
ASSIMP编译 .so 文件
这里编译的是 armeabi-v7a 版本,其他版本可根据需要修改。
基础环境变量设置
编译时用到的一些工具,都是通过环境变量的形式传给脚本。必须设置的几个环境变量如下:
export ANDROID_NDK_PATH=/Users/zhuxiaoyang/Library/Android/sdk/ndk/21.0.6113669
export ANDROID_SDK_PATH=/Users/zhuxiaoyang/Library/Android/sdk
export CMAKE_TOOLCHAIN=/Users/zhuxiaoyang/Library/Android/sdk/ndk/21.0.6113669/build/cmake/android.toolchain.cmake
export ANDROID_NDK_TOOLCHAIN=/Users/zhuxiaoyang/Library/Android/sdk/android-toolchain
export PATH=$PATH:/Users/zhuxiaoyang/Library/Android/sdk/android-toolchain/bin
CMake 生成 makefile
cd xxx/assimp // 下载assimp解压缩的位置
mkdir build // 创建文件夹
cd build // 进入这个文件夹
然后执行CMake命令
cmake -DCMAKE_TOOLCHAIN_FILE=$CMAKE_TOOLCHAIN -DCMAKE_INSTALL_PREFIX=/assimp -DANDROID_ABI=armeabi-v7a -DANDROID_NATIVE_API_LEVEL=android-14 -DANDROID_FORCE_ARM_BUILD=TRUE -DANDROID_STL=c++_shared -DASSIMP_BUILD_OBJ_IMPORTER=TRUE -DASSIMP_BUILD_FBX_IMPORTER=TRUE -DANDROID_NDK=$ANDROID_NDK_PATH -DCMAKE_BUILD_TYPE=Release -DANDROID_FORCE_ARM_BUILD=TRUE -DCMAKE_CXX_FLAGS=-Wno-c++11-narrowing -DANDROID_TOOLCHAIN=clang -DASSIMP_BUILD_TESTS=OFF -DASSIMP_NO_EXPORT=TRUE -DASSIMP_BUILD_ASSIMP_TOOLS=FALSE -DASSIMP_BUILD_SAMPLES=FALSE -DASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT=FALSE ..
如果是想生成arm64-v8a版本的库,可执行如下命令:
cmake -DCMAKE_TOOLCHAIN_FILE=$CMAKE_TOOLCHAIN -DCMAKE_INSTALL_PREFIX=/assimp -DANDROID_ABI=arm64-v8a -DANDROID_NATIVE_API_LEVEL=android-16 -DANDROID_FORCE_ARM_BUILD=TRUE -DANDROID_STL=c++_shared -DASSIMP_BUILD_OBJ_IMPORTER=TRUE -DASSIMP_BUILD_FBX_IMPORTER=TRUE -DANDROID_NDK=$ANDROID_NDK_PATH -DCMAKE_BUILD_TYPE=Release -DANDROID_FORCE_ARM_BUILD=TRUE -DCMAKE_CXX_FLAGS=-Wno-c++11-narrowing -DANDROID_TOOLCHAIN=clang -DASSIMP_BUILD_TESTS=OFF -DASSIMP_NO_EXPORT=TRUE -DASSIMP_BUILD_ASSIMP_TOOLS=FALSE -DASSIMP_BUILD_SAMPLES=FALSE -DASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT=FALSE ..
参数解释
-DCMAKE_TOOLCHAIN_FILE=$CMAKE_TOOLCHAIN 指向上面生成的toolchain
-DCMAKE_INSTALL_PREFIX=/assimp 最终生成的.so文件的名称
-DANDROID_ABI=armeabi-v7a 应用程序二进制接口类型,详见[ABI Management](https://developer.android.com/ndk/guides/abis)
-DANDROID_NATIVE_API_LEVEL=android-14 api版本,设成这个就行
-DANDROID_FORCE_ARM_BUILD=TRUE 强制编译arm架构
-DANDROID_STL=c++_shared c++类型
-DASSIMP_BUILD_OBJ_IMPORTER=TRUE 支持OBJ格式的3D模型文件导入
-DASSIMP_BUILD_FBX_IMPORTER=TRUE 支持FBX格式的3D模型文件导入
-DASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT=FALSE assimp默认支持很多种3D模型格式,这里只指定常用的一两种格式即可,减小.so包的大小
-DASSIMP_BUILD_TESTS=OFF 这个要关掉,不然make时会有一些奇怪的错误
-DASSIMP_NO_EXPORT=TRUE 只需要解析3D模型,不需要生成3D模型
正确运行的结果如下:
之后执行make命令
make -j4
如无意外,即可编译成功。生成的 libassimp.so 文件在 assimp-5.0.1/buildAndroid/code 目录下。
简单测试
使用 Android Studio 创建Native C++项目。具体可参考 Android Studio 中集成 OpenCV (Java 和 NDK 均可,不使用Manager) 中的 创建 Native C++ 项目。
头文件和库文件拷贝
将 assimp-5.0.1/include/assimp 文件夹整体拷贝到项目app/src/main/cpp/include 文件夹下;将 assimp-5.0.1/build/include/assimp/config.h 文件也拷贝到项目app/src/main/cpp/include 文件夹下。
将 assimp-5.0.1/build/code/libassimp.so 文件拷贝到项目app/src/main/jniLibs/armeabi-v7a 文件夹下。
拷贝完成后,其目录结构如下所示(自动忽略opencv的相关文件夹):
CMakeLists.txt 设置
添加头文件和库文件的引用
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
# ====================================================================================
set(CMAKE_VERBOSE_MAKEFILE on)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -fexceptions -frtti")
set(libs "${CMAKE_SOURCE_DIR}/../jniLibs")
include_directories(include)
# ===== ASSIMP =====
add_library(libassimp SHARED IMPORTED )
set_target_properties(libassimp PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libassimp.so")
# ====================================================================================
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
native-lib.cpp )
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
libassimp
android
${log-lib} )
build.gradle 设置
这里需要注意的是以下几行,否则程序可能会闪退
arguments "-DANDROID_STL=c++_shared"
ndk{
abiFilters "armeabi-v7a"
}
packagingOptions {
pickFirst 'lib/armeabi-v7a/libassimp.so'
}
完整文件如下所示:
apply plugin: 'com.android.application'
android {
compileSdkVersion 30
buildToolsVersion "30.0.1"
defaultConfig {
applicationId "com.casmc.opencvndk"
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags "-std=c++11 -frtti -fexceptions"
arguments "-DANDROID_ABI=armeabi-v7a"
arguments "-DANDROID_STL=c++_shared"
arguments "-DCMAKE_BUILD_TYPE=Release"
}
}
ndk{
abiFilters "armeabi-v7a"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
}
}
packagingOptions {
pickFirst 'lib/armeabi-v7a/libassimp.so'
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
测试文件
为了进行简单的测试,这里需要在 native-lib.cpp 中加上头文件引用
#include <assimp/Importer.hpp>
并在任意一个函数里面添加以下语句:
Assimp::Importer();
编译程序并运行,如果程序不出现闪退,则说明程序能够正常运行。
实际测试
实际的Demo我参考的是 使用Android Studio+CMakeLists编译assimp,并附有 GitHub代码。可根据需要进行更改,这里就不再赘述了。当程序正常运行时,结果如下所示。