I think you can use AppDataDirectory to have you app directory, then create a subdir inside it
Save PDF in Xamarin Forms when targeting Android 11
I want a method to save PDF that coming as a byte[] from the server. iOS working well. In Android, I need to save the PDF in my app specific storage location. Previously I saved in the common external storage location. With the new android policy I cannot do that. All my updates are rejected from the play store. Is there a way to use Xamarin.Essential for save the PDF? Can we use Directory.CreateDirectory in Android 11 now?
Old code in Android side...
public class AndroidSaveFile : ISaveFile
{
public async Task<string> SaveFiles(string filename, byte[] bytes, string filePath)
{
var status = await CrossPermissions.Current.CheckPermissionStatusAsync<StoragePermission>();
if (status != PermissionStatus.Granted)
{
if (await CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync(Permission.Storage))
{
await Application.Current.MainPage.DisplayAlert("Storage permission!", "To save files, you need the storage permissions.", "OK");
}
status = await CrossPermissions.Current.RequestPermissionAsync<StoragePermission>();
}
if (status == PermissionStatus.Granted)
{
if (!Directory.Exists(filePath))
{
Directory.CreateDirectory(filePath);
}
File.WriteAllBytes(filename, bytes);
}
else if (status != PermissionStatus.Unknown)
{
await Application.Current.MainPage.DisplayAlert("Storage Denied!", "Can not access storage on this device. Please check the permission and try again.", "OK");
}
return filename;
}
}
Then I tried using Xamarin.Essentials for saving and open PDF in the shared project. Still got reject.
string dateTimePart = DateTime.Now.ToString("yyMMddHHmmss");
string fileName = "bonus_" + dateTimePart + ".pdf";
var filePath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
if (Device.RuntimePlatform == Device.Android)
{
var file = Path.Combine(filePath, fileName);
File.WriteAllBytes(file, resList);
await Launcher.OpenAsync(new OpenFileRequest
{
Title = fileName,
File = new ReadOnlyFile(file)
});
}
Developer technologies .NET Xamarin
2 answers
Sort by: Most helpful
-
-
JarvanZhang 23,971 Reputation points
2021-12-20T08:51:39.767+00:00 Starting in Android 11, apps cannot create their own app-specific directory on external storage. Try using
MediaStore
API to access media files from shared storage using direct file paths.var values = new ContentValues(); values.Put(MediaStore.IMediaColumns.DisplayName, Path.GetFileNameWithoutExtension(fileName)); values.Put(MediaStore.IMediaColumns.MimeType, MimeService.GetMimeType(Path.GetExtension(fileName))); values.Put(MediaStore.IMediaColumns.IsPending, true); var contentResolver = Android.App.Application.Context.ContentResolver; var collection = MediaStore.Downloads.GetContentUri(MediaStore.VolumeExternalPrimary); var fileUri = contentResolver.Insert(collection, values); using var stream = contentResolver.OpenFileDescriptor(fileUri, "w"); using var pdfStream = new ParcelFileDescriptor.AutoCloseOutputStream(stream); await pdfStream.WriteAsync(bytes);
Here is the related doc, you could refer to it: https://developer.android.com/about/versions/11/privacy/storage#app-specific-external