Android JNI NDK 开发
2019-04-17 本文已影响21人
dongbingliu
Android 开发过程中必然会涉及 JNI 与 NDK 开发,简单梳理下 JNI 流程
开发环境:Android Studio 3.3 、CMake :3.10 、NDK:19 ,LLDB:3.1
image.pngAndroid Studio 新建工程:
New Project → Native C++ → C++ Standard
默认已经搭建好 JNI 模板 Hello from C++
CMakeList.txt
# 有关使用CMake在Android Studio的更多信息,请阅读文档:https://d.android.com/studio/projects/add-native-code.html
# 设置CMake的最低版本构建本机所需库
cmake_minimum_required(VERSION 3.4.1)
# 创建并命名库,将其设置为静态的
# 或共享,并提供其源代码的相对路径。
# 你可以定义多个library库,并使用CMake来构建。
# Gradle会自动将包共享库关联到你的apk程序。
add_library( # 设置库的名称
native-lib
# 将库设置为共享库。
SHARED
# 为源文件提供一个相对路径。
src/main/cpp/native-lib.cpp )
# 搜索指定预先构建的库和存储路径变量。因为CMake包括系统库搜索路径中默认情况下,只需要指定想添加公共NDK库的名称,在CMake验证库之前存在完成构建
find_library( # 设置path变量的名称
log-lib
# 在CMake定位前指定的NDK库名称
log )
# 指定库CMake应该链接到目标库中,可以链接多个库,比如定义库,构建脚本,预先构建的第三方库或者系统库
target_link_libraries( # 指定目标库
native-lib
# 目标库到日志库的链接 包含在NDK
${log-lib} )
native-lib.cpp
extern "C" JNIEXPORT jstring JNICALL
Java_com_apple_jnisample03_NativeUtils_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
MainActivity 中使用 JNI 接口
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Example of a call to a native method
TextView tv = findViewById(R.id.sample_text);
tv.setText(stringFromJNI());
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
编译 C++ 代码到 APP 的流程
- Gradle 调用外部构建脚本,CMakeLists.txt;
- CMake 根据构建脚本指令去编译一个 C++源文件,
native-lib.cpp
,编译后的产物扔进共享对象库中,并将其命名为libnative-lib.so
,然后 Gradle 将其打包到 APK 中;- 运行期间,app 的 MainActivity 会调用
System.loadLibrary()
方法,加载 native library,而这个库的原生函数 stringFromJNI()
原项目基础上添加自己的代码
添加 getHelloJni()
接口
public class NativeUtils {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
public native String stringFromJNI();
public native String getHelloJni();
}
extern "C" JNIEXPORT jstring JNICALL
Java_com_apple_jnisample03_NativeUtils_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_apple_jnisample03_NativeUtils_getHelloJni(
JNIEnv *env,
jobject instance
){
return env->NewStringUTF("Hello Jni,欢迎使用 JniSample Hello World");
}
编译打包的 libnative-lib.so 路径
build
→ intermediates
→ cmake
→ debug(release)
→ obj
→ *libnative-lib.so
使用已经编译好的 *.so 文件,JNI 调用 so 文件。
main 目录下新建文件夹jniLibs
「注意」:文件夹名字大小写不能变。
so 文件中 Java_com_apple_jnisample_NativeUtils_getHelloJni()方法,则需建立对应包名com.apple.jnisample.NativeUtils.java 中 System.loadLibrary("native-lib");「去掉库文件的前缀 lib 以及后缀.so」
声明需要使用的方法即可;