Is there a way to share a native C variable instantly with Java in android JNI?
I wanna receive data from C layer in client since the server is written in C++(with struct read/write involved),and record the data-coming situation in an array variable,and wanna detect that variable in Java and do what`s correspond, wondering if that is possible?
I considered writing a file about the data-coming situation into sdcard,however that the last thing I wanna do,any tips?
I recently had this problem and could solve it. I have a C++ Qt Android project that needs to execute some java code (for stuff only accessible from Android SDK). To achieve this, I had to share some constants between my java and C++ code (to have them talk together and understand each other).
Here are possible solutions to achieve this:
Have C++ pass constants values to Java object upon creation (or the way around if Java invokes C++). But it's apain if you have many variables.
Have a config file parsed dynamically by both C++ and Java module. Should work, but did not try it.
Declare variables in both places....bad idea and hard to maintain
Have a declaration file directly used ('included') by both C++ and Java
I finally made last solution work. The idea is to have a java file being used by both C++ and Java (the way around may work, but I'm more a C++ guy, so this way looked easier to me). And we use pre-processor to make this java file valid to be included by C++ as a header file!
Here is an example of Java file (constants.java) declaring constants (integers and strings):
package name1.name2.name3;
import java.lang.String;
class MyConstants
{
public static String THE_NAME() { return "Name"; }
public static Integer THE_VALUE() { return 12; }
};
This can be used with no problem from any Java code to access variables.
Now, here's how to include it from a C++ file:
#include <string>
using namespace std;
#define public public:
#define package struct mockup1 { int name3; };struct mockup2 { mockup1 name2; };int i1 =
#define name1 mockup2()
#define import struct mockup3 { int String; };struct mockup4 { mockup3 lang; };int i2 =
#define java mockup4()
#define String string
#define Integer int
#include "constants.java"
#undef public
#undef String
#undef package
#undef import
#undef java
#undef name3
Pre-processor then changes constants.java file into this valid C++ header file (the main difficuly was to get ride of package and import lines because you cannot use dots in macro names....had to be malicious):
struct mockup1 { int name3; };struct mockup2 { mockup1 name2; };int i1 = mockup2().name2.name3;
struct mockup3 { int String; };struct mockup4 { mockup3 lang; };int i2 = mockup4().lang.String;
class MyConstants
{
public: static string THE_NAME() { return "Name"; }
public: static int THE_VALUE() { return 12; }
};
Here you go with your constants in C++!
int main()
{
cout << MyConstants::THE_NAME() << MyConstants::THE_VALUE() << endl;
return 0;
}
I haven't done any android - so take this with a grain of salt - but you could probably use a direct byte buffer. The problem is going to be knowing that something happened. You could simply poll the buffer, but that wouldn't be much better than just using JNI to poll the value.
In regular java, people might take advantage of the sun.misc.Unsafe class for this, if they were willing to take the risk. I am not sure if that class exists in android, but perhaps this will help Unsafe class in Android?.
Related
Is there any way to use jniRegisterNativeMethods to map JNI functions in a NDK app? i.e. use a method_table to map native (C/C++) functions via the JNI instead of using ridiculously long JNI method names?
For example, in one exercise I saw, there was a C file added onto the platform it self,
#include "core_jni_helpers.h"
#include "jni.h"
static jlong init_native(JNIEnv *env, jobject clazz)
{
return 0;
}
// ...
static JNINativeMethod method_table[] = {
{ "init_native", "()J", (void*)init_native },
{ "finalize_native", "(J)V", (void*)finalize_native },
// ...
};
int register_android_server_ExampleService(JNIEnv *env)
{
return jniRegisterNativeMethods(env, "com/android/server/OpersysService",
method_table, NELEM(method_table));
};
But then the register_android_server_ExampleService was was manually invoked in services/core/jni/onload.cpp (on the platform)
Is there any way to do this or something similar with the NDK though?
My guess is no, as JNIHelp.h and core_jni_helpers.h aren't available in the NDK, and the Kotlin tools in Android Studio likely wouldn't be able to run a function in order to perform the auto complete. However I thought it was worth asking in the small case I could somehow avoid naming functions like Java_vendor_<name>_<name>_<name>_test_MainActivity_stringFromJNI
UPDATE # 4
I've successfully run the firstchar example, but now the problem is with using regex. Even after including header file, it is not recognizing regex operator. Any clue how can this be resolved?
UPDATE # 2
I've compiled sqlite3 library in my project. I am now looking for anyone to help me with writing a function for my regex, attach it to database and call it from query.
UPDATE # 3
I've written some code from this example. Here it is
extern "C"
void
Java_com_kfmwa916_testapp_DatabaseHandler_createFunction() {
sqlite3 *db;
//Open database
sqlite3_open("MyDBName.db", &db);
//Attach function to database
sqlite3_create_function(db, "firstchar", 1, SQLITE_UTF8, NULL, &firstchar, NULL, NULL);
}
And firstchar function is,
static void firstchar(sqlite3_context *context, int argc, sqlite3_value **argv) {
if (argc == 1) {
char *text = (char *) sqlite3_value_text(argv[0]);
if (text && text[0]) {
char result[2];
result[0] = text[0]; result[1] = '\0';
sqlite3_result_text(context, result, -1, SQLITE_TRANSIENT);
return;
}
}
sqlite3_result_null(context);
}
And the used it in my query like
SELECT firstchar(text) FROM dummy
But it is giving error
no such function firstchar()
Any help is highly appreciated.
Original Question
I am working with Arabic Language saved in UNICODE Format in SQLite. I want to implement a search. But there's a problem.
Let's say the text is
<html>
<head>
<style>
#font-face {
font-family: "Al_Mushaf";
src: url('fonts/al_mushaf.ttf');
}
#font-face {
font-family: "Jameel Noori Nastaleeq";
src: url('fonts/jameel_noori.ttf');
}
</style>
</head>
<body>
<h3 style='font-family:"Al_Mushaf"'>
صحابہ کرام کا انبیائے کرام کی سنّت پر عمل
میٹھے میٹھے اسلامی بھائیو!صدائے مدینہ لگانا انبیائے کِرام عَلَیْہِمُ السَّلَام کی اس قَدْر پیاری سنّت ہے کہ صحابۂ کِرام عَلَیْہِمُ الرِّضْوَان نے بھی اسے خُوب اپنایا اور وہ بھی حضرت سَیِّدُنا داؤد عَلَیْہِ السَّلَام کی طرح اپنے گھر والوں کو جگایا کرتے جیسا کہ حضرت سَیِّدُنا عبد اللہ بن عُمَر رَضِیَاللّٰہُ تَعَالٰی عَنْہُما فرماتے ہیں کہ میرے والِدِ مُحْتَرَم اَمِیرُ الْمُوْمِنِین حضرت سَیِّدُنا عُمَر فَارُوقِ اَعْظَم رَضِیَاللّٰہُ تَعَالٰی عَنْہ رات میں جس قَدْر ربّ تعالیٰ چاہتا،نَماز پڑھتے رہتے،یہاں تک کہ جب رات کا آخری وَقْت ہوتا تو اپنے گھر والوں کو بھی نَماز کے لیے جگا دیتے اور ان سے فرماتے: اَلصَّلٰوة یعنی نماز۔ پھر یہ آیت مُبارَکہ تِلاوَت فرماتے:
وَاۡمُرْ اَہۡلَکَ بِالصَّلٰوۃِ وَ اصْطَبِرْ عَلَیۡہَا ؕ لَا نَسْـَٔلُکَ رِزْقًا ؕ نَحْنُ نَرْزُقُکَ ؕ وَالْعٰقِبَۃُ لِلتَّقْوٰی (پ۱۶،طٰهٰ:۱۳۲)
</h3>
</body>
</html>
And it is stored in SQLite Database. Now I want to search html, it will return the result and if I search مبارکہ it won't return a result because in actual text, it is مُبارَکہ (with these extra UNICODE).
I want to ignore all HTML tags and these extra UNICODE Characters while searching so that html shouldn't return a result while مبارکہ should return a result.
What I found so far;
Make extra column and put stripped text into it and then search (I can't do it because there are thousands of books and they will take a lot of memory)
UDF Like SQL (I couldn't find any suitable example/tutorial to implement it)
Using REGEXP (I couldn't figure it out yet how to do this, I just know that I've to implement it myself)
SQL query using LIKE and GLOB operators and wildcard characters.
I'm stuck for two days and couldn't find a working solution. Option#4 is desirable but any working solution will do the charm.
Meanwhile, I've to keep application memory efficient and optimized searching.
Any help is highly appreciated.
UPDATE
I've made regex to ignore html tags and text between style tag and used it in query with REGEXP.
Now there are two problems,
I want to ignore these extra characters too. I know their UNICODEs, just need to know how to append it in the regex. This is my regex;
(?![^<]*>)(?!<style[^>]*?>)(TEXT)(?![^<]*?<\/style>)
I've used it in query like
SELECT text FROM dummy WHERE text REGEXP <myregex>
It's not giving an error but not returning the desired result too.
Answer to Original Question
NOTE: As I have recently learned it, I maybe wrong at many places, kindly correct my mistakes
There are two solutions
Use REGEXP Operator with SQLite Query
Implement your own User Defined Function using NDK
The problem with first one is that it returns either true or false but I need data. And the problem with both methods is that you have to use C/C++ Library in your Android Project. So I decided to create my own user defined function.
You can find many tutorials on how to use NDK in your project, but won't find any complete example of using 3rd Party libraries in your project.
After a lot of searching/studying, I combined things from many different places and was able to complete my task. Below are some steps on how you can do it. I also intend to write a complete step-by-step tutorial.
Getting things ready
First you need libraries which you want to use in your project. In my case, I need sqlite3 amalgamated library, which can be downloaded from here. Extract them in cpp folder of your project.
You might have familiar with CMakeLists.txt file by now when you included NDK in your project. It's time to add these libraries in CMakeLists.txt file. For that, go to your Project pane, you'll see External Build Files there and inside it you'll see the desired file. Open it and edit it as follows,
# Sets the minimum version of CMake required to build the native
# library. You should either keep the default value or only pass a
# value of 3.4.0 or lower.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds it for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
# Associated headers in the same location as their source
# file are automatically included.
src/main/cpp/native-lib.cpp )
include_directories(${CMAKE_SOURCE_DIR}/src)
add_library(sqlite3 STATIC src/main/cpp/sqlite3.c src/main/cpp/sqlite3.h src/main/cpp/sqlite3ext.h)
add_executable(sqlite src/main/cpp/sqlite3.c src/main/cpp/sqlite3.h src/main/cpp/sqlite3ext.h)
set_target_properties(sqlite PROPERTIES OUTPUT_NAME sqlite3)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because system libraries are included in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in the
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
sqlite3
log )
You have to first add libraries using add_library and then link it to your class which you've made, it is by default named native-lib.cpp.
Build your project and you are ready to go.
Implementing Function
Now here comes the main part. Open native-lib.cpp and include required files and headers. What you have to do;
Make a function which you will be calling from YourActivity.java. You'll know the pattern once you see your file. In my case it is Java_com_kfmwa916_testapp_SearchResult_createFunction(JNIEnv * env, jobject object, jstring search) where
Java is a keyword
com_kfmwa916_testapp is your package
SearchResult is your Java class
createFunction is the name of the function.
Create your function. In my case, I have to apply certain regex in search. Here is mine,
static void strip_text(sqlite3_context *context, int argc, sqlite3_value **argv) {
if(argc == 1) {
__android_log_print(ANDROID_LOG_VERBOSE, "TAG", "inside strip_text");
char *result = (char *) sqlite3_value_text(argv[0]);
std::string text(result);
std::regex regex_head("YOUR REGEX");
if (!text.empty()) {
text = std::regex_replace(text, regex_head, "");
sqlite3_result_text(context, text.c_str(), -1, SQLITE_TRANSIENT);
__android_log_print(ANDROID_LOG_VERBOSE, "STRIPPED TEXT", "%s", text.c_str());
return;
}
}
sqlite3_result_null(context);
}
Create sqlite3 instance, open database, attach this function to database and use it in your query. Here is a code snippet
extern "C"
void
Java_com_kfmwa916_testapp_SearchResult_createFunction(JNIEnv * env, jobject object, jstring search) {
const char * search_term = env->GetStringUTFChars(search, 0);
env->ReleaseStringUTFChars(search, search_term);
std::string q(search_term);
std::string query = "SELECT text FROM dummy WHERE LIKE('%" + q + "%', strip_text(text))=1";
__android_log_print(ANDROID_LOG_VERBOSE, "TAG", "%s", query.c_str());
//GetJStringContent(env, search, search_term);
sqlite3 *db;
//Open database
__android_log_print(ANDROID_LOG_VERBOSE, "TAG", "Opening database");
int rc = sqlite3_open("/data/data/com.kfmwa916.testapp/databases/MyDBName.db", &db);
//It'll be good to check 'rc' for error(s).
//Attach function to database
__android_log_print(ANDROID_LOG_VERBOSE, "TAG", "Attaching function");
rc = sqlite3_create_function(db, "strip_text", 1, SQLITE_ANY, NULL, &strip_text, NULL, NULL);
__android_log_print(ANDROID_LOG_VERBOSE, "TAG", "Executing query");
rc = sqlite3_exec(db, query.c_str(), callback, NULL, NULL);
}
Implement callback function to process result. It should look like
static int callback(void *NotUsed, int argc, char **argv, char **azColName) {
__android_log_print(ANDROID_LOG_VERBOSE, "TAG", "FOUND");
int i;
for (i = 0; i < argc; ++i) {
__android_log_print(ANDROID_LOG_VERBOSE, "TAG", "%s = %sn", azColName[i], argv[i] ? argv[i] : "NULL");
}
return 0;
}
Finally come to your Java class, in my case, it is SearchResult Load library and define function.
static {
System.loadLibrary("native-lib");
}
public native void createFunction(String search);
and call it where you want it. Let's say onClickEvent of a button like createFunction(searchterm)
Post is open for correction and modification.
I have integrated two native libraries (.so ) in my application. The libraries compile fine and I can load them in my application too. The first time I invoke a native method of a library it works fine, but if I call the same method again in the Activity the application shuts down.
The problem I am facing is exactly the same as mentioned in here :
http://grokbase.com/t/gg/android-ndk/1226m68ydm/app-exit-on-second-native-call
The solution that works is to invoke the native method in another Activity and shut it down forcefully via System.exit(0). Following the article I tried setting the pointers to NULL of the called method after a successful operation, but this too didn't help me. Also its not possible to unload a library once its loaded by System.loadLibrary().
I want to call the native methods more than once without creating a new Activity. Any ideas how to solve this issue ?
(I FINALLY FOUND A SOLUTION ... HERE IT IS)
Okay, I have finally found a way to resolve this issue. The solution is actually pretty simple. Build another independent native library (utility library) to load and unload the other libraries. What we need to do is use dlopen() and dlclose() in the native method of the utility. We can load the utility library like before via System.loadLibrary().
So in the native method of the utility library what we need to do is:
Use#include <dlfcn.h> // this is required to call dlopen() and dlclose() functions.
Provide handler and function prototype:
void *handle;
typedef int (*func)(int); // define function prototype
func myFunctionName; // some name for the function
Open the library via dlopen() :
handle = dlopen("/data/data/my.package.com/lib/somelibrary.so", RTLD_LAZY);
Get and Call the function of the library:
myFunctionName = (func)dlsym(handle, "actualFunctionNameInLibrary");
myFunctionName(1); // passing parameters if needed in the call
Now that the call is done. Close it via dlclose():
dlclose(handle);
Hope this will help others facing the same issue.
So ... my solution was starting a service that runs the shared library code, this service has a different process name ( you can set it in the Android Manifest ), as it is a different process you can kill it ( Using Process.killProcess(Process.myPid()) when it finishes running, without affecting your application in any way.
Worked very well for me, hope it helps someone else.
As this is the top hit for this issue and as the issue itself still exists, it seems that the approach that ZakiMak shared with us is still the most popular solution.
For others who may want to implement it and would like a little more detail for the latest Android releases, here are some notes I made as I stumbled through this:
Firstly, there is a solution which implements this approach on GitHub now. I have not tried it personally, but I have used it as a reference. It is very useful to see how the Android.mk file is structured and how the library is opened and methods called. Link is here: https://github.com/jhotovy/android-ffmpeg
The path to the native library folder changes over Android releases and it also appears to change every time you run the app (although this may be just in debug mode). Either way, it is best to pass the path in from the calling Java method if possible. For example:
In the Java wrapping class:
import android.content.Context;
import android.util.Log;
public class FfmpegJNIWrapper {
//This class provides a Java wrapper around the exposed JNI ffmpeg functions.
static {
//Load the 'first' or 'outer' JNI library so this activity can use it
System.loadLibrary("ffmpeg_wraper_multi_invoke_jni");
}
public static int call_ffmpegWrapper(Context appContext, String[] ffmpegArgs) {
//Get the native libary path
String nativeLibPath = appContext.getApplicationInfo().nativeLibraryDir;
//Call the method in the first or 'outer' library, passing it the
//native library past as well as the original args
return ffmpegWrapper(nativeLibPath, ffmpegArgs);
}
// Native methods for ffmpeg functions
public static native int ffmpegWrapper(String nativeLibPath, String[] argv);
}
In the 'first' or 'outer' native library:
JNIEXPORT jint JNICALL Java_com_yourpackage_androidffmpegwrapper_FfmpegJNIWrapper_ffmpegWrapper(JNIEnv *pEnv, jobject pObj, jstring nativeLibPath, jobjectArray javaArgv) {
//Get the second or 'inner' native library path
char* nativePathPassedIn = (char *)(*pEnv)->GetStringUTFChars(pEnv, nativeLibPath, NULL);
char ourNativeLibraryPath[256];
snprintf(ourNativeLibraryPath, sizeof (ourNativeLibraryPath), "%s%s", nativePathPassedIn, "/libffmpeg_wraper_jni.so"); //the name of your ffmpeg library
//Open the so library
void *handle;
typedef int (*func)(JNIEnv*, jobject, jobjectArray);
handle = dlopen(ourNativeLibraryPath, RTLD_LAZY);
if (handle == NULL) {
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "could not open library: %s", dlerror());
printf("Could not dlopen(\"libbar.so\"): %s\n", dlerror());
return(-1);
}
//Call the ffmpeg wrapper functon in the second or 'inner' library
func reenterable_ffmpegWrapperFunction;
reenterable_ffmpegWrapperFunction = (func)dlsym(handle, "Java_com_yourpackage_androidffmpegwrapper_FfmpegJNIWrapper_ffmpegWrapper");
reenterable_ffmpegWrapperFunction(pEnv, pObj, javaArgv); //the original arguments
//Close the library
dlclose(handle);
// return
return(1);
}
The Android.mk file is a little 'flaky' to put it politely. Because you are building two separate libraries in one Android.mk file, this may be a little more complex that other NDK make files so if you get some strange errors do some searching before you start taking your project apart. For example: https://stackoverflow.com/a/6243727/334402
Now I got a .so file and a C++ header file.
There is a function as follows:
BOOL __stdcall HK_STD_CreateHandle(IN PBYTE pFileHdrBuffer, IN DWORD dwFileHdrSize, IN DWORD dwBufferSize, OUT HANDLE& hHandle);
typedef BYTE * PBYTE;
typedef unsigned long DWORD;
typedef void * HANDLE;
I think I can implement a Java class to use the .so file:
public class Decoder {
static {
System.loadLibrary("SingleDecode");
}
public native boolean HK_STD_CreateHandle(
byte[] pFileHdrBuffer,
int dwFileHdrSize,
int dwBufferSize,
int hHandle);
}
But I don't know how to write the native function. Can anybody help me?
First of all your native function must have a certain name. For example, if you have a class MyActivity in the package com.android.test where you have declared the native method, the corresponding native function must be named:
Java_com_android_test_MyActivity_functionName();
Next, the native function must receive two additional arguments that are not explicitly defind by you (they're sent by the Java environment). I could explain it here, but it's probably easiest if you read up on JNI. Try Wikipedia for example:
http://en.wikipedia.org/wiki/Java_Native_Interface
There are also a few samples that comes with the NDK that will help you out.
I want to incorporate small, lean and mean C-based parser into my Android project. I've done JNI programming in the past but not any type of native (C) development on Android. My plan is to compile C lib into SO and create JNI wrapper around it which I'm going to use in my app. Is this how it can/should be done? Second and most important question - how can I include .so into my APK? Where would it go?
Depending on how much data you pass and how often I seriously doubt a Java/JNI/C would perform faster than a native java implementation.
Passing anything other than a "Java Int" to a "C long" invokes the JNI data conversion routines which are anything but lean and mean.
So unless your JNI routine fits the pattern:
Pass small amount of data.
Do lots and lots of work in C.
Pass small result set back.
You will be considerably slower than a native java implementation. If you stick with the basic "C" like java operations (+,-,*,==,>) using the "native" data types (int, char, String) and avoid the fancy libraries Java will perform nearly as fast as C.
The remaining bug-bear of java performance is the time taken to fire up the JVM and get everything going, but as you are starting off from a Java program this is a non issue.
The other reason for "slow" java performance is people insist on unnecessary factories, containers, xml beans etc. etc. where plain, simple methods would do the job better.
Create a JNI folder in your Android root Application folder(where there is src, res) .Place the code (1) there name it as someshared-lib.c.
(1)
Java_YourPackageName_YourClassNameWhereYoudeclareYourNativeFunction_NativeFuntionName(JNIEnv* env,jobject thiz)
{
//your c code , the JNI will act as a wrapper for it
return (*env)->NewStringUTF(env, "<string to pass or you can mention jchar * type string >");
}
(2)IN java file
package YourPackageName;
public class YourClassNameWhereYoudeclareYourNativeFunction extends Activity
{
public native String NativeFuntionName();
String returnValue = NativeFuntionName();
}
(3)IN Android.mk do this :
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := someshared-lib //note the libname same as c file name
LOCAL_SRC_FILES := someshared-lib.c //this is the file where you placed the code (1)
include $(BUILD_SHARED_LIBRARY)
export your ndk-build
(do export PATH=:$PATH
go to the JNI folder as created above :
execute ndk-build command
you will get a library formed someshared-lib in the lib folder formed in the Application root folder.While building and running the application this will get bundled up with the apk and will get installed in the device.To verify this you can go to the
/data/data/your_package_name/lib folder.
The app searched this lib in the /data/data/your_package_name/lib ( also /system/lib as well ) folder and use it for the dynamic calls(JNI) being made from the Android application.
Now if you want to return anything other than string you have to change the above method declration in c file as below :
Java_YourPackageName_YourClassNameWhereYoudeclareYourNativeFunction_NativeFuntionName(JNIEnv* env,jclass obj,jobject thiz)
{
jfieldID fid;
jboolean enable_flag;
//Pass the class object having all the variable from the android app to the JNI in the jclass obj and access its members using the field ID and using Get and Set firld ID.
clazz = (*env)->GetObjectClass(env, info);
fid = (*env)->GetFieldID(env,clazz,"some_variable","X"); //"X" - type of variable for boolean it //is Z , for INtezer it is I, for double it is D,
refer this document for detailed explaination
//for getting teh value fomr the JNI
enable_flag = (*env)->GetBooleanField(env, **thiz**, fid);
//for setting the value
fid = (*env)->GetFieldID(env,clazz,"other_float_variable","D");
(*env)->SetDoubleField(env,**thiz**,fid,other_float_variable);
}
Also in the Android Application you have to pass the Class object of the structure.
e.g
(2) will become now :
package YourPackageName;
public class YourClassNameWhereYoudeclareYourNativeFunction extends Activity
{
public native String NativeFuntionName();
String returnValue = NativeFuntionName( exampleStruct exst);
where exampleStruct :
public class exampleStruct {
protected boolean some_variable = 0;//no log saving by default
protected float other_float_variable = 0;
}
}
Hope this helps.
use Android NDK
Download n docs Android NDK 1.6
This will save you from writing JNI layer for lib and also will install the app in the lib folder of your app data folder.
Someone said that JNI in android sucks : http://www.koushikdutta.com/2009/01/jni-in-android-and-foreword-of-why-jni.html