Finally I managed to solve the problem by mixing CommonsWare answer, this answer and this one. Thanks to all in advance!
Step by step solution:
First, let's start with some XML.
- Configure
AndroidManifest.xml
and add the following lines inside the <application>
section. I put them in between my </activity>
and </application>
closing tags, but please take this placement as my personal choice: it might not work for you depending on your manifest layout.
AndroidManifest.xml
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
As I am using API 29, I'm AndroidX libraries. In case you want to use it too consider running the AndroidX migration wizard by clicking Refactor > Migrate to AndroidX...
in Android Studio at your own risk.
- Now create a file in
/res/xml
with the name file_paths.xml
and fill it as follows:
file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
<cache-path name="my_sounds" path="/"/>
</paths>
Note the my_sounds
name is arbitrary. The /
in the path
field is where in the cache path your file will be stored. I just let it like that for the sake of ease. Should you not want to use a cache path, here is the complete list of available tags you can use.
Now we will head back to Java and start coding the method that will handle the sharing. First of all we need to copy the file in our resource folder to a File
object. This File
, however, needs to be pointing to a path created by the File Provider we configured in the XML part. Let's divide the tasks:
- Create an
InputStream
with your file's data and fill a File
with it with an auxiliary procedure.
public void handleMediaSend(int position)
File sound;
try {
InputStream inputStream = getResources().openRawResource(sounds.get(position).getSound()); // equivalent to R.raw.yoursound
sound = File.createTempFile("sound", ".mp3");
copyFile(inputStream, new FileOutputStream(sound));
} catch (IOException e) {
throw new RuntimeException("Can't create temp file", e);
}
Auxiliary procedure:
private void copyFile(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while((read = in.read(buffer)) != -1)
out.write(buffer, 0, read);
}
Now your resource has been successfully transferred to a cached directory (use the debugger to see which one) inside your Internal Storage.
- Get an
Uri
and share the File
.
final String AUTHORITY = BuildConfig.APPLICATION_ID + ".provider";
Uri uri = getUriForFile(getApplicationContext(), AUTHORITY, sound);
Intent share = new Intent(Intent.ACTION_SEND);
share.setType("audio/mp3"); // or whatever.
share.putExtra(Intent.EXTRA_STREAM, uri);
share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(Intent.createChooser(share, "Share"));
Putting it all together we will end up with this method:
Full method
public void handleMediaSend(int position) { // Depends on your implementation.
File sound;
try {
InputStream inputStream = getResources().openRawResource(sounds.get(position).getSound()); // equivalent to R.raw.yoursound
sound = File.createTempFile("sound", ".mp3");
copyFile(inputStream, new FileOutputStream(sound));
} catch (IOException e) {
throw new RuntimeException("Can't create temp file", e);
}
final String AUTHORITY = BuildConfig.APPLICATION_ID + ".provider";
Uri uri = getUriForFile(getApplicationContext(), AUTHORITY, sound);
Intent share = new Intent(Intent.ACTION_SEND);
share.setType("audio/mp3"); // or whatever.
share.putExtra(Intent.EXTRA_STREAM, uri);
share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(Intent.createChooser(share, "Share"));
}