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


相关文章
|
2月前
|
Java Android开发 C++
Android Studio JNI 使用模板:c/cpp源文件的集成编译,快速上手
本文提供了一个Android Studio中JNI使用的模板,包括创建C/C++源文件、编辑CMakeLists.txt、编写JNI接口代码、配置build.gradle以及编译生成.so库的详细步骤,以帮助开发者快速上手Android平台的JNI开发和编译过程。
109 1
|
1天前
|
XML Java 数据库
安卓项目:app注册/登录界面设计
本文介绍了如何设计一个Android应用的注册/登录界面,包括布局文件的创建、登录和注册逻辑的实现,以及运行效果的展示。
11 0
安卓项目:app注册/登录界面设计
|
22天前
|
Java Android开发 C++
🚀Android NDK开发实战!Java与C++混合编程,打造极致性能体验!📊
在Android应用开发中,追求卓越性能是不变的主题。本文介绍如何利用Android NDK(Native Development Kit)结合Java与C++进行混合编程,提升应用性能。从环境搭建到JNI接口设计,再到实战示例,全面展示NDK的优势与应用技巧,助你打造高性能应用。通过具体案例,如计算斐波那契数列,详细讲解Java与C++的协作流程,帮助开发者掌握NDK开发精髓,实现高效计算与硬件交互。
64 1
|
2月前
|
存储 搜索推荐 Java
探索安卓开发中的自定义视图:打造个性化UI组件Java中的异常处理:从基础到高级
【8月更文挑战第29天】在安卓应用的海洋中,一个独特的用户界面(UI)能让应用脱颖而出。自定义视图是实现这一目标的强大工具。本文将通过一个简单的自定义计数器视图示例,展示如何从零开始创建一个具有独特风格和功能的安卓UI组件,并讨论在此过程中涉及的设计原则、性能优化和兼容性问题。准备好让你的应用与众不同了吗?让我们开始吧!
|
2月前
|
Java 调度 Android开发
Android经典实战之Kotlin的delay函数和Java中的Thread.sleep有什么不同?
本文介绍了 Kotlin 中的 `delay` 函数与 Java 中 `Thread.sleep` 方法的区别。两者均可暂停代码执行,但 `delay` 适用于协程,非阻塞且高效;`Thread.sleep` 则阻塞当前线程。理解这些差异有助于提高程序效率与可读性。
52 1
|
2月前
|
Java Android开发
解决Android编译报错:Unable to make field private final java.lang.String java.io.File.path accessible
解决Android编译报错:Unable to make field private final java.lang.String java.io.File.path accessible
194 1
|
2月前
|
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
24 2
|
2月前
|
IDE Java Linux
探索安卓开发:从基础到进阶的旅程Java中的异常处理:从基础到高级
【8月更文挑战第30天】在这个数字时代,移动应用已经成为我们日常生活中不可或缺的一部分。安卓系统由于其开放性和灵活性,成为了开发者的首选平台之一。本文将带领读者踏上一段从零开始的安卓开发之旅,通过深入浅出的方式介绍安卓开发的基础知识、核心概念以及进阶技巧。我们将一起构建一个简单的安卓应用,并探讨如何优化代码以提高性能和应用的用户体验。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供宝贵的知识和启发。
|
3月前
|
Java Android开发 C++
🚀Android NDK开发实战!Java与C++混合编程,打造极致性能体验!📊
【7月更文挑战第28天】在 Android 开发中, NDK 让 Java 与 C++ 混合编程成为可能, 从而提升应用性能。**为何选 NDK?** C++ 在执行效率与内存管理上优于 Java, 特别适合高性能需求场景。**环境搭建** 需 Android Studio 和 NDK, 工具如 CMake。**JNI** 构建 Java-C++ 交互, 通过声明 `native` 方法并在 C++ 中实现。**实战** 示例: 使用 C++ 计算斐波那契数列以提高效率。**总结** 混合编程增强性能, 但增加复杂性, 使用前需谨慎评估。
114 4
|
3月前
|
SQL Java Unix
Android经典面试题之Java中获取时间戳的方式有哪些?有什么区别?
在Java中获取时间戳有多种方式,包括`System.currentTimeMillis()`(毫秒级,适用于日志和计时)、`System.nanoTime()`(纳秒级,高精度计时)、`Instant.now().toEpochMilli()`(毫秒级,ISO-8601标准)和`Instant.now().getEpochSecond()`(秒级)。`Timestamp.valueOf(LocalDateTime.now()).getTime()`适用于数据库操作。选择方法取决于精度、用途和时间起点的需求。
48 3