NDK简介
官方文档介绍如下:
The Android NDK is a toolset that lets you implement parts of your app in native code, using languages such as C and C++. For certain types of apps, this can help you reuse code libraries written in those languages.
大概意思就是NDK它是一个工具集, 它可以让你使用C/C++语言来实现APP的某些部分。对于某些类型的应用,NDK可以帮助你使用C/C++重写代码库。
与NDK密切相关的另一个词汇则是JNI,它是NDK开发中的枢纽,Java与C/C++层交互基本上就是是通过它来完成的,那么什么是JNI?
JNI:Java Native Interface 也就是java本地接口,它是一个协议,这个协议用来沟通java代码和本地代码(c/c++)。通过这个协议,Java类的某些方法可以使用原生实现,同时让它们可以像普通的Java方法一样被调用和使用,而原生方法也可以使用Java对象,调用和使用Java方法。也就是说,使用JNI这种协议可以实现:java代码调用c/c++代码,而c/c++代码也可以调用java代码。
环境准备
1、Android Studio
2、Android SDK
3、Android NDK
使用AS创建好一个Project后,需要注意几个地方的配置:
1)local.propertites 添加ndk目录
2) gradle.propertites 添加ndk的支持
代码编写步骤
第一步 (创建一个Java类)
public class MyFirstJniTest {
// native关键字 即表示该方法为本地方法 是C/C++实现的
public static native String getString();
public static native int add(int a, int b);
}
第二步 (命令行进入到该类的目录下,输入 javac MyFirstJniTest.java)
例如下:
此时,我们可以看到在你的MyFirstJniTest包下 多了个.class文件,如下
第三步(回到代码的Java文件加下,输入命令 javah -jni com.example.androidqunyinhui.jni.MyFirstJniTest)
输入完命令,则会生成com_example_androidqunyinhui_jni_MyFirstJniTest.h文件;
在main文件夹下创建一个jni文件夹,然后将该.h文件剪贴到jni文件夹下,具体如下:
此处的MyFirstJniTest.c文件是接下来的步骤中会创建的文件。
我们大致看下com_example_androidqunyinhui_jni_MyFirstJniTest.h文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_androidqunyinhui_jni_MyFirstJniTest */
#ifndef _Included_com_example_androidqunyinhui_jni_MyFirstJniTest
#define _Included_com_example_androidqunyinhui_jni_MyFirstJniTest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_androidqunyinhui_jni_MyFirstJniTest
* Method: getString
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_androidqunyinhui_jni_MyFirstJniTest_getString
(JNIEnv *, jclass);
/*
* Class: com_example_androidqunyinhui_jni_MyFirstJniTest
* Method: add
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_example_androidqunyinhui_jni_MyFirstJniTest_add
(JNIEnv *, jclass, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
可以发现声明得有两个函数,XXX_getString 和 XXX_add, 这两个函数的具体实现,我们将在.c文件中完成。
第四步 (编写实现代码 MyFirstJniTest)
// 包含头文件
#include <com_example_androidqunyinhui_jni_MyFirstJniTest.h>
//返回一个字符串
JNIEXPORT jstring JNICALL Java_com_example_androidqunyinhui_jni_MyFirstJniTest_getString
(JNIEnv *env, jclass jobj){
return (*env)->NewStringUTF(env,"MyFirstJniTest 我是用jni调用出来的字符串");
}
//返回 a+b的结果
JNIEXPORT jint JNICALL Java_com_example_androidqunyinhui_jni_MyFirstJniTest_add
(JNIEnv *env, jclass jobj, jint a, jint b){
return a+b;
}
第五步 (修改app 下的 build.gradle 中的配置)
defaultConfig {
applicationId "com.example.androidqunyinhui"
minSdkVersion 16
targetSdkVersion 24
versionCode 1
versionName "1.0"
multiDexEnabled true
// 此处为ndk添加的配置
ndk {
moduleName "MyFirstJinTest"//指定生成的so文件名
abiFilters "armeabi-v7a", "x86"//cpu的类型
}
}
第六步 (rebuild project 工程文件)
rebuild 整个工程文件,我们可以在build文件夹下看到对应的so包,具体如下:
第七步(Java层的使用)
public class JniTestActivity extends AppCompatActivity {
public static void startActivity(Context context){
Intent intent = new Intent(context, JniTestActivity.class);
context.startActivity(intent);
}
static {
//名字必须和build.gradle中的moduleName一致
System.loadLibrary("MyFirstJinTest");
}
private TextView tvShowInfo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_jni_test);
initView();
}
private void initView(){
tvShowInfo = (TextView) findViewById(R.id.tv_show_info);
findViewById(R.id.btn_show_info).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String text = MyFirstJniTest.getString();
int sum = MyFirstJniTest.add(1, 2);
tvShowInfo.setText(text+" "+sum);
}
});
}
}
具体显示如下:
通过以上七个步骤, 基本上完成了 Java层native方法-->jni层-->native层代码编写及调用关系,基本上展现了NDK开发的所有步骤流程。
参考文献
https://www.cnblogs.com/guanmanman/p/6769240.html
https://blog.csdn.net/u011652925/article/details/78272406