我在 Kotlin 中为 flutter 应用程序编写了一个功能,可以将媒体文件直接从 Android 手机图库共享到应用程序。
在我测试过的许多设备上运行良好,例如 Realme 3 Pro、Oneplus 6t、Samsung m40。
但是,对于
Asus Zenfone Max Pro M2
来说,共享任何媒体文件都会收到奇怪且不完整的 URI
和 path
来自 Kotlin 代码的日志
D/URI =====(26032) : content://com.android.providers.downloads.documents/document/624
D/路径 =====(26032): /document/624
Kotlin 代码
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
this.binding = binding
binding.addOnNewIntentListener(this)
handleIntent(binding.activity.intent, true)
}
----------------------------------------------------------------------
private fun handleIntent(intent: Intent, initial: Boolean) {
when {
(intent.type?.startsWith("text") != true)
&& (intent.action == Intent.ACTION_SEND
|| intent.action == Intent.ACTION_SEND_MULTIPLE) -> { // Sharing images or videos
val value = getMediaUris(intent)
if (initial) initialMedia = value
latestMedia = value
eventSinkMedia?.success(latestMedia?.toString())
}
...
----------------------------------------------------------------------
private fun getMediaUris(intent: Intent?): JSONArray? {
if (intent == null) return null
return when (intent.action) {
Intent.ACTION_SEND -> {
val uri = intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
Log.d("URI =====",uri)
val path = uri?.let{ FileDirectory.getPathFromUri(applicationContext, it) } ?: uri?.path
Log.d("Path =====",path)
if (path != null) {
...
设备信息
Device Name: Asus Zenfone Max Pro M2
Android Version: 9
External SD card: present
如何解析此 URI 并获取包含文件名和扩展名的正确路径?
您可以使用 uri_to_file 插件从
content://uri
获取路径。使用时,只需解析 uri 并使用 toFile(uri)
import 'package:uri_to_file/uri_to_file.dart';
try {
String uriPath = 'content://com.android.providers.downloads.documents/document/624';
Uri uri = Uri.parse(uriPath);
File file = await toFile(uri);
} catch (e) {
debugPrint(e);
}
更新 getMediaUris
private fun getMediaUris(intent: Intent?): JSONArray? {
if (intent == null) return null
return when (intent.action) {
Intent.ACTION_SEND -> {
val uri = intent.getParcelableExtra<Uri>(Intent.EXTRA_STREAM)
uri?.let {
val path = FileDirectory.getPathFromUri(applicationContext, it)
?: getFilePathFromURI(it) // Fallback if path is null
Log.d("Path =====", path)
}
// Continue with the rest of your logic
}
else -> null
}
}
创建辅助函数
private fun getFilePathFromURI(uri: Uri): String? {
return if (DocumentsContract.isDocumentUri(applicationContext, uri)) {
when (uri.authority) {
"com.android.providers.media.documents" -> {
val documentId = DocumentsContract.getDocumentId(uri)
val split = documentId.split(":")
val type = split[0]
val contentUri = when (type) {
"image" -> MediaStore.Images.Media.EXTERNAL_CONTENT_URI
"video" -> MediaStore.Video.Media.EXTERNAL_CONTENT_URI
"audio" -> MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
else -> null
}
contentUri?.let {
val selection = "_id=?"
val selectionArgs = arrayOf(split[1])
getColumnData(it, selection, selectionArgs)
}
}
"com.android.providers.downloads.documents" -> {
val documentId = DocumentsContract.getDocumentId(uri)
val contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), documentId.toLong()
)
getColumnData(contentUri, null, null)
}
else -> null
}
} else {
null
}
}
private fun getColumnData(uri: Uri, selection: String?, selectionArgs: Array<String>?): String? {
val projection = arrayOf(MediaStore.MediaColumns.DATA)
contentResolver.query(uri, projection, selection, selectionArgs, null)?.use { cursor ->
if (cursor.moveToFirst()) {
val columnIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA)
return cursor.getString(columnIndex)
}
}
return null
}
并检查这一点
<application
android:requestLegacyExternalStorage="true"
... >
</application>