I previously used external storage to store specific data that I would like to share between my applications (without having any contentprovider "host"), by using WRITE_EXTERNAL_STORAGE.
Not a media file, it is more like an encoded string in it.
It does not seem to be possible anymore on Android 11, without requesting MANAGE_EXTERNAL_STORAGE.
But this permission will not be granted by Google to all applications, and will require to fill a form, like everry "restricted permissions" (READ_CALL_LOG, READ_SMS, ACCESS_FINE_LOCATION, etc...) See support.google.com/googleplay/android-developer/answer/9888170
Exemple : By having XX applications, each one could be the first one to write a file (the first app used by the user basically), and the 3 other applications would read this file when started.
Any idea on how this can be achieved on Android 11? BlobManager seems to be appropriate but documentation is terrible (I tried it without success: new BlobStoreManager read write on Android 11)
private void writeFile(String data) {
try {
File f = new File(Environment.getExternalStorageDirectory(), FOLDER_NAME);
if (!f.exists()) {
boolean mkdirs = f.mkdirs();
if (!mkdirs) {
return;
}
}
File file = new File(f, FILE_NAME);
FileOutputStream outputStream = new FileOutputStream(file);
String encoded = Base64.encodeToString(data.getBytes(), Base64.DEFAULT);
outputStream.write(encoded.getBytes());
outputStream.close();
} catch (IOException e) {
Logger.e(TAG, "writeFile: IOException", e);
} catch (Exception e) {
Logger.e(TAG, "writeFile: Basic exception", e);
}
}
private String readFile() {
String data;
try {
File file = new File(Environment.getExternalStorageDirectory(), FOLDER_NAME + "/" + FILE_NAME);
if (!file.exists()) {
return "";
}
InputStream is = new FileInputStream(file);
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
String text = new String(buffer, Charset.forName("UTF-8"));
data = new String(Base64.decode(text, Base64.DEFAULT));
Logger.d(TAG, "readFile: decoded = " + data);
} catch (IOException e) {
Logger.e(TAG, "readFile: IOException", e);
return "";
} catch (IllegalArgumentException e) {
Logger.e(TAG, "readFile: Illegal Base64 import preset", e);
return "";
} catch (Exception e) {
Logger.e(TAG, "readFile: Basic exception", e);
return "";
}
return data;
}
EDIT: I tried some others solutions:
The External Public Storage way
An application "A" can write, and then read the file. But an other application "B" can not read the file written by "A"
I only get an access error: NotificationHelper - readFile: IOException java.io.FileNotFoundException: /storage/emulated/0/Download/myfolder/settings.bin: open failed: EACCES (Permission denied) at libcore.io.IoBridge.open(IoBridge.java:492) at java.io.FileInputStream.(FileInputStream.java:160)
file = new File (Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), FOLDER_NAME + "/" + FILE_NAME);
The mediastore way
But just with one app, I have issues: The app can not override a file writtend earlier, it creates multiple instance "my_file", "myfile(1), ..." And I have error when trying to read it:
java.io.FileNotFoundException: open failed: ENOENT (No such file or directory) at android.database.DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(DatabaseUtils.java:151) at android.content.ContentProviderProxy.openTypedAssetFile(ContentProviderNative.java:781) at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1986) at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1801) at android.content.ContentResolver.openInputStream(ContentResolver.java:1478) at fr.gg.frameworkmobile.utils.NotificationHelper.readFile(NotificationHelper.java:388)
private void writeFile(String data) {
String outputFilename = "my_file";
String outputDirectory = "my_sub_directory"; // The folder within the Downloads folder, because we use `DIRECTORY_DOWNLOADS`
ContentResolver resolver = AbstractMobileApplication.getInstance().getApplicationContext().getContentResolver();
ContentValues values = new ContentValues();
// save to a folder
values.put(MediaStore.Files.FileColumns.DISPLAY_NAME, outputFilename);
values.put(MediaStore.Files.FileColumns.MIME_TYPE, "application/my-custom-type");
values.put(MediaStore.Files.FileColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS + "/" + outputDirectory);
values.put(MediaStore.Files.FileColumns.IS_PENDING, 1);
Uri uri = resolver.insert(MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL), values);
// You can use this outputStream to write whatever file you want:
OutputStream outputStream = null;
Log.d(TAG, "writeFile: >>>>>>>>" + uri.getPath());
try {
outputStream = resolver.openOutputStream(uri);
String encoded = Base64.encodeToString(data.getBytes(), Base64.DEFAULT);
outputStream.write(encoded.getBytes());
outputStream.close();
values.clear();
values.put(MediaStore.Files.FileColumns.IS_PENDING, 0);
resolver.update(uri, values, null, null);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private String readFile() {
String data;
String outputFilename = "my_file";
String outputDirectory = "my_sub_directory"; // The folder within the Downloads folder, because we use `DIRECTORY_DOWNLOADS`
ContentResolver resolver = AbstractMobileApplication.getInstance().getApplicationContext().getContentResolver();
ContentValues values = new ContentValues();
// save to a folder
values.put(MediaStore.Files.FileColumns.DISPLAY_NAME, outputFilename);
values.put(MediaStore.Files.FileColumns.MIME_TYPE, "application/my-custom-type");
values.put(MediaStore.Files.FileColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS + "/" + outputDirectory);
Uri uri = resolver.insert(MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL), values);
// You can use this outputStream to write whatever file you want:
Log.d(TAG, "readFile: >>>>>>>>" + uri.getPath());
try {
InputStream is = resolver.openInputStream(uri);
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
String text = new String(buffer, Charset.forName("UTF-8"));
data = new String(Base64.decode(text, Base64.DEFAULT));
Logger.d(TAG, "readFile: decoded = " + data);
} catch (FileNotFoundException e) {
data = "";
e.printStackTrace();
} catch (IOException e) {
data = "";
e.printStackTrace();
}
return data;
}
from Use external storage to write file used by multiple applications on Android 11
No comments:
Post a Comment