开发者

Creating temporary files in Android with NDK

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 than tmpfile.

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


  1. Obtain path to cache directory on application's startup using a ContentProvider.
  2. Implement tmpfile function with the same signature as POSIX's tmpfile.
  3. 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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜