My Android application comprises two parts: frontend written in Java and game written in C++ using NativeActivity NDK stuff. I have a problem integrating Flurry into my application. Flurry works fine from within Java part, but crashes from within C++.
More specifically, call
jni_env->FindClass("com/flurry/android/FlurryAgent");
results in ClassNotFoundException.
jni_env variable is not broken because I am able to get some Intent params using it.
FlurryAgent.jar is added to libs dir and into .classpath. I've even checked 'Order and Export' checkbox for FlurryAgent.jar (though I have no idea what does it mean). Nothing helps.
One more detail: my application is divided into Library and App parts. I have added FlurryAgent.jar to both parts and checked 'Order and Export' in both parts, but it still does not help. Clean & rebuild does does not help either. Did I miss something?
The answer is here: http://archive.is/QzA8
In other words, NativeActivity cannot find a third-party class and instead of
jni_env->FindClass("com/flurry/android/FlurryAgent");
one should use
jobject nativeActivity = state->activity->clazz;
jclass acl = jni_env->GetObjectClass(nativeActivity);
jmethodID getClassLoader = jni_env->GetMethodID(acl, "getClassLoader", "()Ljava/lang/ClassLoader;");
jobject cls = jni_env->CallObjectMethod(nativeActivity, getClassLoader);
jclass classLoader = jni_env->FindClass("java/lang/ClassLoader");
jmethodID findClass = jni_env->GetMethodID(classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
jstring strClassName = jni_env->NewStringUTF("com.flurry.android.FlurryAgent");
jclass flurryClass = (jclass)(jni_env->CallObjectMethod(cls, findClass, strClassName));
jni_env->DeleteLocalRef(strClassName);
Related
I'm working on an Android Native-Activity application with Visual Studio, starting from scratch (I'm trying to make it work in a basic test app first). It uses Ant to build the apk.
In my native code, I need to call a custom java method (not java native) coming from a jar file, so I plan on using JNI. I found that the jni->findClass wouldn't work because my java function is not native, thus not loaded in the classpath. I'm using this code instead to load the jniHelpers class from my jar :
const ANativeActivity* activity = state->activity;
activity->vm->AttachCurrentThread(&env, 0);
jobject jobj = activity->clazz;
jclass clazz = env->GetObjectClass(jobj);
jmethodID getClassLoader = env->GetMethodID(clazz, "getClassLoader", "()Ljava/lang/ClassLoader;");
jobject cls = env->CallObjectMethod(jobj, getClassLoader);
jclass classLoader = env->FindClass("java/lang/ClassLoader");
jmethodID findClass = env->GetMethodID(classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
jstring strClassName = env->NewStringUTF("com.vivox.sdk.JniHelpers");
jclass jniHelpersClass = (jclass)(env->CallObjectMethod(cls, findClass, strClassName));
env->DeleteLocalRef(strClassName);
if (NULL == jniHelpersClass)
{
LOGW("Can't find the lib");
}
Now my question is how can my java class be found ?
Following a couple of tutorials (listed below), I understand that my jar should be under a libs folder at the root of my *.Packaging, and loaded from the build.xml here :
<target name="-pre-compile">
<path id="project.all.jars.path">
<path path="${toString:project.all.jars.path}"/>
<fileset dir="${jar.libs.dir}">
<include name="*.jar"/>
</fileset>
</path>
</target>
My jar file seems to be properly copied (I think?) into the generated build, but it still not found by JNI/in the classpath. In the tutorials, they all create a custom activity to use System.LoadLibrary, but as soon as I set the AndroidManifest.xml-application:hasCode to true (thus not using the built-in NativeActivity framework class), I can't reach my c++ code anymore. Is it possible to load the jar file without creating a custom activity ? Or if not, how can I reach my native code after entering my custom activity ?
Thanks a lot, I've been stuck on this for way too long already, all help is more than appreciated !
Tutorials :
https://retroscience.net/visual-studio-android-ndk-jar-files.html
https://qa.fmod.com/t/android-visual-studio-native-c-updated-how-to-make-it-work-in-a-reply/14829/2
I have an NDK shared library and I want to do some tests against it. I currently used googletest to create an native executable that links to the library, followed instructions in the README.NDK. A dummy executable can run on a Android emulator. Good.
Now, the tricky thing is that the shared library calls a lot of functions of an JNIEnv instance, for example:
env->NewStringUTF()
...
The question is, how can an Android native executable get an instance of JNIEnv?
One method is to use the invocation API described below.
http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/invocation.html
However, I looked at the jni.h of NDK, and it seems disallow the usages of this API:
/*
* VM initialization functions.
*
* Note these are the only symbols exported for JNI by the VM.
*/
#if 0 /* In practice, these are not exported by the NDK so don't declare them */
jint JNI_GetDefaultJavaVMInitArgs(void*);
jint JNI_CreateJavaVM(JavaVM**, JNIEnv**, void*);
jint JNI_GetCreatedJavaVMs(JavaVM**, jsize, jsize*);
#endif
Any suggestions are highly appreciated!
(I am new to Android so please correct me if I am wrong. Thanks!)
This is done via AttachCurrentThread().
It is benign to call this if the thread is already attached.
I'm creating a C++ Android APP based of the book Pro Android NDK and this tutorial (http://www.swig.org/Doc2.0/Android.html#Android_example_class)
I created a C++ class called Http that creates sockets to perform simple HTTP requests (mostly for learning purposes). The C++ app works on its own.
I compiled it to JNI (using Swig) and generated the appropriate JNI code and the Java "proxy" files which I can use to call the code.
My original C++ constructor has this signature:
Http::Http(const char * ip_address, int port)
1) In my AndroidStudio app I have an Activity called MainActivity. The Package containing the MainActivity and the generated JNI Java classes is com.zuzile. My default constructor looks like this SWIGEXPORT jlong JNICALL Java_com_zuzile_exampleJNI_new_1Http(JNIEnv *jenv, jclass jcls, jstring jarg1, jint jarg2) where "exampleJNI" is my Java class that contains the native method public final static native long new_Http(String jarg1, int jarg2);
2) After generating the appropriate JNI and corresponding Java classes I successfully compiled the JNI code into a .so file using NDK. I was able to load the .so file by calling System.loadLibrary("httpreq") httpreq is the name of my compiled module.
3) When I try to use my Module by calling Http("some IP address", "a port") I get the following error: java.lang.ClassNotFoundException: com.zuzile.MainActivity (as output by the Debugger).
If I remove the Http(...) declaration from my MainActivity.java my APP loads perfectly without crashing. But as soon as I use the Native code I generated it states it can't find com.zuzile.MainActivity.
I appreciate any help in advance as I've been stuck on this for 3 days now.
JNI is just an interface between JAVA and C/C++, you can't map directly c++ class to Jave class. you can just call mapped methods.
In your case, Http("some IP address", "a port") means java constructor, but you don't have a java class named "Http", right?
I am getting this message which is not allowing my apps to run which contain some native C/C++ files, which I build using NDK. Apps is closing and opening again and crashing in a loop. I am getting below compilation warning after making some awk related changes in android.mk
C:/android-ndk-r8/build/core/add-application.mk 128:Android NDK : Warning: APP-PLATFORM android-14 is larger than android:minsdkVersion 8 in ./AndroidManifest.xml
I have checked relevant threads associated with it, but couldn't find anything which can help me. Can anyone please help me, what I am missing here.
Logcat Output:
15:44:15.815: E/Trace(3026): error opening trace file: No such file or directory (2)
05-28 15:44:16.007: D/dalvikvm(3026): Trying to load lib /data/app-lib/com.example.raptorjni-2/libraptorq-test.so 0x40ce6428
05-28 15:44:16.035: D/dalvikvm(3026): Added shared lib /data/app-lib/com.example.raptorjni-2/libraptorq-test.so 0x40ce6428
05-28 15:44:16.035: D/dalvikvm(3026): No JNI_OnLoad found in /data/app-lib/com.example.raptorjni-2/libraptorq-test.so 0x40ce6428, skipping init
05-28 15:44:16.255: D/RaptorQ(3026): Entering the main function
Java main file snippet from where the C function is called :
Log.d(TAG,"isteps Ecoded" + isteps);
/* Call the JNI-ized version of DFRQEncPerfTest */
String res =
resultRQEncPerfString(nSrcSymbols, symbolSize, loss, niter,
mode, 0, header);
.C file function Snippet:
jstring
Java_com_example_raptorjni_RaptorJni_resultRQEncPerfString
(JNIEnv *env, jobject thiz,
jint nSrcSymbols, jint symbolSize, jint lossrate, jint nLoop,
jint mode, jint nRepair, jint header)
{
Implementation ....
JNI_Onload is optional initialization function introduced since JNI 1.4 (more or less), that allows developers to do some init jobs while library is loaded (for example, register native methods to jvm).
So we really don't need javah or something stupid to implement native java methods in c/c++, just call JNIEnv::registerNatives inside JNI_Onload .
For this issue, I think something else was wrong.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I load my own Java class in C on Android?
Application works in debug / run from Eclipse, but .APK gives .classNotFoundException when parsing XML layout that contains a custom View
In Android, I am accessing a native C library, by doing:
System.loadLibrary("testlib");
To load a native library.
In the JNI_OnLoad() function, it is trying to find a Java glue code class:
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env;
jclass k;
jint r;
r = vm->GetEnv ((void **) &env, JNI_VERSION_1_4);
k = env->FindClass ("com/test/android/aclass");
The FindClass() fails, and throws a NoClassDefFoundError exception.
Any idea why I cannot see my Java class from my C code?
I use this same library in another test application, and it works (so I am confident that the library works). I don't see why one app can find the java class, while the other cannot.
Found the answer.
My clue was that it would run fine if I ran it through eclipse, and only had this problem when I created a .apk file.
I found the solution here: Application works in debug / run from Eclipse, but .APK gives .classNotFoundException when parsing XML layout that contains a custom View