Saving Files to Public Storage on Android Q (API 29)
Android Q (API 29) introduced significant changes to how apps can access external storage, enhancing user privacy and data control. Accessing public storage for writing files now requires specific permissions and adheres to a scoped storage model. This article outlines the steps and considerations for saving files to public storage in Android Q and above.
Understanding Scoped Storage
Scoped storage restricts apps to their designated storage areas (app-specific directories). This model enhances security and prevents data conflicts between apps. Accessing public storage, like the Downloads folder, involves requesting specific permissions and using designated system APIs.
Prerequisites
- Target API Level 29 or higher
- Manifest Permissions:
android.permission.WRITE_EXTERNAL_STORAGE
android.permission.READ_EXTERNAL_STORAGE
Saving Files using MediaStore API
1. Create a ContentResolver
ContentResolver resolver = getContentResolver();
2. Define the File’s Content URI
The content URI for the Downloads folder is: MediaStore.Downloads.EXTERNAL_CONTENT_URI
3. Prepare File Metadata
ContentValues values = new ContentValues();
values.put(MediaStore.Downloads.DISPLAY_NAME, "your_file_name.ext");
values.put(MediaStore.Downloads.MIME_TYPE, "mime/type");
values.put(MediaStore.Downloads.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);
4. Create the File
Uri contentUri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values);
5. Open an OutputStream
OutputStream outputStream = resolver.openOutputStream(contentUri);
6. Write File Data
// Write your file data to the outputStream
outputStream.write(fileData);
outputStream.close();
7. Handle Result
If successful, contentUri
will hold the URI of the newly created file in the Downloads folder.
Example Code
import android.content.ContentResolver;
import android.content.ContentValues;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
// ... within your activity or service
public void saveFileToDownloads(byte[] fileData, String fileName, String mimeType) {
ContentResolver resolver = getContentResolver();
ContentValues values = new ContentValues();
values.put(MediaStore.Downloads.DISPLAY_NAME, fileName);
values.put(MediaStore.Downloads.MIME_TYPE, mimeType);
values.put(MediaStore.Downloads.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);
Uri contentUri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values);
if (contentUri != null) {
try (OutputStream outputStream = resolver.openOutputStream(contentUri)) {
outputStream.write(fileData);
} catch (Exception e) {
// Handle error
}
} else {
// Handle failure to create file
}
}
Permissions
To use these APIs, you must declare the necessary permissions in your app’s manifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Important Considerations
- Target API Level: Ensure your app’s target API level is 29 or higher to use the MediaStore API for external storage.
- Runtime Permissions: Request the
READ_EXTERNAL_STORAGE
andWRITE_EXTERNAL_STORAGE
permissions at runtime using therequestPermissions()
method, as per best practices. - Data Security: Always consider data security when accessing external storage. Encrypt sensitive information before storing it in external storage.
Conclusion
Saving files to public storage in Android Q (API 29) and above requires specific permissions, utilizing the MediaStore API. By following these steps and adhering to the scoped storage model, you can safely and securely manage your app’s file storage access.