2

The question is nearly the same as "android ndk data save/load" which has a very good and satisfying answer if you developing a native only app. But I am writing a native library. Okay, back to the Problem:

I write a library for Java which handles my server connection. In the library I want to load and save binary data which is related to the App. In the answer above there is a good way, the "internalDataPath". Unfortunately it is part of the

struct android_app* state

which I do not have as library as it is a parameter given to a native main fuction. All I have is

JNIEnv *

and

JavaVM *

how do I get the internalDataPath from one of them?

Community
  • 1
  • 1
Martin Schlott
  • 4,369
  • 3
  • 25
  • 49

3 Answers3

1

I believe this has been covered before, but the usual recommendation is to obtain the path to internal or external storage using a Java API - either pass that into your native code in the first call you make, or use JNI "in reverse" to call the Java API from the native code (though you may need a Context for that).

Chris Stratton
  • 39,853
  • 6
  • 84
  • 117
1

The main problem is the missing activity object which is given to you via the android_app structure in your main if you make a pure NDK solution. If you only want to make a library which can used by a Java developer, you have no access to the main-activity without given to you by a call. Or, to be more precise, I did not found a way to get the main-activity of a Java App from my c++ code. This leaves me to two options:

1) Use getFilesPath called from java and make it part of a method call of the c++ object (maybe "Init")

2) Give the main-activity to the C++ code (maybe in "init").

I decided for the second one. First I didn't want to give control to the programmer of the Java part where to put what. Second, I got the feeling that I will need the activity for some more reasons.

So I ended at a code snipped from Jong Wook Kim which I modified for my needs:

void here_your_ndk_conform_name_init(JNIEnv* env,jobject mainactivity)
{
     jclass cls = env->GetObjectClass(mainactivity);
     jmethodID getFilesDir = env->GetMethodID(cls, "getFilesDir", "()Ljava/io/File;");
     jobject dirobj = env->CallObjectMethod(mainactivity,getFilesDir);
     jclass dir = env->GetObjectClass(dirobj);
     jmethodID getStoragePath =
                           env->GetMethodID(dir, "getAbsolutePath", "()Ljava/lang/String;");
     jstring path=(jstring)env->CallObjectMethod(dirobj, getStoragePath);
     const char *pathstr=env->GetStringUTFChars(path, 0);
     std::string strPath=pathstr;
     env->ReleaseStringUTFChars(path, pathstr);
}

where strPath now has the path to your internal storage which you can freely access with iostreams.

Martin Schlott
  • 4,369
  • 3
  • 25
  • 49
-1

If the data is application-specific, it is good practice to let the app decide where its data is stored. If the data is "private" to the library (especially if it is relevant across different apps that may use your library on the same device), feel free to choose a subdirectory of /sdcard/data. Note that this way you force the applications to request relevant permissions.

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307