TL;DR
I wanna get(read/generate) file Uri -- with path like below -- by FileProvider, but don't know how:
val file = File("/external/file/9359") // how do I get its Uri then?
All I know was FileProvider.getUriForFile method, but it throws exception.
What I was doing
I was trying to mock a download progress -- create a file in Download folder, and then pass it to ShareSheet to let user do whatever it want to do.
What I have done:
- Create file in
Downloadby usingMediaStoreandContentResolver. - Have a
ShareSheetutil function. - Registered
FileProviderandfilepath.xml.
In my case, I want to share the file via ShareSheet function, which requires
- The Uri of
File
but the usual file.toUri() will throw exception above SDK 29. Hence I change it into FileProvider.getUriForFile() as Google-official recommended.
The Direct Problem Code
val fileUri: Uri = FileProvider.getUriForFile(context, "my.provider", file)
Will throw exception:
java.lang.IllegalArgumentException: Failed to find configured root that contains /external/file/9359
My File Creation Code
val fileUri: Uri? = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, "test.txt")
put(MediaStore.MediaColumns.MIME_TYPE, "text/plain")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// create file in download directory.
put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)
}
}.let { values ->
context.contentResolver.insert(MediaStore.Files.getContentUri("external"), values)
}
if (fileUri == null) return
context.contentResolver.openOutputStream(fileUri)?.use { fileOut ->
fileOut.write("Hello, World!".toByteArray())
}
val file = File(fileUri.path!!) // File("/external/file/9359")
I can assure the code is correct because I can see the correct file in Download folder.
My FileProvider Setup
I have registered provider in AndroidManifest.xml:
<application>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="my.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepath" />
</provider>
</application>
with filepath.xml below:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external"
path="." />
</paths>
I've also tried so many path variants, one by one:
<external-files-path name="download" path="Download/" />
<external-files-path name="download" path="." />
<external-path name="download" path="Download/" />
<external-path name="download" path="." />
<external-path name="external" path="." />
<external-files-path name="external_files" path="." />
I also even registered external storage reading permissions:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
which part did I do wrong?
Edit 1
After posting, I thought the File initialization might be the problem:
File(fileUri.path!!)
So I changed it to
File(fileUri.toString())
but still not working.
Their content difference is below btw:
fileUri.path -> /external/file/9359
(file.path) -> /external/file/9359
error -> /external/file/9359
fileUri.toString() -> content://media/external/file/9359
(file.path) -> content:/media/external/file/9359
error -> /content:/media/external/file/9359
Edit 2
What I originally wanted to achieve is sending binary data to other app. As Official-documented, it seems only accept nothing but file Uri.
I'd be appreciate if there's any other way to achieve this, like share the File directly, etc.
But what I'm wondering now is simple -- How do I make FileProvider available to get/read/generate file Uri like /external/file/9359 or so on? This might comes in help not only this case, and seems like a more general/basic knowledge to me.