[Android JNI] --- 静态注册和动态注册实现java和native相互调用

简介: [Android JNI] --- 静态注册和动态注册实现java和native相互调用

1 静态注册的方式实现c/c++和java相互调用

C/C++中访问Java方法

C/C++中访问Java父类的方法

C/C++中访问/修改Java变量

Java中访问C/C++方法

Java中访问/修改C/C++变量

给出实现代码如下:

// StaticReg.java

package com.android.javacpp;
import android.util.Log;
public class StaticReg {
    private String  TAG = "JC_StaticReg";
    private String TestString = "1234";
    private int TestInt = 1234;
    // java access c++
    public native String geJNIString();
    public native int getJNIInt(Object obj);
    public native void passStringToJNI(String str);
    // 用于调用 C++ 方法
    public native int callJNIAdd(int a, int b);
    // c++ access java
    public native void setJavaString();
    public native void setJavaInt();
    public native int callJavaMethodAdd();
    public int Add(int a, int b) {
        return a + b;
    }
    public void StaticRegTest()
    {
        Log.d(TAG, "geJNIString: " + geJNIString());
        Log.d(TAG, "getJNIInt: " + getJNIInt(this));
        passStringToJNI("12345678");
        int result = callJNIAdd(999, 999);
        Log.d(TAG, "callNativeAdd: " +  result);
        // c++ access java
        Log.d(TAG, "before modif TestString: " + TestString);
        setJavaString();
        Log.d(TAG, "after modif TestString: " + TestString);
        Log.d(TAG, "before modif TestInt: " + TestInt);
        setJavaInt();
        Log.d(TAG, "after modif TestInt: " + TestInt);
        int result2 = callJavaMethodAdd();
        Log.d(TAG, "callJavaMethodAdd: " +  result2);
    }
}

StaticReg.cpp

#include <jni.h>
#include <string>
#include "log.h"
#include "DynamicReg.h"
extern "C"
JNIEXPORT jstring JNICALL
Java_com_android_javacpp_StaticReg_geJNIString(JNIEnv *env, jobject thiz) {
    // TODO: implement geJNIString()
    return env->NewStringUTF("the string from C++");
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_android_javacpp_StaticReg_getJNIInt(JNIEnv *env, jobject thiz, jobject obj) {
    // TODO: implement getJNIInt()
    jint inttest = 999;
    return inttest;
}
extern "C"
JNIEXPORT void JNICALL
Java_com_android_javacpp_StaticReg_passStringToJNI(JNIEnv *env, jobject thiz, jstring str) {
    // TODO: implement passStringToJNI()
    const char* utfChars = env->GetStringUTFChars(str, nullptr);
    std::string strtest = utfChars;
    LOGD("string from java: %s", strtest.c_str());
    env->ReleaseStringUTFChars(str, utfChars);
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_android_javacpp_StaticReg_callJNIAdd(JNIEnv *env, jobject thiz, jint a, jint b) {
    // TODO: implement callJNIAdd()
    return a + b;
}
extern "C"
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
    JNIEnv *env = NULL;
    if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        return JNI_ERR;
    }
    jint result = DynamicReg::GetInstance().RegisterNatives(env);
    LOGD("RegisterNatives result: %d", result);
    return JNI_VERSION_1_6;
}
// c++ access java method/var
extern "C"
JNIEXPORT void JNICALL
Java_com_android_javacpp_StaticReg_setJavaString(JNIEnv *env, jobject thiz) {
    // TODO: implement setJavaString()
    jclass activityClass=env->GetObjectClass(thiz);
//    获取java层的text属性
    jfieldID idText = env->GetFieldID(activityClass, "TestString", "Ljava/lang/String;");
    //给text属性赋值
    jstring text1 = env->NewStringUTF("5678");
    env->SetObjectField(thiz, idText, text1);
//    通过jobject参数获取MainActivity对应的class对象在Native层的映射jclass 对象
//    通过jclass 对象得到text属性的id
//    通过text属性id去修改text的值
}
extern "C"
JNIEXPORT void JNICALL
Java_com_android_javacpp_StaticReg_setJavaInt(JNIEnv *env, jobject thiz) {
    // TODO: implement setJavaInt()
    jclass activityClass=env->GetObjectClass(thiz);
    //  获取java层的text属性
    jfieldID idText = env->GetFieldID(activityClass, "TestInt", "I");
    //给text属性赋值
    jint text1 = 5678;
    env->SetIntField(thiz, idText, text1);
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_android_javacpp_StaticReg_callJavaMethodAdd(JNIEnv *env, jobject thiz) {
    // TODO: implement callJavaMethodAdd()
    // 获取 MainActivity 类的引用
    jclass clazz = env->FindClass("com/android/javacpp/StaticReg");
    if (clazz == nullptr) {
        return -1;
    }
    // 获取 MainActivity 实例的引用
    jobject activityObj = env->NewObject(clazz, env->GetMethodID(clazz, "<init>", "()V"));
    if (activityObj == nullptr) {
        return -1;
    }
    // 调用 MainActivity 中的 add 方法
    jmethodID addMethodId = env->GetMethodID(clazz, "Add", "(II)I");
    if (addMethodId == nullptr) {
        return -1;
    }
    return env->CallIntMethod(activityObj, addMethodId, 100, 20);
}

2 动态注册的方式实现c/c++调用java的方法/变量

C/C++中访问Java方法

C/C++中访问Java父类的方法

C/C++中访问/修改Java变量

Java中访问C/C++方法

Java中访问/修改C/C++变量

// DynamicReg.java

package com.android.javacpp;
import android.util.Log;
public class DynamicReg {
    private String  TAG = "JC_DynamicReg";
    public native String stringFromJNI();
    public static native int add(int a, int b);
    public int JavaInt = 10;
    public void JavaMethod() {
//        System.out.println("Hello from Java!");
        Log.d(TAG, "Java print hello world");
    }
    public native void JNIMethod();
    public void DynamicRegTest()
    {
        Log.d(TAG, "stringFromJNI: " + stringFromJNI());
        Log.d(TAG, "add (100, 500) " + add(100,500));
        Log.d(TAG, "JNIMehod called");
        JNIMethod();
    }
}

// DynamicReg.cpp

//
// Created by Administrator on 2023/7/6.
//
#include "DynamicReg.h"
std::string DynamicReg::myString = "Hello from c++";
jstring DynamicReg::stringFromJNI(JNIEnv *env, jobject instance) {
    jint version = env->GetVersion();
    LOGD("JNI version is : %x", version);
    return env->NewStringUTF(myString.c_str());
}
jint DynamicReg::JNIadd(JNIEnv *env, jclass clazz, jint a, jint b) {
    return a + b;
}
jint DynamicReg::RegisterNatives(JNIEnv *env) {
    jclass clazz = env->FindClass("com/android/javacpp/DynamicReg");
    if (clazz == NULL) {
        LOGE("could't find class: com/android/javacpp/DynamicReg");
        return JNI_ERR;
    }
    JNINativeMethod methods_MainActivity[] = {
            {"stringFromJNI", "()Ljava/lang/String;", (void *) stringFromJNI},
            {"add",           "(II)I",                (void *) JNIadd},
            {"JNIMethod", "()V", (void*) JNIMethod}
    };
    // int len = sizeof(methods_MainActivity) / sizeof(methods_MainActivity[0]);
    return env->RegisterNatives(clazz, methods_MainActivity,
                                sizeof(methods_MainActivity) / sizeof(methods_MainActivity[0]));
}
jint DynamicReg::JNI_OnLoad(JavaVM *vm, void *reserved) {
    JNIEnv *env = NULL;
    if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        LOGE("JNI_ERR");
        return JNI_ERR;
    }
    jint result = RegisterNatives(env);
    LOGD("RegisterNatives result: %x", result);
    return JNI_VERSION_1_6;
}
DynamicReg& DynamicReg::GetInstance()
{
    static DynamicReg instance;
    return instance;
}
void DynamicReg::JNIMethod(JNIEnv *env, jobject obj)
{
    // 访问Java层的变量
    jfieldID fieldId = env->GetFieldID(env->GetObjectClass(obj), "JavaInt", "I");
    jint myInt = env->GetIntField(obj, fieldId);
    printf("myInt = %d\n", myInt);
    LOGD("C++ get JavaInt = %d\n", myInt);
    // 调用Java层的方法
    jmethodID methodId = env->GetMethodID(env->GetObjectClass(obj), "JavaMethod", "()V");
    env->CallVoidMethod(obj, methodId);
}

完整示例代码下载

JNI实现java cpp相互调用


相关文章
|
4月前
|
Java Android开发 C++
Android Studio JNI 使用模板:c/cpp源文件的集成编译,快速上手
本文提供了一个Android Studio中JNI使用的模板,包括创建C/C++源文件、编辑CMakeLists.txt、编写JNI接口代码、配置build.gradle以及编译生成.so库的详细步骤,以帮助开发者快速上手Android平台的JNI开发和编译过程。
330 1
|
3月前
|
Java Android开发 C++
🚀Android NDK开发实战!Java与C++混合编程,打造极致性能体验!📊
在Android应用开发中,追求卓越性能是不变的主题。本文介绍如何利用Android NDK(Native Development Kit)结合Java与C++进行混合编程,提升应用性能。从环境搭建到JNI接口设计,再到实战示例,全面展示NDK的优势与应用技巧,助你打造高性能应用。通过具体案例,如计算斐波那契数列,详细讲解Java与C++的协作流程,帮助开发者掌握NDK开发精髓,实现高效计算与硬件交互。
166 1
|
3月前
|
安全 Java API
【性能与安全的双重飞跃】JDK 22外部函数与内存API:JNI的继任者,引领Java新潮流!
【9月更文挑战第7天】JDK 22外部函数与内存API的发布,标志着Java在性能与安全性方面实现了双重飞跃。作为JNI的继任者,这一新特性不仅简化了Java与本地代码的交互过程,还提升了程序的性能和安全性。我们有理由相信,在外部函数与内存API的引领下,Java将开启一个全新的编程时代,为开发者们带来更加高效、更加安全的编程体验。让我们共同期待Java在未来的辉煌成就!
72 11
|
3月前
|
安全 Java API
【本地与Java无缝对接】JDK 22外部函数和内存API:JNI终结者,性能与安全双提升!
【9月更文挑战第6天】JDK 22的外部函数和内存API无疑是Java编程语言发展史上的一个重要里程碑。它不仅解决了JNI的诸多局限和挑战,还为Java与本地代码的互操作提供了更加高效、安全和简洁的解决方案。随着FFM API的逐渐成熟和完善,我们有理由相信,Java将在更多领域展现出其强大的生命力和竞争力。让我们共同期待Java编程新纪元的到来!
117 11
|
4月前
|
Java 调度 Android开发
Android经典实战之Kotlin的delay函数和Java中的Thread.sleep有什么不同?
本文介绍了 Kotlin 中的 `delay` 函数与 Java 中 `Thread.sleep` 方法的区别。两者均可暂停代码执行,但 `delay` 适用于协程,非阻塞且高效;`Thread.sleep` 则阻塞当前线程。理解这些差异有助于提高程序效率与可读性。
85 1
|
4月前
|
Android开发
Cannot create android app from an archive...containing both DEX and Java-bytecode content
Cannot create android app from an archive...containing both DEX and Java-bytecode content
44 2
|
4月前
|
开发框架 Java Android开发
JNI中调用Java函数
JNI中调用Java函数
30 0
|
4月前
|
开发框架 Java Android开发
JNI中调用Java函数
JNI中调用Java函数
37 0
|
Java Android开发 索引
Android插件化开发基础之Java反射机制研究(2)
Android插件化开发基础之Java反射机制研究(2)
138 0
|
6天前
|
安全 Java API
java如何请求接口然后终止某个线程
通过本文的介绍,您应该能够理解如何在Java中请求接口并根据返回结果终止某个线程。合理使用标志位或 `interrupt`方法可以确保线程的安全终止,而处理好网络请求中的各种异常情况,可以提高程序的稳定性和可靠性。
37 6
下一篇
DataWorks