NDK相关的博客
1,什么是JNI
java native interface(java本地/原生接口)
JNI是一种标准,c/c++和java相互调用的标准
NDK就是基于这个 标准开发的
优点:可以利用大部分c/c++的语言库库,可以跨平台去移植代码,提升运算效率;
缺点:限制了部分java跨平台的能力,java跨平台的能力是jvm(java虚拟机),因为jni是脱离了jvm运行
2,JNI c/c++动态库
windows:.dll
Linux :.so(注:android的内核就是Linux)
Mac OSx:.jnilib
3,新建一个包含ndk的项目,我们发现它比普通项目增加了两个文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XIWQyfrw-1658988783800)(https://img-blog.csdn.net/20180207145051551?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcWN6Z193eGc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)]
看下相关的类
package com.example.acer.test_02_06;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
// 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);
TextView tv = (TextView) 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();
}
JNIEnv类型实际上代表了Java环境,通过这个JNIEnv* 指针,就可以对Java端的代码进行操作。例如,创建Java类中的对象,调用Java对象的方法,获取Java对象中的属性等等。JNIEnv的指针会被JNI传入到本地方法的实现函数中来对Java端的代码进行操作。
JNIEnv类中有很多函数可以用:
NewObject:创建Java类中的对象
NewString:创建Java类中的String对象
NewArray:创建类型为Type的数组对象
GetField:获取类型为Type的字段
SetField:设置类型为Type的字段的值
GetStaticField:获取类型为Type的static的字段
SetStaticField:设置类型为Type的static的字段的值
CallMethod:调用返回类型为Type的方法
CallStaticMethod:调用返回值类型为Type的static方法
等许多的函数,具体的可以查看jni.h文件中的函数名称。
#include <jni.h>//引入jni的头文件
#include <string>
//允许以后的函数被编译为c的模式
extern "C"
/**
* 1,JNIEXPORT:允许该函数被java调用,这里是固定写法
* 2,jstring:返回值类型
* 3,JNICALL:jni约束函数入栈顺序和堆栈内存清理的规则
* 4,Java_com_example_acer_test_102_106_MainActivity_stringFromJNI:
方法名,java+项目具体的包名+类名+native方法名
* 5,JNIEnv:java native interface environment Jave本地接口环境
在C中:JNIEnv 指针类型
JNIEnv* env (*env)->方法名(env,参数列表)
javaVM* vm (*vm)->方法名(vm,参数列表)
在C++中:JNIEnv 结构体类型
JNIEnv* env env->方法名(参数列表)
javaVM* vm vm->方法名(参数列表)
*/
JNIEXPORT jstring JNICALL
Java_com_example_acer_test_102_106_MainActivity_stringFromJNI(
JNIEnv *env,
//1-native方法不是静态的时候,jobject对应的是java中对应的对象(调用此
//方法的对象)
//2-native方法是静态方法,jobject对应的是调用此方法的class对象(当前类的类对象)
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
4,JNI基本数据类型和引用类型
在 JNI 开发中,我们知道,Java 的数据类型并不是直接在 JNI 里使用的,例如 int 就是使用 jint 来表示。那么,就如我们来认识一下这些数据类型吧。
Java数据类型通过JNI数据类型调用C/C++数据类型
基本数据类型
引用数据类型
c/c++类型 JNI类型 解释
uint8_t jboolean; /* unsigned 8 bits */
int8_t jbyte; /* signed 8 bits */
uint16_t jchar; /* unsigned 16 bits *
int16_t jshort; /* signed 16 bits */
int32_t jint; /* signed 32 bits */
int64_t jlong; /* signed 64 bits */
float jfloat; /* 32-bit IEEE 754 */
double jdouble; /* 64-bit IEEE 754 */
jobject; 任何java对象,包括没有对应的java类的对象
jclass; Class 对象
jstring; 字符串类对象
jarray; 对应任何数组
5,在JVM虚拟机中,存储数据类型的名称时,是使用指定的描述符来存储,而不是我们习惯的 int,float 等。
c/c++代码调用Java类 对象的属性(类对象的成员)
java类型 属性类型符号(成员类型符号)
boolean Z
byte B
char C
short S
int I
long J
float F
double D
void V
object L完整类名(如String就应写为:Ljava/lang/String;);
array [arry-type [数组类型
method (参数类型)返回类型
在MainActivity类中声明int a 成员变量,在c++中为其赋值,我们看下代码中怎么实现
(补充: jstring NewStringUTF(const char* bytes),以 UTF-8 的编码方式创建一个 Java 的字符串。bytes:指向字符数组的指针)
JNIEXPORT jstring JNICALL
Java_com_example_acer_test_102_106_MainActivity_stringFromJNI(
JNIEnv *env,
jobject jobject1/* this */) {
jclass jcl=env->GetObjectClass(jobject1);
jfieldID jid=env->GetFieldID(jcl,"a","I");
jint a=45;
env->SetIntField(jobject1,jid,45);
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
如果把MainActivity中的a改为String类型,我们看下如何修改值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JHyXIuyz-1658988783803)(https://img-blog.csdn.net/20180207180357283?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcWN6Z193eGc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)]
补充:
c/c++可以直接调硬件,Java需要调用c/c++;
java和c/c++在同一个进程。两个语音不同,Java调用c/c++,需要传参,比如JavaString对象,这时候需要将Java的内存对象转换为C/C++内存对象,这就是jni。NDK是工具集,
#include <jni.h>
#include <string>
extern "C"//表示兼容C,会把代码放到C中,使用gcc进行编译。不加这个代码就是c++代码,会交给g++编译
//c不支持重载,c++支持。c++编译后函数会增加参数名字,这个时候Java会找不到编译后的函数,会报错。
JNIEXPORT //宏(__attribute__ ((visibility ("default")))),代表访问权限.有两个取值,default与hidden
jstring //返回值
JNICALL //提醒你这是个jni函数,可以去掉
Java_com_example_ctest0728_MainActivity_stringFromJNI//静态注入,函数名,根据生命的Java native方法生成的,Java+包名+类名+方法名
(
JNIEnv* env,//工具类,提供了很多转换方法
jobject /* this */,
jstring data
) {
const char* dataC =env->GetStringUTFChars(data,0);//0表示不需要复制
env->ReleaseStringChars(data, reinterpret_cast<const jchar *>(dataC));//释放
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());//hello.c_str()转化为指针数组,C++字符串是对象但C没有对象,c里面的字符串就是指针数组
}