I am currently working on a C-base开发者_开发问答d, NDK-based, Android application. This application needs to create temporary files. On a regular Linux system, I would use tmpfile
to ensure that these files are properly created in a temporary directory and cleaned-up at process end.
However, my investigations on various Android devices seem to indicate that
tmpfile
always fails;- there is no
/tmp
directory; - directory
/data/local/tmp
isn't present on all variants of Android; - there is no
TEMP
environment variable set; mkstemp
doesn't work any better thantmpfile
.
Now, I'm sure that I could hack something together, but seeing that the SDK offers context.getCacheDir
and File.createTempFile
for Java applications, I hope that there is an equivalent at C-level.
Does anyone know of a good reliable and cross-Android method for creating a temporary file?
The best way we've found is to call Context.getCacheDir
on startup, get its path with getAbsolutePath
, then call a JNI function to store that path in a global. Any function that wants to create a temporary file simply appends a suitable temporary file name to that path.
If you really want to fetch it from JNI another alternative would be to pass in a Context
to a JNI function and use a bunch of GetMethodID
/ CallObjectMethod
stuff to call back into Java to getCacheDir
, but the former approach is a lot simpler.
Unfortunately, there does not appear to be a more elegant solution at the moment.
Below is the GetMethodID / CallObjectMethod procedure that Ertebolle refers to. It is necessary if you are working with a pure native app (such as built by Visual Studio 2015) and cannot use java code.
std::string android_temp_folder( struct android_app *app ) {
JNIEnv* env;
app->activity->vm->AttachCurrentThread( &env, NULL );
jclass activityClass = env->FindClass( "android/app/NativeActivity" );
jmethodID getCacheDir = env->GetMethodID( activityClass, "getCacheDir", "()Ljava/io/File;" );
jobject cache_dir = env->CallObjectMethod( app->activity->clazz, getCacheDir );
jclass fileClass = env->FindClass( "java/io/File" );
jmethodID getPath = env->GetMethodID( fileClass, "getPath", "()Ljava/lang/String;" );
jstring path_string = (jstring)env->CallObjectMethod( cache_dir, getPath );
const char *path_chars = env->GetStringUTFChars( path_string, NULL );
std::string temp_folder( path_chars );
env->ReleaseStringUTFChars( path_string, path_chars );
app->activity->vm->DetachCurrentThread();
return temp_folder;
}
As far as I know there is no global /tmp in android, you should use the cache dir. Use getCacheDir() to get the "tmp" dir.
http://developer.android.com/guide/topics/data/data-storage.html#filesInternal and http://developer.android.com/reference/android/content/Context.html#getCacheDir%28%29
mkstemp is available in the NDK under stdlib.h
- Obtain path to cache directory on application's startup using a ContentProvider.
- Implement tmpfile function with the same signature as POSIX's tmpfile.
- Call mkstemp from your tmpfile function using the previously obtained cache directory
Packaged it as .aar, so it could be consumed through gradle.
https://github.com/ViliusSutkus89/tmpfile-Android
精彩评论