我JNIEnv
在全局存储,所以我稍后可以调用静态java方法.但是存储一个全局指针是否是必要的JNIEnv
,它们可以与任何其他java对象一起存储,或者它是一个不需要它的特殊情况.
JNIEnv* globalEnvPointer;
[JNICALL etc] void init(JNIENv* env, [etc])
{
//required?
globalEnvPointer = (JNIENv*) (env*)->GetGlobalRef(env, env);
//or is this OK?
globalEnvPointer = env;
}
Run Code Online (Sandbox Code Playgroud)
编辑
我在这里有点愚蠢,将使用的所有方法globalEnvPointer
都在我的init中调用,因为我init
实际上是我的c
程序main
方法,直到程序结束才会返回.我也在c程序中没有使用其他线程.我认为这简化了答案.
JNIEnv* globalEnvPointer;
[JNICALL etc] void main(JNIENv* env, [etc])
{
//required?
globalEnvPointer = (JNIENv*) (env*)->GetGlobalRef(env, env);
//or is this OK?
globalEnvPointer = env;
someMethod();
}
void someMethod()
{
//use globalEnvPointer here
}
Run Code Online (Sandbox Code Playgroud) 我正在尝试使用JNI从C++调用Java方法.要做到这一点,我已经安装jdk1.7.0_51
,链接jdk1.7.0_51\lib\jvm.lib
,包括jdk1.7.0_51\include
和jdk1.7.0_51\include\win32
.在Visual Studio 2012中使用以下代码我尝试创建一个Java vm对象 - 但该函数总是以退出代码1终止我的应用程序(该函数不返回1:我的程序完全终止并发送退出代码1).
#include <iostream>
#include "jni.h"
int main(int argc, char*argv[]){
JNIEnv* env = nullptr;
JavaVM* jvm = nullptr;
JavaVMInitArgs vm_args;
JavaVMOption options[2];
options[0].optionString = "-Djava.class.path=.";
options[1].optionString = "-DXcheck:jni:pedantic";
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 2;
vm_args.options = options;
vm_args.ignoreUnrecognized = JNI_TRUE; // remove unrecognized options
int ret = JNI_CreateJavaVM(&jvm, (void**) &env, &vm_args);
std::cout << "This code is never reached" << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
操作系统: Windows 7(x64)
编译器: Visual …
我通过名为Xamarin.GradleBinding的visual studio扩展创建了java绑定库.我添加了ru.rambler.android:swipe-layout:1.0.14
包,并在使用它时SwipeLayout
,一切正常.但不幸的是,它没有创建相应的C#类或类似的东西.我尝试手动添加包但仍然没有.
我检查了GitHub上的源代码.SwipeLayout
有一个没有参数的public void
方法reset()
:
public void reset()
Run Code Online (Sandbox Code Playgroud)
我尝试从c#中调用此方法JNIEnv
.
IntPtr type = JNIEnv.FindClass("ru/rambler/libs/swipe_layout/SwipeLayout");
IntPtr method = JNIEnv.GetMethodID(type, "reset", "()V");
try
{
JNIEnv.CallObjectMethod(_swiper.Handle, method);
}
catch (Exception ex)
{
var s = ex.Message;
}
Run Code Online (Sandbox Code Playgroud)
已成功找到类型和方法,但正在调用
JNIEnv.CallObjectMethod(_swiper.Handle, method);
Run Code Online (Sandbox Code Playgroud)
这个方法崩溃了应用程序,它甚至没有进入catch块.
Tt必须是_swiper.Handle
第一个参数的原因.
_swiper
字段是类型,ViewGroup
因为SwipeLayout
派生自ViewGroup
.我找不到如何获取视图的指针来传递该方法.
在调试时,当我调查时_swiper
,它似乎是正确的实例SwipeLayout
关于这方面的信息很少,例如2006 年的这个,人们放弃了优雅地释放 JNI 资源。
JNI_OnUnload
( Oracle 文档) 旨在当 JVM 中不再需要您的本机功能时释放资源(特别是“全局引用”)。本机库将像这样加载
static {
System.loadLibrary("mylibjni"); // on Linux this translates to "libmylibjni.so"
}
Run Code Online (Sandbox Code Playgroud)
...但是 Java 没有提供明确的卸载方法。
发生了什么:在我的 lib 中,由于没有机会进行清理,lib 最终确实卸载了(我不明白什么时候,请参阅下面的调用堆栈),但是为时已晚,这会触发一些拥有 JNI 全局引用的全局变量调用DeleteGlobalRef
失败:
# JRE version: OpenJDK Runtime Environment (10.0.2+13) (build 10.0.2+13)
# Java VM: OpenJDK 64-Bit Server VM (10.0.2+13, mixed mode, tiered, compressed oops, g1 gc, linux-amd64)
# Problematic frame:
# C [libblahjni.so+0x9a7e6] JNIEnv_::DeleteGlobalRef(_jobject*)+0x14
Run Code Online (Sandbox Code Playgroud)
深入研究一下,这是因为线程上没有JNIEnv
执行卸载(我正在缓存环境thread_local
)。当时尝试检索 Env 没有成功 …
我在 VC6 中编写了一个普通的 C++ 应用程序,它使用 jni 调用 java 中的方法。为此,我在项目目录中包含了 jni.h 和其他 lib 文件夹。
代码编译但是当我运行应用程序时它失败说“找不到jvm.dll。重新安装应用程序会修复它”。但是 jvm.dll 存在于我的电脑中。
如果我将应用程序的工作目录设置为 jvm.dll 所在的位置,那么它就像一个魅力。我无法将应用程序的工作目录设置为 jvm.dll 目录,因为该应用程序将来会成为 dll。
我也尝试将系统变量中的 PATH 变量更新到 jvm.dll 的位置,但没有任何效果..
我怀疑 jvm.lib 正在从我的应用程序未提供的某个目录位置加载 jvm.dll .. 因此它失败了,..
请建议我出了什么问题。
提前致谢。
问候拉加文德拉
我正在尝试使用 AudioTrack 从 JNI 播放音频缓冲区
使用以下代码从 JNI 初始化 AudioTrack 对象
jclass AudioTrack = mEnv->FindClass("android/media/AudioTrack");
jclass AudioFormat = mEnv->FindClass("android/media/AudioFormat");
jclass AudioManager = mEnv->FindClass("android/media/AudioManager");
jfieldID AudioFormat_ENCODING_PCM_16BIT = mEnv->GetStaticFieldID(AudioFormat, "ENCODING_PCM_16BIT", "I");
jint ENCODING_PCM_16BIT =mEnv->GetStaticIntField( AudioFormat, AudioFormat_ENCODING_PCM_16BIT);
jfieldID AudioFormat_CHANNEL_CONFIGURATION_MONO = mEnv->GetStaticFieldID(AudioFormat, "CHANNEL_CONFIGURATION_MONO", "I");
jint CHANNEL_CONFIGURATION_MONO =mEnv->GetStaticIntField( AudioFormat, AudioFormat_CHANNEL_CONFIGURATION_MONO);
getMinBufferSize = mEnv->GetStaticMethodID(AudioTrack,"getMinBufferSize","(III)I");
// int minBufferSize = AudioTrack.getMinBufferSize(8000,AudioFormat.CHANNEL_CONFIGURATION_MONO,AdioFormat.ENCODING_PCM_16BIT);
minBufferSize = mEnv->CallStaticIntMethod(AudioTrack,getMinBufferSize,8000,ENCODING_PCM_16BIT,CHANNEL_CONFIGURATION_MONO);
//AudioTrack at = new AudioTrack(AudioManager.STREAM_MUSIC, 8000, AudioFormat.CHANNEL_CONFIGURATION_MONO,AudioFormat.ENCODING_PCM_16BIT, minBufferSize,AudioTrack.MODE_STREAM);
jfieldID AudioManager_STREAM_MUSIC = mEnv->GetStaticFieldID(AudioManager, "STREAM_MUSIC", "I");
jint STREAM_MUSIC = mEnv->GetStaticIntField( AudioManager, AudioManager_STREAM_MUSIC);
jfieldID AudioTrack_MODE_STREAM = mEnv->GetStaticFieldID(AudioTrack, "MODE_STREAM", …
Run Code Online (Sandbox Code Playgroud) 我正在寻找有关如何使用 JNI 从 C 调用 Java 方法的教程。在我迄今为止找到的所有教程中,示例展示了如何首先从 C 创建 JVM。
我的应用程序从Java开始并使用JNI调用一些C函数。我现在需要从 C 调用一些 Java 函数,但我不想从 C 启动 JVM。
例如,是否可以创建一个用 C 实现的“本机”方法,并使用它来保存指针JNIEnv
,然后重用它,而不是从 C 创建一个新的 JVM 实例来调用 Java方法?
有例子吗?
编辑:
看过这篇文章的人一定要小心!仅使用JNIEnv*
来自当前 JNI 调用的实例!JNIEnv*
如果您不想让程序崩溃,请不要保存和重用之前获得的任何指针。
在最好的情况下,使用旧的保存的指针可能会使您的应用程序崩溃。在更糟糕的情况下,它可能会导致难以调试和理解的低级不一致问题
不应缓存任何JNIEnv*
实例,因为如果您的程序从 Java 启动,那么您的 C 代码无论如何都只能作为本机 java 方法执行,其 C 实现始终会获取相关的JNIEnv*
实例。这是在本机方法返回之前应使用的唯一实例,而不是任何旧的已保存实例。
我将我们的本机 Windows 应用程序启动器从 Java 8 移植到 Java 11。我们过去常常调用JNI_CreateJavaVM
方法来实例化 JVM 实例、查找主类并调用其main
方法。对于模块化应用程序,env->FindClass
不会返回我们的应用程序类。我尝试调用Class.forName
,但它也没有返回类实例。
另外,还有JNI_CreateJavaVM
对争论的抱怨--add-modules
。
我们应该如何指定 JNI api 加载的模块?
我该怎么做才能从本机部分找到应用程序类?
java java-native-interface java-platform-module-system jnienv java-11
我正在尝试做的简化如下。
我必须存储 JVM(2) 和 global jobject(3)。
但在第 3 部分,
JNI DETECTED ERROR IN APPLICATION: JNI CallVoidMethodV called with pending exception java.lang.NoSuchMethodError: no non-static method "Lpackage/name/here/d/b;.setInput([F)V"
Run Code Online (Sandbox Code Playgroud)
我总是收到这个错误。
结构
** <-> 表示沟通
其他 Java 类 <-> Wrapper.java
Wrapper.java <-> native-lib.cpp
native-lib.cpp <-> Wrapper.cpp
Wrapper.cpp <-> 其他 C++ 类
包装器
private static long wrapperAddr = 0; // initializes later …
Run Code Online (Sandbox Code Playgroud) 我正在做一个涉及 Rust 和 Java 的项目。我需要能够从 Rust 端使用 JNI,而无需 Java 端调用它(因为它不是我的代码)。到目前为止,我已经能够确保我的 DLL 被注入(在按键上打开一个小窗口,我一直在使用它进行调试)。
相关代码的简短示例如下:
use jni::sys::{JNI_GetCreatedJavaVMs, JNIInvokeInterface_};
let jvm_ptr = null_mut() as *mut *mut *const JNIInvokeInterface_;
let count = null_mut();
// hasn't crashed
JNI_GetCreatedJavaVMs(jvm_ptr, 1, count); // https://docs.rs/jni/latest/jni/sys/fn.JNI_GetCreatedJavaVMs.html
// crashes
Run Code Online (Sandbox Code Playgroud)
我的问题是:在这种情况下是否有可能/如何获得 JNI 环境?
jnienv ×10
java ×6
c++ ×3
android ×2
c ×2
android-ndk ×1
ffi ×1
java-11 ×1
java-binding ×1
java-platform-module-system ×1
jniwrapper ×1
rust ×1
xamarin ×1