新建支持 C/C++ 的工程
新建工程
新建支持 C/C++ 的工程和我们创建工程的步骤基本一致。
在选择项目模板界面,选择**Native C++**卡片。
点击下一步,然后填入项目的基本信息。
然后一路点击下一步直至完成。
打开新建好的项目。可以看到 cpp 目录与 java 同级。
src/main/cpp 中有 native-lib.cpp
和 CMakeLists.txt
。
另外一个值得关注的是 gradle 文件。里面有 cmake
的配置。
报错: NDK not configured
若无报错请忽略本节
新建工程 Build 栏目出现报错信息
NDK not configured. Download it with SDK manager. Preferred NDK version is '20.0.5594570'. Log: /SampleNDK/app/.cxx/ndk_locator_record.json
信息指出NDK工具没有配置好。`ndk_locator_record.json`给出了详细的信息。
```json
{
"level": "ERROR",
"message": "No version of NDK matched the requested version 20.0.5594570. Versions available locally: 18.1.5063045, 21.2.6472646"
}
项目要求 NDK 版本 20.0.5594570,但电脑上没有与之匹配的版本。
我们前面安装的是 21.2.6472646 版本,可以在 SDK Manager 里下载安装 NDK 20.0.5594570。
安装完毕后,重新打开这个项目即可。
运行工程
在手机上运行这个工程。可以看到效果。
构建和运行过程大致如下:
- Gradle 调用您的外部构建脚本
CMakeLists.txt
。 - CMake 按照构建脚本中的命令将 C++ 源代码文件
native-lib.cpp
编译到共享的对象库中,并将其命名为libnative-lib.so
,Gradle 随后会将后者打包到 APK 中。 - 运行时,应用的
MainActivity
会使用System.loadLibrary()
加载原生库。现在,应用就可以使用库的原生函数stringFromJNI()
了。 MainActivity.onCreate()
会调用stringFromJNI()
,后者会返回“Hello from C++”
,并通过TextView
显示出来。
观察工程
首先关注 cpp 目录下的文件。
CMakeLists.txt
CMakeLists.txt
是构建脚本。文件中进行一些配置。
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 )
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib} )
从文件中可以得知,库的名字叫做 native-lib
,源文件是 native-lib.cpp
。
以前可以用
Android.mk
来进行 ndk-build。现在 cmake 取代了Android.mk
。
cpp 文件
cpp 文件是实现功能的地方。
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_rustfisher_samplendk_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
注意方法的名字,Java_com_rustfisher_samplendk_MainActivity
是带有 Java 文件的包名。
stringFromJNI
是具体的方法名。
以前的 ndk 可以用
javah
生成.h
头文件。现在不需要自己手动生成了。
build.gradle
gradle 中指定了 CMake
的配置。
android {
defaultConfig {
externalNativeBuild {
cmake {
cppFlags ""
}
}
}
// ...
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.10.2"
}
}
}
可指定此 CMake 版本作为最低版本,只需在 build.gradle 条目的末尾添加一个“+”即可,例如 3.10.2+。不过,这并非最佳做法。
Java 文件
MainActivity
需要加载这个库。
static {
System.loadLibrary("native-lib");
}
定义关联的 native 方法。
public native String stringFromJNI();
.so 文件
刚才运行在 armeabi-v7a 架构的手机上。
编译生成的 .so
文件在 app/build/intermediates/cmake/debug/obj/armeabi-v7a/libnative-lib.so
CMake 库文件命名规范:lib
+native-lib
+.so
。即 libnative-lib.so
生成 release 版 apk 时,会打包 .so
文件进去。
修改工程
新建的工程中,配置和方法都是 as 默认的。我们可以根据自己的需要来修改。
修改库名
默认的库名字是 native-lib
,可以自定义修改。
修改 CMakeLists.txt
。把库的名字改成 fisher-lib
,cpp 文件名字改成 fisher-lib.cpp
。
add_library( # Sets the name of the library.
fisher-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
fisher-lib.cpp )
target_link_libraries( # Specifies the target library.
fisher-lib
# Links the target library to the log library
# included in the NDK.
${log-lib} )
cpp 文件的名字改成 fisher-lib.cpp
。
MainActivity
文件中,修改库名。
static {
System.loadLibrary("fisher-lib");
}
再次编译运行即可。
可以在 build 目录中找到 libfisher-lib.so
。
添加 native 方法
仿照已有的方法,在 MainActivity
中添加一个 native 方法。
public native int getIntFromJNI();
fisher-lib.cpp
文件中添加方法。注意要写上返回类型 extern "C" JNIEXPORT int JNICALL
。
extern "C" JNIEXPORT int JNICALL
Java_com_rustfisher_samplendk_MainActivity_getIntFromJNI(
JNIEnv* env,
jobject /* this */) {
return 42;
}
编译运行即可。
本文链接
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于