我在 VC6 中编写了一个普通的 C++ 应用程序,它使用 jni 调用 java 中的方法。为此,我在项目目录中包含了 jni.h 和其他 lib 文件夹。
代码编译但是当我运行应用程序时它失败说“找不到jvm.dll。重新安装应用程序会修复它”。但是 jvm.dll 存在于我的电脑中。
如果我将应用程序的工作目录设置为 jvm.dll 所在的位置,那么它就像一个魅力。我无法将应用程序的工作目录设置为 jvm.dll 目录,因为该应用程序将来会成为 dll。
我也尝试将系统变量中的 PATH 变量更新到 jvm.dll 的位置,但没有任何效果..
我怀疑 jvm.lib 正在从我的应用程序未提供的某个目录位置加载 jvm.dll .. 因此它失败了,..
请建议我出了什么问题。
提前致谢。
问候拉加文德拉
Android C/C++ 原生调用Java API 的例子很多。但是,我读过的所有这些示例都是 Android Java API 首先调用 native,然后 native 使用传递的 JNI-ENV 调用其他 Java API。
没有通过的JNI-ENV,C/C++怎么能搞定呢?C/C++ 本机是否有可能通过创建 JavaVM 来调用 Android 中的 Java API?如果是这样,请分享链接。我已经完成了一个项目 CoCos2dx,我无法找到明确的细节。github.com/nokia-developer/cocos2d-x-qt/tree/master/
提前致谢!
我正在尝试使用 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 环境?
我正在编写一个带有本机线程(pthreads)的C++应用程序,我需要调用一些Java方法等.我不确定哪些JNI对象可以安全地缓存,即存储在我的C++对象中以供以后使用,可能/可能是由不同的线程.我知道如果我的类'方法可以被不同的线程调用,我不能缓存JNIEnv,而是缓存JavaVM并通过附加当前线程获得JNIEnv.但这是否意味着我无法缓存从JNIEnv获得的任何东西?我需要使用以下JNIEnv方法获得的对象:
FindClass,GetMethodID,NewObject,NewGlobalRef
那些在线程中保持有效,还是每次都必须获得新的?如果是后者,有没有办法在一个本机线程中创建一个对象,并且能够访问另一个线程中的同一个对象?
我用来jvm->GetEnv(&envThread, JNI_VERSION_1_6)获取多线程的“env”以便进行多个envThread->GetMethodID()调用。两个线程都正确连接到 JVM。
我在第一个线程上调用“GetMethodID()”返回的函数没有任何问题,但是当第二个线程尝试调用时,我看到以下消息:
art/runtime/check_jni.cc:65] JNI DETECTED ERROR IN APPLICATION: thread Thread[13,tid=8207,Native,Thread*=0xaed08400,peer=0x12dcd080,"Thread-10224"]
using JNIEnv* from thread Thread[1,tid=8148,Runnable,Thread*=0xb4e07800,peer=0x87bc5ef0,"main"]
A/art(8148): art/runtime/check_jni.cc:65 in call to CallVoidMethodV
08-31 14:11:08.029: A/art(8148): art/runtime/check_jni.cc:65] "Thread-10224" prio=10 tid=13 Runnable
08-31 14:11:08.029: A/art(8148): art/runtime/check_jni.cc:65] group="main" sCount=0 dsCount=0 obj=0x12dcd080 self=0xaed08400
08-31 14:11:08.029: A/art(8148): art/runtime/check_jni.cc:65] sysTid=8207 nice=-11 cgrp=apps sched=0/0 handle=0xafb18b00
08-31 14:11:08.029: A/art(8148): art/runtime/check_jni.cc:65] state=R schedstat=( 17710887 6014947 64 ) utm=1 stm=0 core=3 HZ=100
08-31 14:11:08.029: A/art(8148): art/runtime/check_jni.cc:65] | stack=0xaee04000-0xaee06000 stackSize=1012KB
Run Code Online (Sandbox Code Playgroud)
因为我对第二个线程jvm->getEnv()返回的调用JNI_OK,所以它已经附加(如预期)。但没想到的是,返回的 JniENV …
"Simple" question put short:
Why exactly does
JNIEnv *g_env = NULL;
(*g_env)->ExceptionDescribe(g_env);
Run Code Online (Sandbox Code Playgroud)
compile in gcc (C)
but not in g++ (C++)
error: base operand of ‘->’ has non-pointer type ‘JNIEnv’ {aka ‘JNIEnv_’}
Run Code Online (Sandbox Code Playgroud)
As I am working mainly with C++ I don't see why it should compile. As stated by the error, dereferencing the pointer will yield a "variable" and not a pointer anymore. I.e.: in C++ it would be either
g_env->ExceptionDescribe
Run Code Online (Sandbox Code Playgroud)
or
(*g_env).ExceptionDescribe
Run Code Online (Sandbox Code Playgroud)
as its not JNIEnv **
到目前为止,我已将JNI环境和作业对象保存在本地.我发现,为了我的JNI运行ICS和up设备,我需要修复我的JNI代码.这是我得到的错误:
02-20 10:20:59.523: E/dalvikvm(21629): JNI ERROR (app bug): attempt to use stale local reference 0x38100019
02-20 10:20:59.523: E/dalvikvm(21629): VM aborting
02-20 10:20:59.523: A/libc(21629): Fatal signal 11 (SIGSEGV) at 0xdeadd00d (code=1), thread 21629
Run Code Online (Sandbox Code Playgroud)
我对如何创建/销毁这些全局变量感到困惑,如果我甚至做得对.
我的应用程序目前在使用此代码的所有pre-ICS设备上正常运行:
BYTE Java_my_eti_commander_RelayAPIModel_00024NativeCalls_InitRelayJava( JNIEnv *env, jobject obj ) {
myEnv = (env);
myObject = obj;
changeID = (*myEnv)->GetStaticMethodID( myEnv, myObject, "changeItJavaWrapper", "(S)V" );
getID = (*myEnv)->GetStaticMethodID( myEnv, myObject, "getItJavaWrapper" , "(S)S" );
putID = (*myEnv)->GetStaticMethodID( myEnv, myObject, "putItJavaWrapper" , "(B)V" );
flushID = (*myEnv)->GetStaticMethodID( myEnv, myObject, "flushItJavaWrapper" …Run Code Online (Sandbox Code Playgroud) JNI参考说明了这一点
"本地引用在本机方法调用的持续时间内有效.它们在本机方法返回后自动释放.
资料来源:http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html#global_local
我有点迷失在这里.根据上面,我必须显式调用NewGlobalRef并传递从调用NewObject的对象返回的对象.我尝试了这个,似乎当GC启动时,它不会收集我的引用(就像仍然保留它们的东西).考虑以下项目: Main.java:
package lv.example;
import java.io.IOException;
import java.util.ArrayList;
class Main {
public static void main(String[] args) {
ArrayList<Object> store = new ArrayList<Object>();
while(true) {
Object d = null;
try {
int c = System.in.read();
d = Dummy.getWeakGlobalRef();
if(c == 'c')
store.clear();
store.add(d);
System.out.println(d);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
Dummy.java:
package lv.example;
class Dummy {
static {
System.loadLibrary("dummy");
}
native static Dummy getLocalRef();
native …Run Code Online (Sandbox Code Playgroud) 我的 Java 类中有一个返回 string 的方法。当前方法签名 ()Ljava/lang/String; 我可以在本地调用中使用 JVM 创建类和方法 ID。已经完成了 GetStaticMethodID 等......一切都很好。
如何调用这个方法?例如: env->CallIntMethod() env->CallCharMethod() .... 哪个选项可以取回字符串?
在 C++ 中,我需要复制此 Java 方法返回的字符串值。注意:如果需要,我可以更改 Jar 中方法的签名。或者可以添加另一种方法来包装另一个。
jnienv ×13
java ×6
android ×5
c++ ×5
android-ndk ×3
c ×3
ffi ×1
java-11 ×1
java-platform-module-system ×1
jniwrapper ×1
pointers ×1
rust ×1
struct ×1