Xamarin.Plugin.FilePicker - 内容:/com.android.providers.downloads.documents 问题
Xamarin.Plugin.FilePicker - content:/com.android.providers.downloads.documents Problem
我正在使用 Xamarin.Plugin.FilePicker(版本是:2.1.41)。它在 android 10 个设备中给了我这样的路径:
内容://com.android.providers.downloads.documents/document/3025 或
内容://com.android.providers.downloads.documents/document/msf:14
我正在尝试通过这种方式获取真实文件路径:
public class StorageFolderPath : IStorageFolderPath
{
public string SDCardPath(string path)
{
Android.Net.Uri uri = Android.Net.Uri.Parse(path);
bool isKitKat = Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Kitkat;
if (isKitKat && DocumentsContract.IsDocumentUri(MainActivity.MainContext, uri))
{
if (isExternalStorageDocument(uri))
{
//...
}
else if (isDownloadsDocument(uri))
{
string id = DocumentsContract.GetDocumentId(uri);
Android.Net.Uri contentUri = ContentUris.WithAppendedId(
Android.Net.Uri.Parse("content://downloads/public_downloads"), ContentUris.ParseId(uri));
return getDataColumn(MainActivity.MainContext, contentUri, null, null);
}
//...
}
}
public static String getDataColumn(Context context, Android.Net.Uri uri, String selection, String[] selectionArgs)
{
ICursor cursor = null;
String column = "_data";
String[] projection =
{
column
};
try
{
cursor = context.ContentResolver.Query(uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.MoveToFirst())
{
int index = cursor.GetColumnIndexOrThrow(column);
return cursor.GetString(index);
}
}
finally
{
if (cursor != null)
cursor.Close();
}
return null;
}
public static bool isDownloadsDocument(Android.Net.Uri uri)
{
return "com.android.providers.downloads.documents".Equals(uri.Authority);
}
public bool DownloadsDocumentControl(string path)
{
Android.Net.Uri uri = Android.Net.Uri.Parse(path);
return isDownloadsDocument(uri);
}
}
共享代码:
public async Task UploadFileAsync(UploadRequest upload_request)
{
string newPath = "";
if (Device.RuntimePlatform == Device.Android &&
(DependencyService.Get<IStorageFolderPath>().ExternalStorageDocumentControl(upload_request.Properties.FilePath) ||
DependencyService.Get<IStorageFolderPath>().DownloadsDocumentControl(upload_request.Properties.FilePath)))
newPath = DependencyService.Get<IStorageFolderPath>().SDCardPath(upload_request.Properties.FilePath);
else
newPath = upload_request.Properties.FilePath;
Stream stream = File.OpenRead(newPath);
//...
}
当我这样做时:
如果路径是 content://com.android.providers.downloads.documents/document/msf:14,app 会抛出这个错误:
{Java.Lang.NumberFormatException: For input string: "msf:14"
at Java.Interop.JniEnvironment+StaticMethods.CallStaticLongMethod (Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x0006e] in <42748fcc36b74733af2d9940a8f3cc8e>:0
at Java.Interop.JniPeerMembers+JniStaticMethods.InvokeInt64Method (System.String encodedMember, Java.Interop.JniArgumentValue* parameters) [0x00018] in <42748fcc36b74733af2d9940a8f3cc8e>:0
at Android.Content.ContentUris.ParseId (Android.Net.Uri contentUri) [0x00031] in <7d2292394f8c488b97f5bc2a0ac0240d>:0
at FileOrbis.Droid.Services.StorageFolderPath.SDCardPath (System.String path) [0x0017c] in C:\Users\Deytek\Desktop\GitWorkspace\FileorbisMobil\FileOrbis\FileOrbis.Android\Services\StorageFolderPath.cs:91
at FileOrbis.Services.AllFileUploadService.UploadFileAsync (FileOrbis.Models.RequestModels.UploadRequest upload_request) [0x000ae] in C:\Users\Deytek\Desktop\GitWorkspace\FileorbisMobil\FileOrbis\FileOrbis\Services\AllFileUploadService.cs:69
--- End of managed Java.Lang.NumberFormatException stack trace ---
java.lang.NumberFormatException: For input string: "msf:14"
at java.lang.Long.parseLong(Long.java:594)
at java.lang.Long.parseLong(Long.java:636)
at android.content.ContentUris.parseId(ContentUris.java:89)
}
(应用程序在此行崩溃:(ContentUris.ParseId(uri))
Android.Net.Uri contentUri = ContentUris.WithAppendedId(
Android.Net.Uri.Parse("content://downloads/public_downloads"), ContentUris.ParseId(uri));)
如果路径是 content://com.android.providers.downloads.documents/document/3025 ,应用会抛出这个错误:
{System.IO.DirectoryNotFoundException: Could not find a part of the path "/content:/com.android.providers.downloads.documents/document/3025".
at System.IO.FileStream..ctor (System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share, System.Int32 bufferSize, System.Boolean anonymous, System.IO.FileOptions options) [0x00177] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/corlib/System.IO/FileStream.cs:223
at System.IO.FileStream..ctor (System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share) [0x00000] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/corlib/System.IO/FileStream.cs:91
at (wrapper remoting-invoke-with-check) System.IO.FileStream..ctor(string,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare)
at System.IO.File.OpenRead (System.String path) [0x00000] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/external/corefx/src/System.IO.FileSystem/src/System/IO/File.cs:266
at FileOrbis.Services.AllFileUploadService.UploadFileAsync (FileOrbis.Models.RequestModels.UploadRequest upload_request) [0x000de] in C:\Users\Deytek\Desktop\GitWorkspace\FileorbisMobil\FileOrbis\FileOrbis\Services\AllFileUploadService.cs:73 }
注意:
我添加到清单文件:
<application android:requestLegacyExternalStorage="true">
</application>
我必须在 Android 10 台设备上解决这个问题? (我没有在所有 android 10 台设备上遇到此问题。我在三星 Galaxy S10 - 模拟器、华为 P20 Lite - 真实 phone 或 Galaxy S20 - 真实 phone 上遇到)
blackapps说的是真的。 Already FilePicker plugin has notified that is possible.但我现在看到了。
从内容方案中获取实际路径不是正确的方法,也不可能。
这就是为什么我必须像这样在我的代码中编写 if 条件:
Stream stream = null;
if (Device.RuntimePlatform == Device.Android && DependencyService.Get<IStorageFolderPath>().DownloadsDocumentControl(newPath))
stream = DependencyService.Get<IStorageFolderPath>().GetFileFromUri(newPath);
else
stream = File.OpenRead(newPath);
public Stream GetFileFromUri(string path)
{
Android.Net.Uri uri = Android.Net.Uri.Parse(path);
var stream = MainActivity.MainContext.ContentResolver.OpenInputStream(uri);
return stream;
}
您可以查询文件名,然后构建路径。
查询文件名:
public static string getFileName(Context context, Android.Net.Uri uri)
{
ICursor cursor = null;
string[] projection = {
MediaStore.MediaColumns.DisplayName
};
try
{
cursor = context.ContentResolver.Query(uri, projection, null, null,
null);
if (cursor != null && cursor.MoveToFirst())
{
int index = cursor.GetColumnIndexOrThrow(MediaStore.MediaColumns.DisplayName);
return cursor.GetString(index);
}
}
finally
{
if (cursor != null)
if (cursor != null)
{
cursor.Close();
}
}
return null;
}
构建路径:
else if (isDownloadsDocument (uri)) {
string fileName = getFileName(context, uri);
string filePath = Android.OS.Environment.ExternalStorageDirectory + "/Download/" + fileName;
return filePath;
}
我正在使用 Xamarin.Plugin.FilePicker(版本是:2.1.41)。它在 android 10 个设备中给了我这样的路径: 内容://com.android.providers.downloads.documents/document/3025 或 内容://com.android.providers.downloads.documents/document/msf:14
我正在尝试通过这种方式获取真实文件路径:
public class StorageFolderPath : IStorageFolderPath
{
public string SDCardPath(string path)
{
Android.Net.Uri uri = Android.Net.Uri.Parse(path);
bool isKitKat = Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Kitkat;
if (isKitKat && DocumentsContract.IsDocumentUri(MainActivity.MainContext, uri))
{
if (isExternalStorageDocument(uri))
{
//...
}
else if (isDownloadsDocument(uri))
{
string id = DocumentsContract.GetDocumentId(uri);
Android.Net.Uri contentUri = ContentUris.WithAppendedId(
Android.Net.Uri.Parse("content://downloads/public_downloads"), ContentUris.ParseId(uri));
return getDataColumn(MainActivity.MainContext, contentUri, null, null);
}
//...
}
}
public static String getDataColumn(Context context, Android.Net.Uri uri, String selection, String[] selectionArgs)
{
ICursor cursor = null;
String column = "_data";
String[] projection =
{
column
};
try
{
cursor = context.ContentResolver.Query(uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.MoveToFirst())
{
int index = cursor.GetColumnIndexOrThrow(column);
return cursor.GetString(index);
}
}
finally
{
if (cursor != null)
cursor.Close();
}
return null;
}
public static bool isDownloadsDocument(Android.Net.Uri uri)
{
return "com.android.providers.downloads.documents".Equals(uri.Authority);
}
public bool DownloadsDocumentControl(string path)
{
Android.Net.Uri uri = Android.Net.Uri.Parse(path);
return isDownloadsDocument(uri);
}
}
共享代码:
public async Task UploadFileAsync(UploadRequest upload_request)
{
string newPath = "";
if (Device.RuntimePlatform == Device.Android &&
(DependencyService.Get<IStorageFolderPath>().ExternalStorageDocumentControl(upload_request.Properties.FilePath) ||
DependencyService.Get<IStorageFolderPath>().DownloadsDocumentControl(upload_request.Properties.FilePath)))
newPath = DependencyService.Get<IStorageFolderPath>().SDCardPath(upload_request.Properties.FilePath);
else
newPath = upload_request.Properties.FilePath;
Stream stream = File.OpenRead(newPath);
//...
}
当我这样做时: 如果路径是 content://com.android.providers.downloads.documents/document/msf:14,app 会抛出这个错误:
{Java.Lang.NumberFormatException: For input string: "msf:14"
at Java.Interop.JniEnvironment+StaticMethods.CallStaticLongMethod (Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x0006e] in <42748fcc36b74733af2d9940a8f3cc8e>:0
at Java.Interop.JniPeerMembers+JniStaticMethods.InvokeInt64Method (System.String encodedMember, Java.Interop.JniArgumentValue* parameters) [0x00018] in <42748fcc36b74733af2d9940a8f3cc8e>:0
at Android.Content.ContentUris.ParseId (Android.Net.Uri contentUri) [0x00031] in <7d2292394f8c488b97f5bc2a0ac0240d>:0
at FileOrbis.Droid.Services.StorageFolderPath.SDCardPath (System.String path) [0x0017c] in C:\Users\Deytek\Desktop\GitWorkspace\FileorbisMobil\FileOrbis\FileOrbis.Android\Services\StorageFolderPath.cs:91
at FileOrbis.Services.AllFileUploadService.UploadFileAsync (FileOrbis.Models.RequestModels.UploadRequest upload_request) [0x000ae] in C:\Users\Deytek\Desktop\GitWorkspace\FileorbisMobil\FileOrbis\FileOrbis\Services\AllFileUploadService.cs:69
--- End of managed Java.Lang.NumberFormatException stack trace ---
java.lang.NumberFormatException: For input string: "msf:14"
at java.lang.Long.parseLong(Long.java:594)
at java.lang.Long.parseLong(Long.java:636)
at android.content.ContentUris.parseId(ContentUris.java:89)
}
(应用程序在此行崩溃:(ContentUris.ParseId(uri))
Android.Net.Uri contentUri = ContentUris.WithAppendedId(
Android.Net.Uri.Parse("content://downloads/public_downloads"), ContentUris.ParseId(uri));)
如果路径是 content://com.android.providers.downloads.documents/document/3025 ,应用会抛出这个错误:
{System.IO.DirectoryNotFoundException: Could not find a part of the path "/content:/com.android.providers.downloads.documents/document/3025".
at System.IO.FileStream..ctor (System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share, System.Int32 bufferSize, System.Boolean anonymous, System.IO.FileOptions options) [0x00177] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/corlib/System.IO/FileStream.cs:223
at System.IO.FileStream..ctor (System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share) [0x00000] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/corlib/System.IO/FileStream.cs:91
at (wrapper remoting-invoke-with-check) System.IO.FileStream..ctor(string,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare)
at System.IO.File.OpenRead (System.String path) [0x00000] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/external/corefx/src/System.IO.FileSystem/src/System/IO/File.cs:266
at FileOrbis.Services.AllFileUploadService.UploadFileAsync (FileOrbis.Models.RequestModels.UploadRequest upload_request) [0x000de] in C:\Users\Deytek\Desktop\GitWorkspace\FileorbisMobil\FileOrbis\FileOrbis\Services\AllFileUploadService.cs:73 }
注意:
我添加到清单文件:
<application android:requestLegacyExternalStorage="true">
</application>
我必须在 Android 10 台设备上解决这个问题? (我没有在所有 android 10 台设备上遇到此问题。我在三星 Galaxy S10 - 模拟器、华为 P20 Lite - 真实 phone 或 Galaxy S20 - 真实 phone 上遇到)
blackapps说的是真的。 Already FilePicker plugin has notified that is possible.但我现在看到了。
从内容方案中获取实际路径不是正确的方法,也不可能。 这就是为什么我必须像这样在我的代码中编写 if 条件:
Stream stream = null;
if (Device.RuntimePlatform == Device.Android && DependencyService.Get<IStorageFolderPath>().DownloadsDocumentControl(newPath))
stream = DependencyService.Get<IStorageFolderPath>().GetFileFromUri(newPath);
else
stream = File.OpenRead(newPath);
public Stream GetFileFromUri(string path)
{
Android.Net.Uri uri = Android.Net.Uri.Parse(path);
var stream = MainActivity.MainContext.ContentResolver.OpenInputStream(uri);
return stream;
}
您可以查询文件名,然后构建路径。
查询文件名:
public static string getFileName(Context context, Android.Net.Uri uri) { ICursor cursor = null; string[] projection = { MediaStore.MediaColumns.DisplayName }; try { cursor = context.ContentResolver.Query(uri, projection, null, null, null); if (cursor != null && cursor.MoveToFirst()) { int index = cursor.GetColumnIndexOrThrow(MediaStore.MediaColumns.DisplayName); return cursor.GetString(index); } } finally { if (cursor != null) if (cursor != null) { cursor.Close(); } } return null; }
构建路径:
else if (isDownloadsDocument (uri)) {
string fileName = getFileName(context, uri);
string filePath = Android.OS.Environment.ExternalStorageDirectory + "/Download/" + fileName;
return filePath;
}