[Android]Copy the files from the app’s specific folder to your Downloads folder.

この記事は約10分で読めます。
スポンサーリンク

Things I want to do

The files created in the unique folder (\Android\data\package name) of the Android app are copied to the user’s download folder.

In modern Android development, java.io.File Travel using this method has become difficult. Android 10 (API 29) and laterIntroducedScoped Storage As a result, access permissions to external storage have become stricter.

This article discusses the private area of ​​Android apps./date/date/... or /Android/data/.../files)from,WRITE_EXTERNAL_STORAGE Without requiring much authority, a secure area for sharing files (DownloadThis explains how to move it to ).

background

In previous versions of Android, apps were once WRITE_EXTERNAL_STORAGE Once I obtained the necessary permissions, I could write files to almost anywhere on the external storage.

However, with the introduction of Scoped Storage, each app can use its own private space,MediaStore A specific shared collection managed by (Pictures, DownloadAccess has been restricted to only (etc.).

In other words, apps can no longer arbitrarily place files in other apps’ folders or in arbitrary locations on shared storage.

This is a simple way to move files from a private area to a user’s shared area. File.renameTo() or File.copy() These are the main reasons why it cannot be used.

What will you use it for?

During processing, the files are handled in a private folder, and after completion, they are moved to a folder accessible to the user (for downloads, etc.).

Move files from the Private folder to a user-accessible folder (archive them) for backup purposes.

スポンサーリンク

implementation

Implement it as follows:

(This is implemented as a method of the Activity.)

import android.provider.MediaStore;
import android.content.ContentValues; 
import android.os.Environment;

    public void moveFileToDownloads( Path privatePath) {
        File privateFile = privatePath.toFile();
        ContentValues values = new ContentValues();
        values.put(MediaStore.MediaColumns.DISPLAY_NAME, privateFile.getName());
        values.put(MediaStore.MediaColumns.MIME_TYPE, "application/zip");

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
            values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS + File.separator + APPNAME);
        }

        ContentResolver resolver = this.getContentResolver();
        Uri uri = null;

        try {
            uri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values);
            if (uri == null) {
                throw new RuntimeException("MediaStore insert failed.");
            }

            try (OutputStream os = resolver.openOutputStream(uri);
                 FileInputStream is = new FileInputStream(privateFile)) {
                if (os == null) {
                    throw new RuntimeException("Failed to open output stream.");
                }

                byte[] buffer = new byte[4096];
                int length;
                while ((length = is.read(buffer)) > 0) {
                    os.write(buffer, 0, length);
                }

                privateFile.delete();
            }
        } catch (Exception e) {
            e.printStackTrace();
            if (uri != null) {
                resolver.delete(uri, null, null);
            }
        }
    }

The argument `privatePath` is the path to the file to be moved to the Downloads folder.

If you are storing the file path as a String, you can convert it using `Path path = Paths.get(pathString);`.

Code explanation

        ContentValues values = new ContentValues();
        values.put(MediaStore.MediaColumns.DISPLAY_NAME, privateFile.getName());
        values.put(MediaStore.MediaColumns.MIME_TYPE, "application/zip");

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
            values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS + File.separator + APPNAME);
        }

Creating ContentValues ​​(information about the saved file). Please change the MIME_TYPE as needed.

The APPNAME part in values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS + File.separator + APPNAME); is the name of the folder to be created in the Download folder. If you are saving directly to the Download folder, Environment.DIRECTORY_DOWNLOADS is fine.

        ContentResolver resolver = this.getContentResolver();
        Uri uri = null;

        try {
            uri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values);
            if (uri == null) {
                throw new RuntimeException("MediaStore insert failed.");
            }

Create a resolver and obtain the URI (the path for saving).

                byte[] buffer = new byte[4096];
                int length;
                while ((length = is.read(buffer)) > 0) {
                    os.write(buffer, 0, length);
                }

                privateFile.delete();

This code copies the contents of a file and deletes the original file. If you are copying and not moving the file, do not call `privateFile.delete();`.

        } catch (Exception e) {
            e.printStackTrace();
            if (uri != null) {
                resolver.delete(uri, null, null);
            }
        }

This is error handling. `resolver.delete(uri, null, null);` deletes the failed file in the Download folder.

コメント

タイトルとURLをコピーしました