[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相互调用


相关文章
|
前端开发 Java 编译器
当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
483 36
当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
|
Java Android开发 C++
🚀Android NDK开发实战!Java与C++混合编程,打造极致性能体验!📊
在Android应用开发中,追求卓越性能是不变的主题。本文介绍如何利用Android NDK(Native Development Kit)结合Java与C++进行混合编程,提升应用性能。从环境搭建到JNI接口设计,再到实战示例,全面展示NDK的优势与应用技巧,助你打造高性能应用。通过具体案例,如计算斐波那契数列,详细讲解Java与C++的协作流程,帮助开发者掌握NDK开发精髓,实现高效计算与硬件交互。
663 1
|
安全 Java API
【性能与安全的双重飞跃】JDK 22外部函数与内存API:JNI的继任者,引领Java新潮流!
【9月更文挑战第7天】JDK 22外部函数与内存API的发布,标志着Java在性能与安全性方面实现了双重飞跃。作为JNI的继任者,这一新特性不仅简化了Java与本地代码的交互过程,还提升了程序的性能和安全性。我们有理由相信,在外部函数与内存API的引领下,Java将开启一个全新的编程时代,为开发者们带来更加高效、更加安全的编程体验。让我们共同期待Java在未来的辉煌成就!
387 11
|
安全 Java API
【本地与Java无缝对接】JDK 22外部函数和内存API:JNI终结者,性能与安全双提升!
【9月更文挑战第6天】JDK 22的外部函数和内存API无疑是Java编程语言发展史上的一个重要里程碑。它不仅解决了JNI的诸多局限和挑战,还为Java与本地代码的互操作提供了更加高效、安全和简洁的解决方案。随着FFM API的逐渐成熟和完善,我们有理由相信,Java将在更多领域展现出其强大的生命力和竞争力。让我们共同期待Java编程新纪元的到来!
810 11
|
IDE Java Linux
探索安卓开发:从基础到进阶的旅程Java中的异常处理:从基础到高级
【8月更文挑战第30天】在这个数字时代,移动应用已经成为我们日常生活中不可或缺的一部分。安卓系统由于其开放性和灵活性,成为了开发者的首选平台之一。本文将带领读者踏上一段从零开始的安卓开发之旅,通过深入浅出的方式介绍安卓开发的基础知识、核心概念以及进阶技巧。我们将一起构建一个简单的安卓应用,并探讨如何优化代码以提高性能和应用的用户体验。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供宝贵的知识和启发。
|
存储 搜索推荐 Java
探索安卓开发中的自定义视图:打造个性化UI组件Java中的异常处理:从基础到高级
【8月更文挑战第29天】在安卓应用的海洋中,一个独特的用户界面(UI)能让应用脱颖而出。自定义视图是实现这一目标的强大工具。本文将通过一个简单的自定义计数器视图示例,展示如何从零开始创建一个具有独特风格和功能的安卓UI组件,并讨论在此过程中涉及的设计原则、性能优化和兼容性问题。准备好让你的应用与众不同了吗?让我们开始吧!
|
Java Android开发 C++
Android Studio JNI 使用模板:c/cpp源文件的集成编译,快速上手
本文提供了一个Android Studio中JNI使用的模板,包括创建C/C++源文件、编辑CMakeLists.txt、编写JNI接口代码、配置build.gradle以及编译生成.so库的详细步骤,以帮助开发者快速上手Android平台的JNI开发和编译过程。
1363 1
|
Java 调度 Android开发
Android经典实战之Kotlin的delay函数和Java中的Thread.sleep有什么不同?
本文介绍了 Kotlin 中的 `delay` 函数与 Java 中 `Thread.sleep` 方法的区别。两者均可暂停代码执行,但 `delay` 适用于协程,非阻塞且高效;`Thread.sleep` 则阻塞当前线程。理解这些差异有助于提高程序效率与可读性。
443 1
|
开发框架 Java Android开发
JNI中调用Java函数
JNI中调用Java函数
242 0
|
开发框架 Java Android开发
JNI中调用Java函数
JNI中调用Java函数
303 0