'Alternative to requestLegacyExternalStorage and MANAGE_EXTERNAL_STORAGE for Public Folders in Android 10/API 29?
I have an Android app on the play store that publishes data to a simple .txt file and lets you share using any other app of your choice. It used to write directly into the external storage, but now is uses the "Documents" public folder to stay compliant with the scoped storage requirements. I have successfully gotten it to work for every API except for 29; and I can tell what the problem is but have yet to find a workaround, and unfortunately I'm getting hit with angry reviews from Android 10 users because of this.
These are the 3 "solutions" I'm finding and what's wrong with them:
A) The usual way to write to public directories for Android 10 is to use requestLegacyExternalStorage, but this doesn't work if you target an SDK higher than 29. Google now requires all updates to target 30 or higher as of now. Because of this, it is guaranteed to ignore the flag.
B) I've already appealed to Google to allow use of permission MANAGE_EXTERNAL_STORAGE, to no avail.
C) I suppose I could change the directory to an app-specific folder that is accessible to other apps via the old files API. Such as method 2.1 in this guide. But I would prefer not to do this as I would like for the files to stay in place should the user uninstall and reinstall the app. Is this my only option?
In My Manifest:
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE"
android:maxSdkVersion="29"/>
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE"
android:maxSdkVersion="29"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="29"/>
<application
android:requestLegacyExternalStorage="true"
android:preserveLegacyExternalStorage="true"
>
And in my main activity where the file path is declared (skipping over other irrelevant bits):
public class Counting extends Activity {
String filename, path_string;
private static final int REQUEST_WRITE_STORAGE = 112;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent getTimes = getIntent();
filename = getTimes.getStringExtra("fileName");
int permission = ContextCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "Permission to record denied");
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Permission to access the SD-CARD is required for this app to
write text files.")
.setTitle("Permission required");
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Log.i(TAG, "Clicked");
makeRequest();
}
});
AlertDialog dialog = builder.create();
dialog.show();
} else {
makeRequest();
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){
path_string = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS) + "/appname";
}
else {
path_string = Environment.getExternalStorageDirectory().getAbsolutePath() + "/appname";
}
File path = new File(path_string);
path.mkdirs();
Log.d("TAG", "mkdirs called=" + String.valueOf(path.mkdirs()));
String adjustedName = filename.replaceAll("[\\\\/:*?\"<>|]", "");
File file = new File(path, adjustedName + ".txt");
try {
FileOutputStream fos = new FileOutputStream(file);
fos.write(initialTemplate.getBytes());
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
protected void makeRequest() {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_WRITE_STORAGE);
}
}
Solution 1:[1]
Because of this, it is guaranteed to ignore the flag
Android 10 will honor the flag. Newer versions of Android will not (Android 11 and up), because of the targetSdkVersion
.
Solution 2:[2]
If you want to write & delete the media files in android 10 or above, You can do it easily.
Just need to use some new APIs & you also have to declare the write external storage permission like this
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29" />
Use 'android:requestLegacyExternalStorage="true"' for android 10.
For android 11 and above, check out this - Scoped Storage in Android — Writing & Deleting Media Files
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | CommonsWare |
Solution 2 | Dev4Life |