I am trying to compile the following for the android ndk
#include <jni.h>
#include <string.h>
extern "C" {
JNIEXPORT jstring JNICALL Java_com_knucklegames_helloCpp_testFunction(JNIEnv * env, jobject obj);
};
JNIEXPORT jstring JNICALL Java_com_knucklegames_helloCpp_testFunction(JNIEnv *env, jobject obj) {
return env->NewStringUTF(env, "Hello from native code!");
}
but it is giving the following error
Compile++ thumb: helloCpp <= /cygdrive/c/workspace/helloCpp/jni/main.cpp
/cygdrive/c/workspace/helloCpp/jni/main.cpp: In function '_jstring* Java_com_knucklegames_hello
Cpp_testFunction(JNIEnv*, _jobject*)':
/cygdrive/c/workspace/helloCpp/jni/main.cpp:10: error: no matching function for call to '_JNIEn
v::NewStringUTF(JNIEnv*&, const char [24])'
/cygdrive/d/android/android-ndk-r4b/build/platforms/android-8/arch-arm/usr/include/jni.h:839: note: candidates
are: _jstring* _JNIEnv::NewStringUTF(const char*)
make: *** [/cygdrive/c/workspace/helloCpp/obj/local/armeabi/objs/helloCpp/main.o] Error 1
The NewStringUTF function only takes one argument, a c-string:
env->NewStringUTF("Hello from native code!");
There is a C version that goes like this:
NewStringUTF(env, "Hello from native code!");
But you are obviously using the C++ version.
Related
I am looking at the MoreTeapots sample:
https://github.com/googlesamples/android-ndk/tree/master/MoreTeapots
and I see that is easy to call a Java method from the C++ code using android_native_app_glue.c by using this method:
jclass clazz = jni->GetObjectClass(app_->activity->clazz);
jmethodID methodID = jni->GetMethodID(clazz, "updateCamera", "(FFF)V");
jni->CallVoidMethod(app_->activity->clazz, methodID, x, y, z);
yet, can I do the reverse in that sample?
Declare a function into java code and that calls the native code. Notice that sample uses "glue"; therefore, the answer is not just these steps:
https://developer.android.com/ndk/samples/sample_hellojni.html
it is different. I see no hooks from java to glue, only from glue to java. I believe glue is running in its own thread.
any leads?
thx!
you could declare a callback in your native code
JNIEXPORT void JNICALL Java_package_Activity_nativeCallback(JNIEnv* jenv, jobject obj);
And then from Java code, just declared as native
native void nativeCallback();
Remember that this execute in main thread, and you should send a command to the background thread to process.
Best regards.
That does not work with "glue". If you look at the sample I mentioned it is different. It uses glue. So I added to the java code:
public native void nativeCallback();
then to native:
extern "C" {
JNIEXPORT void JNICALL Java_com_sample_moreteapots_MoreTeapotsNativeActivity_nativeCallback(JNIEnv *env, jobject obj);
};
JNIEXPORT void JNICALL Java_com_sample_moreteapots_MoreTeapotsNativeActivity_nativeCallback(JNIEnv *env, jobject obj) {
int i = 0;
return;
}
it compiled and linked. But when I tried to invoke the method from Java I get this:
FATAL EXCEPTION: main
Process: com.sample.moreteapots, PID: 31733
java.lang.UnsatisfiedLinkError: No implementation found for void com.sample.moreteapots.MoreTeapotsNativeActivity.nativeCallback()
(tried Java_com_sample_moreteapots_MoreTeapotsNativeActivity_nativeCallback
and Java_com_sample_moreteapots_MoreTeapotsNativeActivity_nativeCallback__)
I try to compiled this:
#include <stdio.h>
#include <jni.h>
#include "callJNITest.h"
JNIEXPORT jint JNICALL Java_callJNITest_displayHelloWorld
(JNIEnv env, jclass jcls) {
printf("Hello World!");
return 1;
}
But I always get these errors:
../HelloWorldJNI.c:5:24: error: conflicting types for ‘Java_callJNITest_displayHelloWorld’
../callJNITest.h:15:24: note: previous declaration of ‘Java_callJNITest_displayHelloWorld’ was here
make: * [HelloWorldJNI.o] Error 1
The error happened also in this case:
JNIEXPORT void JNICALL Java_callJNITest_displayHelloWorld
(JNIEnv env, jclass jcls) {
printf("Hello World!");
return;
}
but
JNIEXPORT JNICALL Java_callJNITest_displayHelloWorld
(JNIEnv env, jclass jcls) {
printf("Hello World!");
return;
}
works fine.
My question is how return types should be declared in JNI? Thanks!
Creating an answer from my comment since it solved the OP's problem.
The header file contains a declaration where the type of the first argument of Java_callJNITest_displayHelloWorldis a JNIEnv*, while in the cpp file it has the type JNIEnv.
The fix is to change the type of env in the cpp file to JNIEnv* so that it matches the declaration in the header file.
An old win32 project does not compile correctly on new vista 64bit machine.
I do not use 64-bit java.
package org.denkweise.coloredconsole;
public final class Console{
static native void setColor(byte fg, byte bg);
}
goes to ColoredConsole32.h:
#include <jni.h>
JNIEXPORT void __cdecl Java_org_denkweise_coloredconsole_Console_setColor(JNIEnv *, jobject, jbyte, jbyte);
goes to ColoredConsole32.cpp:
#include "ColoredConsole32.h"
#include <windows.h>
JNIEXPORT void __cdecl Java_org_denkweise_coloredconsole_Console_setColor(JNIEnv * env, jobject ob, jbyte fg, jbyte bg) {
/*stuff*/
}
and compile successfully via mingw
g++ -D_JNI_IMPLEMENTATION_ -enable-stdcall-fixup -Wl,--kill-at ColoredConsole32.h -Ic:\jdk1.6.0_26\include -Ic:\jdk1.6.0_26\include\win32 -shared -o ColoredConsole.dll
System.loadLibrary works great, but setColor throws an
java.lang.UnsatisfiedLinkError: org.denkweise.coloredconsole.Console.setColor(BB)V
any sugestions?
OK, was my mistake:
the java-method was static, but the 2nd param of my c-method was jobject instead of jclass.
make the method unstatic solves my problem.
Regards
I have created my first native call in Java with the Android SDK today.
I found a few examples but there aren't consistent with the function head.
I used always
JNIEXPORT void JNICALL Java_com_test_Calculator_calcFileSha1
(JNIEnv *, jclass, jstring);
but I have seen
JNIEXPORT void JNICALL Java_com_test_Calculator_calcFileSha1
(JNIEnv *, jobject, jstring);
Belonging to the heads are different was to get the class of the caller.
But what is the preferred way?
From the C++ code I want to call a java method. I found the JNI documentation (Calling Instance Methods).
But I don't know what the first parameter (object) should be.
I tried to give the class instance which I get from the call of the native method, which fails with an AbstractMethodError.
Fixed source code:
public class TestCalc extends Activity {
static {
System.loadLibrary("Test");
}
private void setFilesize(long size) {
}
}
Native Library:
// header
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL Java_com_test_TestCalc_calcFilesize
(JNIEnv *, jobject, jstring);
void setFilesize(const INT_64 size);
#ifdef __cplusplus
}
#endif
#endif
// code
JNIEnv * callEnv;
jobject callObj;
JNIEXPORT void JNICALL Java_com_test_SHA1Calc_calcFileSha1
(JNIEnv * env, jobject jobj, jstring file)
{
callEnv = env;
callObj = jobj;
[...]
}
void setFilesize(const INT_64 size) {
jmethodID mid;
jclass cls;
cls=callEnv->FindClass("com/test/TestCalc");
mid=callEnv->GetMethodID(cls, "setFilesize", "(J)V");
if (mid == 0) {
__android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "NDK:LC: [%s]", "Cannot find method setFilesize");
return;
}
callEnv->ExceptionClear();
callEnv->CallVoidMethod(callObj, mid, size);
if(callEnv->ExceptionOccurred()) {
callEnv->ExceptionDescribe();
callEnv->ExceptionClear();
}
}
Thanks for any advices.
Call[type]Method is only for private methods and constructors. (Calling Instance Methods) When you call a public method, you will get an AbstractMethodError.
jobject could be any java object while jclass is supposed to be an object representing java.lang.Class. In C API, jobject and jclass is the same thing while C++ API is trying to enforce type safety and declares those as different types where jclass inherits jobject. The second argument is supposed to represent a class, so jclass is preferred. Even if in C it doesn't matter, it can hint the developer or even save you time if you ever decide to switch to C++. Read more about JNI types here.
I have a working implementation of NDK library and corresponding Java-class. But I am not able to add overloaded method to that class. Currently my class contains:
package com.package;
public class MyClass
{
public static native String getFileName();
static
{
System.loadLibrary("mylib");
}
}
My jniwrappers.cpp file has the following declaration:
JNIEXPORT jstring JNICALL
Java_com_package_MyClass_getFileName(_JNIEnv* env, jobject thiz);
Up to this point everything is working fine. But next I modify my class:
package com.package;
public class MyClass
{
public static native String getFileName();
public static native String getFileName(int index);
...
}
And add to jniwrappers.cpp another declaration:
JNIEXPORT jstring JNICALL
Java_com_package_MyClass_getFileName__I(_JNIEnv* env, jobject thiz, jint index);
It compiles fine, Android application starts, does not get UnsatisfiedLinkError but when it calls the second method with the argument the first C++ function is being called but not the second. I have other methods with arguments in that class but none of them are overloaded so their respective JNI signatures do not contain arguments.
So, what am I doing wrong?
You should use javah tool to generate those signatures.
To use it, build the class file where you have your native function. You'll get a class file.
Run javah -jni com.organisation.class_with_native_func, it'll generate a header file for you.
It's far cleaner than editing it yourself.
You have to add a __ onto the end of the original getFileName function now that it is overloaded. Your 2 C function prototypes should now look like this:
JNIEXPORT jstring JNICALL Java_com_package_MyClass_getFileName__
(JNIEnv *, jclass);
JNIEXPORT jstring JNICALL Java_com_package_MyClass_getFileName__I
(JNIEnv *, jclass, jint);