Forms-如何为android定义作用域存储,如何将其实现到下载目录中的downlaod文件?
在我的应用程序中,我可以下载PDF格式的报告。在我在安卓10及以下系统上测试我的应用程序之前,一切都很好。最近我将一台设备升级到Android 11,现在我无法下载共享存储中的任何文件。下载文件时出现访问被拒绝错误 我已授予读取和写入外部存储器的权限Forms-如何为android定义作用域存储,如何将其实现到下载目录中的downlaod文件?,android,xamarin.forms,xamarin.android,Android,Xamarin.forms,Xamarin.android,在我的应用程序中,我可以下载PDF格式的报告。在我在安卓10及以下系统上测试我的应用程序之前,一切都很好。最近我将一台设备升级到Android 11,现在我无法下载共享存储中的任何文件。下载文件时出现访问被拒绝错误 我已授予读取和写入外部存储器的权限 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
我还在AndroidManifest.xml中设置了android:requestLegacyExternalStorage=true
我下载文件的代码如下所示
public async void DownloadSupplierSample(object sender, EventArgs e)
{
try
{
string basepath;
if (Device.RuntimePlatform == Device.Android)
basepath = DependencyService.Get<IDownloadPath>().GetDownloadsPath();
else
basepath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "..", "Library");
PermissionStatus readstatus = await Permissions.CheckStatusAsync<Permissions.StorageRead>();
PermissionStatus writestatus = await Permissions.CheckStatusAsync<Permissions.StorageWrite>();
if (readstatus == PermissionStatus.Granted && writestatus == PermissionStatus.Granted)
{
DownloadSupplier(basepath);
}
else
{
var read = await Permissions.RequestAsync<Permissions.StorageRead>();
var write = await Permissions.RequestAsync<Permissions.StorageWrite>();
if (read == PermissionStatus.Granted && write == PermissionStatus.Granted)
{
DownloadSupplier(basepath);
}
}
await DisplayAlert("", "Sample is downaloaded at Downloads directory","Ok");
}
catch (Exception ex)
{
}
}
async void DownloadSupplier(string basepath)
{
using (var stream = await FileSystem.OpenAppPackageFileAsync("SupplierMaster.xlsx"))
{
string filename = $"SupplierMaster_{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx";
string filepath = Path.Combine(basepath, filename);
byte[] bytes = Utils.Common.StreamToBytes(stream);
File.WriteAllBytes(filepath, bytes);
//using (Stream filestream = File.Create(filepath))
//{
// //stream.Seek(0, SeekOrigin.Begin);
// stream.CopyTo(filestream);
//}
}
}
我也尝试过从这个设备设置标志
如何为我的应用定义作用域存储
任何更新如何在我的下载目录中下载PDF文件
多谢各位
我如何为我的应用定义作用域存储?任何更新我如何在我的下载目录中下载PDF文件
Android 10为应用程序引入了一种新的存储模式,称为作用域存储,它改变了应用程序在设备外部存储上存储和访问文件的方式。如果您的目标是Android 10 API级别29或更高,请在应用程序的清单文件中将requestLegacyExternalStorage的值设置为true
调用android CreateFile方法
私有无效btn1\u单击对象发送者,事件参数e
{
DependencyService.Get.CreateFiletest.txt;
}
几个月前我也有同样的问题 我在developer.android页面上发现: 第一种替代方法getExternalFilesDir无法正常工作,文件不会出现在下载目录中,此位置是应用程序的内部位置 第二种选择是媒体文件 我最后使用了第三种选择。我在Android项目中创建了一个服务类,如下所示:
public class FilesManager : IFilesManager
{
private const int CREATE_FILE_REQUEST_CODE = 123;
private static Context _context;
public static void Init(Context context)
{
_context = context;
}
public async Task SaveFile(string fileName, byte[] content)
{
Intent intent = new Intent(Intent.ActionCreateDocument);
intent.AddCategory(Intent.CategoryOpenable);
intent.SetType(your_file_mimeType);
intent.PutExtra(Intent.ExtraTitle, fileName);
var activity = (MainActivity)_context;
var listener = new ActivityResultListener(activity);
activity.StartActivityForResult(intent, CREATE_FILE_REQUEST_CODE);
var result = await listener.Task;
if (result == null)
{
// Cancelled by user
return;
}
using (Stream os = _context.ContentResolver.OpenOutputStream(result.Data))
{
os?.Write(content);
os?.Close();
}
}
private class ActivityResultListener
{
private readonly TaskCompletionSource<Intent> Complete = new TaskCompletionSource<Intent>();
public Task<Intent> Task { get { return this.Complete.Task; } }
public ActivityResultListener(MainActivity activity)
{
// subscribe to activity results
activity.ActivityResult += OnActivityResult;
}
private void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
if(requestCode != CREATE_FILE_REQUEST_CODE)
{
return;
}
// unsubscribe from activity results
var activity = (MainActivity)_context;
activity.ActivityResult -= OnActivityResult;
// process result
if (resultCode == Result.Ok)
{
Complete.TrySetResult(data);
}
else
{
Complete.TrySetResult(null);
}
}
}
}
注意:此方法需要用户交互。系统将提示用户选择保存文件的位置。在Android 11设备上,您应该能够像在其他Android版本上一样,在外部存储的下载目录中创建文件。你们并没有下载问题,只是下载目录中的一个文件创建问题,我不明白。您添加了要求用户在运行时确认写入权限的代码?并不是说Android 11设备上需要它。我的下载路径是,这是您获取路径的代码。你走哪条路?请告诉我它的价值。请填写完整路径。这是下载目录/storage/emulated/0/Download/SupplierMaster_20210310141155.xlsx的路径。若我能够下载文件,即使在安卓11,那个么为什么我得到访问拒绝错误?这在Android 10或belowAccess上有效拒绝什么?你是说下载文件时拒绝访问错误,但我不这么认为。是的,我错了,你是对的。当我尝试创建文件时会出现错误好的,这意味着我必须在Android和iOS上分别实现文件创建逻辑。我一定要试一试。谢谢你的支持answer@Monica如果我的回复对您有帮助,请记住将我的回复标记为答案。是的,当然,我已经编写了您的代码,但无法对其进行测试。由于过去两个小时,我无法在android project上运行我的应用程序。System.IO.DirectoryNotFoundException:找不到路径“/Users/apple/Library/Android/sdk”的一部分。。一旦我解决了这个问题,我将测试你的答案,并将其标记为接受。我再次遇到这个错误。昨天还在工作。但同样的拒绝访问问题再次出现。@Monica您使用Visual studio for mac?如果是,请手动将Android SDK文件从默认路径复制到错误消息中的硬编码路径,更多详细信息,请查看:谢谢您的回答。我在activity.ActivityResult中遇到错误。未找到ActivityResult。我应该在MainActivity中添加什么?没问题,我编辑了答案。感谢您编辑答案。在调用SaveFile之前是否需要调用Init?因为我在_上下文中变为空。是的,当然,我再次编辑:非常感谢@alexgavru对我的帮助。它现在正在工作。
public class FilesManager : IFilesManager
{
private const int CREATE_FILE_REQUEST_CODE = 123;
private static Context _context;
public static void Init(Context context)
{
_context = context;
}
public async Task SaveFile(string fileName, byte[] content)
{
Intent intent = new Intent(Intent.ActionCreateDocument);
intent.AddCategory(Intent.CategoryOpenable);
intent.SetType(your_file_mimeType);
intent.PutExtra(Intent.ExtraTitle, fileName);
var activity = (MainActivity)_context;
var listener = new ActivityResultListener(activity);
activity.StartActivityForResult(intent, CREATE_FILE_REQUEST_CODE);
var result = await listener.Task;
if (result == null)
{
// Cancelled by user
return;
}
using (Stream os = _context.ContentResolver.OpenOutputStream(result.Data))
{
os?.Write(content);
os?.Close();
}
}
private class ActivityResultListener
{
private readonly TaskCompletionSource<Intent> Complete = new TaskCompletionSource<Intent>();
public Task<Intent> Task { get { return this.Complete.Task; } }
public ActivityResultListener(MainActivity activity)
{
// subscribe to activity results
activity.ActivityResult += OnActivityResult;
}
private void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
if(requestCode != CREATE_FILE_REQUEST_CODE)
{
return;
}
// unsubscribe from activity results
var activity = (MainActivity)_context;
activity.ActivityResult -= OnActivityResult;
// process result
if (resultCode == Result.Ok)
{
Complete.TrySetResult(data);
}
else
{
Complete.TrySetResult(null);
}
}
}
}
public event Action<int, Result, Intent> ActivityResult;
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
ActivityResult?.Invoke(requestCode, resultCode, data);
}
FilesManager.Init(this);