0

This is my problem:

I get permission from the user to access storage in my app (READ/WRITE_EXTERNAL_STORAGE permission), my app saves a backup file on internal storage. My app can read that backup and restore it without any problems.

The problem is that if the user uninstalls and reinstalls the app , even if the app receives READ/WRITE_EXTERNAL_STORAGE permissions,my app can not restore that file anymore! because that file has not saved with the current version of the app. I know I can solve it by getting MANAGE_EXTERNAL_STORAGE permission, But because this is a sensitive permission, Google does not allow my application to have this permission and they will reject my app update with this permission.

Is there a way to solve this problem? It does not seem logical at all that my program can not be backed up and restored

farhad.kargaran
  • 2,233
  • 1
  • 24
  • 30
  • 1
    Use the Storage Access Framework (`ACTION_CREATE_DOCUMENT` / `ActivityResultContracts.CreateDocument` and `ACTION_OPEN_DOCUMENT` / `ActivityResultContracts.OpenDocument`). This allows the user to specify where on the user's device you should place the backup. It also requires no permissions. – CommonsWare Apr 03 '22 at 17:07
  • 1
    https://stackoverflow.com/questions/71725859/store-files-in-android-app-targeting-api-31-and-above-which-is-retained-even-a/71727689#71727689 – blackapps Apr 04 '22 at 04:47

1 Answers1

0

I find the answer, I should uses Storage Access Framework, It doesn't need any permission

Imagine we have saved JSON to a text file, here is the steps to restore data from it:

1- We need a method that displays a dialog to the user, so he/she can choose saved file:

private void openFile() {
    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    intent.setType("text/*");
    someActivityResultLauncher.launch(intent);
}

2- We should implement onActivityResult to get the uri of the file that user has selected, so add someActivityResultLauncher to activity class:

    ActivityResultLauncher<Intent> someActivityResultLauncher;

3- Add following methods to Activity class:

 private void registerActivityResult()
{
    someActivityResultLauncher = registerForActivityResult(
            new ActivityResultContracts.StartActivityForResult(),
            new ActivityResultCallback<ActivityResult>() {
                @Override
                public void onActivityResult(ActivityResult result) {
                    if (result.getResultCode() == Activity.RESULT_OK) {
                        // There are no request codes
                        Intent data = result.getData();
                        Uri uri = data.getData();
                            // Perform operations on the document using its URI.
                            try {
                                String txt = readTextFromUri(Setting_Activity.this, uri);
                                dorestore(txt);
                            }catch (Exception e){}

                    }
                }
            });
}

4- Call the above method in onCreate() method of activity:

@Override
protected void onCreate(Bundle savedInstanceState) {
    //......   
    registerActivityResult();
    //.....
 }

5- Implement the readTextFromUri() method we used in step 3:

public static String readTextFromUri(Context context, Uri uri) throws IOException {
    StringBuilder stringBuilder = new StringBuilder();
    try (InputStream inputStream =
                 context.getContentResolver().openInputStream(uri);
         BufferedReader reader = new BufferedReader(
                 new InputStreamReader(Objects.requireNonNull(inputStream)))) {
        String line;
        while ((line = reader.readLine()) != null) {
            stringBuilder.append(line);
        }
    }
    return stringBuilder.toString();
}

That's all, just implement the dorestore() method we used in step 3 to restore your json data. in mycase it looke something like this:

private void dorestore(String data)
{
    ArrayList<dbObject_user> messages = new ArrayList<>();
    try {
           JSONArray jsonArray = new JSONArray(data);
           //....
           //parsing json and saving it to app db....
           //....
     }
    catch (Exception e)
    {}
  }

just call the openFile() in step 1. That's all.

farhad.kargaran
  • 2,233
  • 1
  • 24
  • 30