We are using Android NDK to write a c++ library on android and the library needs use JavaVM and AAssetManager. The problem is that we find no way to access JavaVM and AAssetManager inside our library.
What I know is:
In native host application, we can get them from ANativeActivity
AAssetManager_fromJava if java
jint JNI_OnLoad(JavaVM* vm, void* reserved)
It seems it can't work if the host application is also native c++
The library will be delivered to our users. It won't be elegant to force our users to set JavaVM and AAssetManager. Do you have any idea? thanks
If you want to cover both cases in the same way ("typical" and "native" app) - the only way is next:
Add MyLibrary.java to your library. That file should declare native method MyLibrary.init(AssetManager am);. Implementation of that method must be placed in your C++ code, where you get java reference to asset manager and then can obtain AAssetManager *
Add JNI_OnLoad() to your library in order to obtain JavaVM*
Build your library as separate .so to allow system to invoke your JNI_OnLoad()
Usage looks next:
Client app declares custom Application class in its manifest
Implementation of this custom class overrides onAttachBaseContext() method, which implementation invokes System.loadLibrary("mylibrary") and then your MyLibrary.init(getAssets()).
Related
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 currently developing app for Android that provides various audio settings. I use android system prepared by someone else, and it provides (I see in source and compiled files) some methods that could be useful for me. For example there are (kernel/drivers/audio/audio.c) some methods to change bands (for equalizer). In compiled system there is audio_setting.so file in some audio dir on kernel. Is there a possibility to use this methods (library) in my application NDK? I don't want to compile my app with whole system, rather to dynamically add this lib.
edit:
It was simplier than I thought. I used:
void *some_lib;
bundlewrapper = dlopen("some/path/some_lib.so", RTLD_LAZY);
if ( some_lib!= NULL ) {
LOGV("Loaded lib\n");
// use methods from lib
}
Sure, you can use any code on the system.
Obviously if it is non-JNI code you'll have to call it from your own JNI code or wrapper.
In your Android.mk file you will need to add the extra lib in LOCAL_LDLIBS
In Android if an C/C++ shared library created using NDK is invoked and it loads a file what is its currently working directory? Thanks
The current directory is "/", not the application directory:
#include <jni.h>
#include <android/log.h>
char cwd[1024];
if (getcwd(cwd, sizeof(cwd)) != NULL)
__android_log_print(ANDROID_LOG_INFO, "", cwd);
To get the application directory, you need to use JNI calls to Java code, which in turn gets android application directory from Context.
Negative. Native code getcwd() will return '/', which is not the application directory. To let native know where it is, must pass application directory (obtained from Context object) to native deliberately via a native method.
Or try to call Context's method with native codes, which is too complex.
Maybe NDK sample at "android-ndk-rxx/samples/two-libs" will give you some useful message.
I have built FFMPEG executables and libraries as provided by Bambuser (http://bambuser.com/opensource). So I managed to build the Android executables and libraties. How can I link these libs in my Eclipse project and invoke the FFmpeg functions from Java? The open source code includes the C header-files.
I am new to native coding for Android, and I could not find an easy answer for this. In basic : having a bunch of Android compatible libraries and some C header files what do I have to do to reuse those libaries' functionality from java (+Android SDK)?
Any help would be appreciated.
Kind regards,
WhyHow
You have to write some C glue code using the JNI conventions to expose the FFmpeg functionalities to Java code. Here's an example of a JNI method implemented in C from the Android NDK samples:
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
return (*env)->NewStringUTF(env, "Hello from JNI !");
}
You also need some Java code to load the library and declare the native method.
public class HelloJni
{
public native String stringFromJNI();
static {
System.loadLibrary("hello-jni");
}
}
I found this project on sourceforge which already has implemented some JNI interface to ffmpeg to integrate it with the Java Media Framework. You may find it useful.
There's another Java FFI technology called JNA (Java Native Access) that allows you to declare native function prototypes in Java and call them directly. Using it may require less boilerplate code. See this project for an Android implementation. (I have never used it myself)