Force access to external removable microSD card

后端 未结 3 1574
隐瞒了意图╮
隐瞒了意图╮ 2021-02-05 18:26

I\'m using a Samsung A3, Android 5.0.2. I\'m using this setup to compile apps, i.e. Android 4.1 Jelly Bean (API 16) target.

I precisely know the path of the external rem

3条回答
  •  栀梦
    栀梦 (楼主)
    2021-02-05 19:16

    As I struggled a lot with the same problem I'll share my bit. I have taken help from these resources big thanks to them as well:

    DocumentFile Android Docs and From Here

    I have tested the code on 5.1.1 and 6.0.1 not on rest of the device I have not tested it but it should work fine.

    On 5.0.2 to write on the external device you will have to ask user's permission.

    Using below code and before asking this permission you need to instruct the user to select the root sd card so that you will have the access to the entire external storage.

    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
    startActivityForResult(intent, 25);
    

    now in the onActivityResult save the UriTree return by the API as you will need it later.

     @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == 25&&resultCode == RESULT_OK) {
                getContentResolver().takePersistableUriPermission(data.getData(), Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        } 
        super.onActivityResult(requestCode, resultCode, data);
    }
    

    Once you have the root UriTree you can create modify delete files or directories from the external storage for that you will have get the DocumentFile from the UriTree.

    To get the Document UriTree used the below code.

    public static DocumentFile getDocumentFile(final File file) {
            String baseFolder = getExtSdCardFolder(file);
            String relativePath = null;
    
            if (baseFolder == null) {
                return null;
            }
    
            try {
                String fullPath = file.getCanonicalPath();
                relativePath = fullPath.substring(baseFolder.length() + 1);
            } catch (IOException e) {
                Logger.log(e.getMessage());
                return null;
            }
            Uri treeUri = Common.getInstance().getContentResolver().getPersistedUriPermissions().get(0).getUri();
    
            if (treeUri == null) {
                return null;
            }
    
            // start with root of SD card and then parse through document tree.
            DocumentFile document = DocumentFile.fromTreeUri(Common.getInstance(), treeUri);
    
            String[] parts = relativePath.split("\\/");
    
            for (String part : parts) {
                DocumentFile nextDocument = document.findFile(part);
                if (nextDocument != null) {
                    document = nextDocument;
                }
            }
    
            return document;
        }
    
    
        public static String getExtSdCardFolder(File file) {
            String[] extSdPaths = getExtSdCardPaths();
            try {
                for (int i = 0; i < extSdPaths.length; i++) {
                    if (file.getCanonicalPath().startsWith(extSdPaths[i])) {
                        return extSdPaths[i];
                    }
                }
            } catch (IOException e) {
                return null;
            }
            return null;
        }
    
    
    @TargetApi(Build.VERSION_CODES.KITKAT)
    public static String[] getExtSdCardPaths() {
        List paths = new ArrayList<>();
        for (File file : Common.getInstance().getExternalFilesDirs("external")) {
    
            if (file != null && !file.equals(Common.getInstance().getExternalFilesDir("external"))) {
                int index = file.getAbsolutePath().lastIndexOf("/Android/data");
                if (index < 0) {
                    Log.w("asd", "Unexpected external file dir: " + file.getAbsolutePath());
                } else {
                    String path = file.getAbsolutePath().substring(0, index);
                    try {
                        path = new File(path).getCanonicalPath();
                    } catch (IOException e) {
                        // Keep non-canonical path.
                    }
                    paths.add(path);
                }
            }
        }
        return paths.toArray(new String[paths.size()]);
    }
    

    Above code will return you the DocumentFile version of any file using that you can perform the desired operation.

    If you want to see this code in action check out I have used this in my open source project to modify the mp3 files present on the external storage.

    Hope it helps in case of doubts let me know.

    Forgot to tell I had asked the same question a while ago Here is that question.

    Edit: Using this code you can check if the user has given the permission on not

    public static boolean hasPermission() {
        List uriPermission = Common.getInstance().getContentResolver().getPersistedUriPermissions();
        return uriPermission != null && uriPermission.size() > 0;
    }
    

    if the permission is revoked then there will be no UriTree so you will have to ask for the permission again.

提交回复
热议问题