Leo Technology Stack Leo Technology Stack
首页
  • Android
  • Web
  • SpringBoot
  • 数据库
  • Docker
  • Netty
  • KubeSphere
  • Linux
  • Android Framework
  • 开源库
思维
  • 面试
  • 投资理财
  • 杂事记录
  • 索引

    • 分类
    • 标签
    • 归档
  • 开源项目

    • Advance Markdown
    • AnLibrary (opens new window)

Leo

不知名的架构师
首页
  • Android
  • Web
  • SpringBoot
  • 数据库
  • Docker
  • Netty
  • KubeSphere
  • Linux
  • Android Framework
  • 开源库
思维
  • 面试
  • 投资理财
  • 杂事记录
  • 索引

    • 分类
    • 标签
    • 归档
  • 开源项目

    • Advance Markdown
    • AnLibrary (opens new window)
  • NDK详解

    • Android NDK 开发
      • 基础介绍
      • Java调用C
      • C调用Java
      • 三方工具
  • notes
  • 前端
  • Android
Leo
2022-04-27

NDK详解

# Android NDK 开发

# 基础介绍

# 静态注册C/C++函数

  • 函数命名规则

    Java_包名_类名_函数名

    JNIEXPORT void JNICALL
    Java_com_top_demo_helloCpp(JNIEnv* env, jobject obj)
    {
    
    }
    
    1
    2
    3
    4
    5
    • 上面的JNIEXPORT和JNICALL是JNI的宏,用来标识该函数可以被JNI调用。
    • JNIEnv结构体指向了JNI的函数表,这些函数可以完成和Java的交互。
    • jobject是当前与之链接的native方法隶属的类对象,即调用这个JNI方法的对象。
    • 上面这两个参数由Java虚拟机调用的时候传入。

# 动态注册C/C++函数

  • 由于是将函数映射表注册到JVM中,所以函数的调用速度更快。

  • 不用使用静态注册那套繁琐的命名规则。

  • 注册

//编写需要使用的函数
static jstring nativeJNITest(JNIEnv *env, jobject) 
{
    std::string test = "你好,c++";
    return env->NewStringUTF(test.c_str());
}

static jint nativeComputeDamage(JNIEnv *env, jobject thiz, jint attack, jint agility)
{
    return (jint)(attack + agility * 1.2)
}

// 提供一个函数映射表,注册给JVM,这样JVM就可以通过函数映射表来调用相应的函数
// 这样的效率比静态注册的效率高
/**
 * @param1 Java中的native方法名。可以自定义。
 * @param2 函数签名,描述函数的返回值和参数
 * @param3 函数指针,指向被调用的c++函数。名车需要和函数名一样。
 */
static JNINativeMethod nativeMethod[] = {
    {"JNITest", "()Ljava/lang/String;", (void *) nativeJNITest},
    {"computeDamage", "(II)I", (void *)nativeComputeDamage}
};


//该函数在执行System.loadLibrary()后会被调用,用于向JVM注册函数表。
//返回值是使用的JNI版本。
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved)
{
    JNIEnv *env;
    //需要通过JVM动态的获取JNIEnv来提供Java介质
    if (jvm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        return JNI_ERR;
    }
    
    //需要调用这些函数的类
    //一定要注意名称的正确性:包名 + 类名
    jclass clz = env->FindClass("com/example/xingxinyu/cppdemo/JNIHelper");
    if(clz == NULL){
        LOGE("类名不对");
    } else {
        LOGE("类加载成功");
    }
    
    jint method_size = sizeof(nativeMethod) / sizeof(nativeMethod[0]);
   /**
     * 注册函数表
     * @param1 需要关联到那个【Java】类,Kotlin类不行
     * @param2 方法数组
     * @param3 方法数
     */
    env->RegisterNatives(clz, nativeMethod, method_size);
    //返回使用的JNI版本                               
    return JNI_VERSION_1_6;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
  • 解注册
    向JVM中注册函数映射表后,因该在JVM释放改JNI组件时把其释放,不然就是隐患。
//该函数在执行System.loadLibrary()后会被调用,用于向JVM注册函数表。
//返回值是使用的JNI版本。
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *jvm, void *reserved)
{
    JNIEnv *env;
    //需要通过JVM动态的获取JNIEnv来提供Java介质
    if (jvm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        return;
    }
    jclass clz = env->FindClass("com/example/xingxinyu/cppdemo/JNIHelper");
    // 解注册函数表
    env->UnregisterNatives(clz);
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# JNI描述符

前面在动态注册时,需要生成函数映射表,其中需要一个是函数签名,它是由JNI描述符来描述的,写错了函数就会找不到。

Java JNI
byte B
char C
short S
int I
long J
float F
double D
boolean Z
  • 引用类型描述符
  • 数组描述符
  • 方法描述符

# JNI数据类型

普遍规律:在普通数据类型前+j,比如: jobject对应Java的obejct

  • 基本数据类型
Java Type Native Type Description
boolean jboolean unsigned 8 bits
byte jbyte signed 8 bits
char jchar unsigned 16 bits
short jshort signed 16 bits
int jint signed 32 bits
long jlong signed 64 bit
float jfloat 32 bit
double jdouble 64 bit
  • 引用类型
jobject                             (all objects)
    |
    |--jclass                       (java.lang.Class instances)
    |--jstring
    |--jarray                       (arrays)
    |     |
    |     |--jobjectArray           (Object[])
    |     |--jboolArray             (boolean[])
    |     |--jbyteArray             (byte[])
    |     |--jcharArray             (char[])
    |     |--jshortArray            (short[])
    |     |--jintArray              (int[])
    |     |--jlongArray             (long[])
    |     |--jfloatArray            (float[])
    |     |--jdoubleArray           (double[])
    |--jthrowable                   (java.lang.Throwable objects)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# Java调用C

# C调用Java

# 三方工具

编辑此页 (opens new window)
#Android
上次更新: 2022-04-28, 11:21:32
Theme by Leo | Copyright © 2016-2022 Leo | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式