I spent literally several hours searching (and trying) different ways to write some files to my 4.4-bit SD card with Android KitKat after receiving countless permission permissions errors. It seems that now Google has limited access to the file system on SD cards, which you are forced to write only to directories belonging to the application (for example: /Android/data/com.mycompany.myapp/files/).
Finally, I was able to get something working that creates a directory on a removable SD card that you can write to. However, I am curious why, in order to access this own directory on a removable SD card, I first had to create a new file object using the path to the external directory?
My implementation:
First, I create two globals for placing lines of both external and removable paths.
MainActivity
public class MainActivity extends ActionBarActivity { String externalStorageDirectory;
Then I ask the system what are called by the manufacturer’s specific directories and begin concatenating the absolute paths for both externalStorage variables and removable variables. I also create a new File object initialized with the directory path belonging to the external application.
onCreate()
externalStorageDirectory = this.getExternalFilesDir(null).toString();//build absolute path to the app owned external directory File folder = new File(externalStorageDirectory ); //THIS LINE IS CRUCIAL!! Log.d("DEBUG", " - External Path" + externalStorageDirectory );// "/storage/emulated/0/Android/data/com.mycompany.myapp/files" String ownedDirectory = "/Android/data/" + this.getPackageName() + "/files/"; secondaryStorageDirectory = System.getenv("SECONDARY_STORAGE").toString() + ownedDirectory;//build absolute path to the app owned removable directory Log.d("DEBUG", " - Removable Path"+secondaryStorageDirectory );// "/storage/external/Android/data/com.mycompany.myapp/files/"
Finally, I was able to write the file to a directory accessible for use with the SD card. And, more specifically, I used AsyncTask to upload my files and save them, method # 1 of this post .
doInBackground()
output = new FileOutputStream(secondaryStorageDirectory + "myawesomefile.mp4");
Then I managed to navigate to the removable SD card directory through the adb shell, and I could see my file.
Adb shell output:
//internal storage shell@QTAQZ3 :/storage/emulated/0/Android/data/com.mycompany.myapp/files $ ls s < //removable SD card shell@QTAQZ3 :/storage/external/Android/data/com.mycompany.myapp/files $ ls ls myawesomefile.mp4 <
And just a little repeat:
File folder = new File(externalStorageDirectory); //THIS LINE IS CRUCIAL!! File folder = new File(secondaryStorageDirectory ); //THIS LINE DOES NOTHING?
So my questions are:
- When I instantiate a File object, what happens, what makes these directories accessible?
- Why does calling mkdir () or mkdirs () seem unnecessary in this case, when magic objects appear when creating a file object?
- And why can I see the secondary (removable) directory of my application only after I installed the file on an external (non-removable) path?
Admittedly, I'm relatively new to Android programming, so I'm not even sure if this approach is right or just a successful hack? But now it works in my application.