在目前ndk的最新版本25.1.8937393中有4个libc++_shared.so,用Everything搜索结果如下:
可以看到,大小最小的有4M多。
对于libc++库,官方介绍在此,摘取一些片段如下:
LLVM 的 libc++ 是 C++ 标准库,自 Lollipop 以来 Android 操作系统便一直使用该库,并且从 NDK r18 开始成为 NDK 中唯一可用的 STL。
libc++ 的共享库为 libc++_shared.so,静态库为 libc++_static.a。通常情况下,构建系统将根据用户需要对这些库的使用和打包进行处理。
注意:libc++ 不是系统库。如果您使用 libc++_shared.so,就必须将该库添加到您的应用中。如果您使用 Gradle 构建应用,此步骤会自动完成。
接下来我们来验证一下最后一句话:如果您使用 Gradle 构建应用,此步骤会自动完成。
使用Android Studio的向导创建一个Native C++项目,自动创建的mative-lib.cpp文件如下:
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_cn_dazhou_hello_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
然后运行到模拟器,然后执行:构建 > Analyze Apk…,然后选择我们的app-debug.apk进行分析,如下:
如上图所示,产生的libhello.so大小为114.5KB。这里我们看不到libc++_shared.so,这是因为CMake构建工具默认使用c++_static进行编译的,也就是说会把用到的libc++_shared.so中的相关内容编译到libhello.so中,注意,只是编译用到的相关内容而已,这也是为什么libhello.so只有114.5KB,而libc++_shared.so有4M以上,我们可以配置CMake不使用c++_static,而使用c++_shared,如下:
plugins {
...
}
android {
...
defaultConfig {
applicationId "cn.dazhou.hello"
minSdk 21
targetSdk 32
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
arguments "-DANDROID_STL=c++_shared"
cppFlags '-std=c++17'
}
}
}
externalNativeBuild {
cmake {
path file('src/main/cpp/CMakeLists.txt')
version '3.18.1'
}
}
...
}
dependencies {
...
}
关于cmake的更多参数在此。
这个参数配置的写法我是参考的是这个。
再次运行app,然后再查看apk的分析,如下:
如上图所示,此时就能看到libc++_shared.so了,大小为370.3KB,而libhello.so的大小只有17.3KB。
如果应用包括多个共享库,应使用libc++_shared.so,比如多个Android库有依赖关系,每个库都使用到了libc++,则应该使用c++_shared的方式编译,这样libc++_shared.so的内容就不会被重复打包到多个so中了。多个库中的libc++_shared.so最好保持使用同一个版本,因为最终打包apk时只会选择其中一个libc++_shared.so打包到apk中。
在 Android 系统中,NDK 使用的 libc++ 与操作系统的 libc++ 是不同的(也就是说Android系统本身内部就已经有libc++的实现了)。如此一来,即使应用以旧版 Android 为目标平台,NDK 用户也能获得最新的 libc++ 功能和 bug 修复。需要权衡的是,如果使用 libc++_shared.so,就必须将该库添加到您的应用中。如果使用 Gradle 构建应用,此步骤会自动完成。 早期使用ndk-build进行编译的时候,是不会自动使用 libc++_shared.so的,则默认使用的是系统内部自带的libc++库,比如该系统自带的libc++的版本是C++11,而我们写的C++代码使用到了C++17,则此时运行就会报找不到函数实现,所以需要使用ndk中支持c++17版本的libc++_shared.so实现,如果是用ndk-build编译的就需要指定添加该so,如果是使用gradle编译,则会自动使用对应的so,无需要手动设置。
在以前比较旧版本的Android Studio中,是在local.properties指定NDK路径的,而较新版本的Android Studio已经看不到NDK路径的设置了,这是因为在发布之前,每个AGP(Android Gradle Plugin) 版本都使用当时最新的稳定 NDK 版本进行了全面测试。对于AGP版本 3.6 及更高版本,如果您未在build.gradle文件中指定 NDK 版本,则默认的 NDK 版本将用于构建您的项目。默认的 NDK 版本记录在AGP发行说明中。当前默认的 NDK 版本如下表所列:
Android Studio/Gradle 插件版本 | 对应的默认 NDK 版本 |
---|---|
7.3 | 23.1.7779620 |
7.0 | 21.4.7075529 |
4.2 | 21.4.7075529 |
4.1 | 21.1.6352462 |
4.0 | 21.0.6113669 |
3.6 | 20.0.5594570 |
3.5或更低 | 无默认 |
如果需要使用特定的NDK版本,则可以在app的gradle文件中进行配置,如下:
android {
ndkVersion "major.minor.build" // e.g., ndkVersion "21.3.6528147"
}
其实不同的版本的AGP有不同的设置NDK版本的方式,官网链接在此。