Xamarin: сохранение файлов во внешнем хранилище на Android с уровнем API ›= 29

Я пытаюсь экспортировать файлы в общедоступное внешнее хранилище телефона Android в Xamarin для резервной БД. Однако в последней версии телефонов Android (11.0 - API30) нельзя отказаться от ограниченного хранилища, используя свойство android:requestLegacyExternalStorage="true" тега <application> в manifest.xml.

Я убедился, что разрешения READ_EXTERNAL_STORAGE & WRITE_EXTERNAL_STORAGE предоставлены, прежде чем пытаться создать файл. Тем не менее, при попытке создать файл выдается System.UnauthorizedAccessException исключение.

/* file 1: */
// ....
private async void Export_Tapped (object sender, EventArgs e) {
    // check if permission for writing in external storage is given
    bool canWrite = await FileSystem.ExternalStoragePermission_IsGranted ();

    if (!canWrite) {
        // request permission
        canWrite = await FileSystem.ExternalStoragePermission_Request ();

        if (!canWrite) {
            // alert user

            return;
        }
    }

    // find the directory to export the db to, based on the platform
    string fileName = "backup-" + DateTime.Now.ToString ("yyMMddThh:mm:ss") + ".db3";
    string directory = FileSystem.GetDirectoryForDatabaseExport ();     // returns "/storage/emulated/0/Download"
    string fullPath = Path.Combine (directory, fileName);

    // copy db to the directory
    bool copied = false;
    if (directory != null)
        copied = DBConnection.CopyDatabase (fullPath);

    if (copied)
        // alert user
    else
        // alert user
}
// ....

/* file 2: */
class DBConnection 
{
    private readonly string dbPath;
    
    // ....

    public bool CopyDatabase(string path) 
    {
        byte[] dbFile = File.ReadAllBytes(dbPath);
        File.WriteAllBytes(path, dbFile);        // --> this is where the exception is thrown <--
        
        return true;
    }

    // ....
}

Возникает вопрос: как записать новый файл в общедоступное внешнее хранилище Android-устройства с уровнем API 29 или выше?


Все ресурсы, которые я нашел до сих пор, возможно, вы сможете собрать больше информации, чем я:


person E. Epstein    schedule 30.09.2020    source источник
comment
ты нашел на это ответ?   -  person Shubham Tyagi    schedule 16.12.2020
comment
@ShubhamTyagi, К сожалению, решения не нашел. Вы можете придумать обходные пути (например, заставить пользователя отправить файл по электронной почте куда-нибудь), но настоящего решения нет :(   -  person E. Epstein    schedule 20.12.2020


Ответы (2)


Попробуйте это, я использую службу зависимостей , чтобы вызвать этот метод в собственном Android и сохранить файлы, такие как docx и pdf, из их побайтного массива.

public async Task<bool> CreateFile(string fileName, byte[] docBytes, string fileType)
        {
            try
            {
                Java.IO.File file = new Java.IO.File(Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).AbsolutePath, fileName + fileType);
                OutputStream os = new FileOutputStream(file);
                os.Write(docBytes);
                os.Close();
            }
            catch
            {
                return false;
            }
            return true;
        }
person Shubham Tyagi    schedule 09.10.2020
comment
Когда я пытаюсь это сделать, строка OutputStream os ... выдает исключение: _2 _... Есть идеи? Я убедился, что предоставлены права на запись . - person E. Epstein; 11.10.2020

Используемый вами путь неверен, попробуйте следующий путь к файлу.

Context context = Android.App.Application.Context;
var filePath = context.GetExternalFilesDir(Android.OS.Environment.DirectoryDocuments);

См. https://forums.xamarin.com/discussion/comment/422501/#Comment_422501.

person ColeX - MSFT    schedule 01.10.2020
comment
Возвращаемый путь context.GetExternalFilesDir(...) относится к частному внешнему, в то время как я ищу способ сохранить файл в общедоступном внешнем хранилище, чтобы пользователь мог взаимодействовать с файл... - person E. Epstein; 01.10.2020
comment
Приложения, ориентированные на Android 10 и новее, больше не имеют доступа к общедоступным каталогам внешнего хранилища. Проверьте developer.android.com/reference/android. / os /. - person ColeX - MSFT; 01.10.2020
comment
Я понимаю, однако, что приложения могут записывать файлы во внешнее хранилище, чтобы пользователь мог с ними взаимодействовать. Например: CamScanner (сохранение файлов в хранилище), Reddit (загрузка изображения / видео для публикации) и т. Д. Итак, как это возможно, если у них нет доступа к внешнему хранилищу? - person E. Epstein; 01.10.2020
comment
Приложения, которые работают на Android 11, но нацелены на Android 10 (уровень API 29), по-прежнему могут запрашивать атрибут requestLegacyExternalStorage. После обновления приложения до Android 11 система игнорирует флаг requestLegacyExternalStorage, поэтому вы должны установить в качестве цели Android 10. - person ColeX - MSFT; 06.10.2020
comment
Пробовал с Android 11, когда приложение нацелено на Android 10, все еще не работало ... - person E. Epstein; 07.10.2020
comment
Проверьте stackoverflow.com/a/57116787/8187800. - person ColeX - MSFT; 12.10.2020