androidandroid-ndkscoped-storage

keeping file across android app uninstall/reinstall


I maintain a native app that has a thin Android layer. This app relies on a data file that has been in /sdcard, however starting with Android 11 scoped storage will be enforced, so /sdcard will either no longer be available or be scoped to the app if i understand correctly. So i migrated the file onto . (so it now resides in the files/ directory of the app).

However, if the user decides to uninstall and then reinstall the app (which may be done as a quasi-upgrade process) the files/ directory is erased and so is the data file.

Both getExternalStorageDirectory and getExternalStoragePublicDirectory are deprecated in API 29, the latter of which seemed to serve my needs.

So where can i put a file that will survive an uninstall if targeting Android 11?

This should be accessible through JNI in native code.

getExternalFilesDir states that these files will be deleted when the application is uninstalled so that's a no. Intents and MediaStore are also out since this is a native app.


After some experimenting, getStorageDirectory maps to /storage, which is owned by root, i'm not sure i could write there.

getDataDirectory maps to /data, owned by system, can't even list it, must have one of those com.my.app/0 subdirectory structures, so liable for deletion.

The deprecated getExternalStorageDirectory maps to /storage/emulated/0, which is /sdcard, so it may be a candidate so long as i keep using <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />. I hope. While i assume contents won't be deleted, i'm unsure if /sdcard will be accessible, although i'd assume getExternalStorageDirectory will, if not deprecated, even if pointing to the same location.
Oddly enough my test device is an Android 10 with API 29 and uses getExternalStorageDirectory just fine, but maybe that's because i'm targeting lower?

I'm trying to figure out how to pass Environment.DIRECTORY_DOCUMENTS onto the JNI call of getExternalStoragePublicDirectory, a bit unsuccessfully, and it's also flagged as deprecated.


Solution

  • Since getExternalStorageDirectory() is no longer deprecated i'm using that instead of hardcoded /sdcard.

    getExternalStoragePublicDirectory(String) keeps returning the same as getExternalStorageDirectory() + whichever string i pass it, which makes it rather useless.