跳至主要內容

JNI

LincZero大约 2 分钟

JNI

目录

参考:

  • https://www.bilibili.com/video/BV188411V7Yq(1h快速入门版,选)
  • https://www.bilibili.com/video/BV1qW411L7oY(10h详细版)
  • JNI最新在线API:https://docs/oracle.com/javase/8/docs/technotes/guides/jni/spec/jniTOC.html

JNI入门

环境准备

  1. AndroidStudio环境准备:4.2版本 (2021 04 29 Build),小蜜蜂最新版本可能有问题。JDK 1.8
  2. 创建NDK工程
    • new Peoject > Native C++
    • SDK API 16: Android 4.1
  3. 运行

JNI介绍

如何沟通Java与C/C++

  • 上层 Kotlin Java
  • 中间件 JNI
  • 下层 C/C++

为什么要有JNI?

  • 实际使用中,Java需要与本地代码进行交互

JNI与NDK的关系

  • 先有JNI才有NDK,JNI是Java的东西,JNI在1996的时候就有了,而NDK是Android的东西,200X左右才有Android
  • 那为什么NDK里面有JNI呢?jni.h 的的JDK版本和NDK版本是不一样的:
    • NDK版本:D:/Android/Sdk/ndk/21.0.6113669/toolchains/llvm/prebuilt/windows-x86_64/sysroot/usr/include/jni.h (将JDK的JNI再次进行了封装,NDK包括gcc g++ 工具链 JNI 等一堆东西)
    • JDK版本:C:/Program Files/Java/jdk1.8.0_131/include/jni.h

常用规则如下:

java类型——属性类型符号

  • boolean, Z
  • byte, B
  • char, C
  • short, S
  • int, I
  • long, J
  • float, F
  • double, D
  • void, V
  • object, L完整类名
  • array[数组的数据类型, int [] […………
  • mehtod(参数类型)返回直类型, void name (int a, double b) (ID) V

实战

< MainActivity.java

public class MainActivity extends AppCompatActivity {
    static {
        System.loadLibrary("native-lib");
    }
    
    private ActivityMainBinding binding;
    
    private String name = "Derry";
    
    public native String stringFromJNI(); // (原生函数,cpp进行实现) 
    public native void changeName(); // (原生函数,cpp进行实现) 改变我们的属性name
    
    @Override
    protected void onCreate(Bundle saveInstanceState) {
        super.onCreate(savedInstanceState);
        
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        serContentView(binding.getRoot());
        
        TextView tv = binding.sampleText;
        tv.serText(stringFromJNI());
        
        System.out.prinln("name修改前是:"+name);
        changName();
        System.out.prinln("name修改后是:"+name);
    }
}

< native-lib.cpp

#include <jni.h>
#incldue <string>

extern "C" JNIEXPORT jstring JNICALL
MainActivity.stringFromJIN(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from Cpp";
    return env->NewStringUTF(hello.c_str());
}

/**
 * @param env JNI环境,核心,桥梁
 */
extern "C" // 下面的代码,重用C的编译方式。为什么要这样,后面专门讲JNIEnv源码
JNIEXPORT void JNICALL
Java_com_derry_as_1jni_1project_MainActivity_changeName(JNIEnv* env, jobject this) {
    
}

jni.h 源码

< jni.h

// < 139 line
// 无论Cpp还是C,都是要访问 JNINativeInterface 这个C结构体的
#if defined(__cplusplus) // C++
typedef _JNIEnv JNIEnv;
typedef _JavaVM JavaVM;
#else // C
typedef const struct JNINativeInterface* JNIEnv;
typedef const struct JNINativeInterface* JavaVM;
#endif

// < 490 line
struct _JNIEnv {
    const struct JNINativeInterface* functions; // 这里又是个结构体,见下
    ...
}

// < 150 line
// 核心,只要将里面的300多个函数学完,就基本会了
struct JNINativeInterface {
    ...
}