简体   繁体   中英

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);
 }
}

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 .

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM