Cordova file plugin - сохранить файл на устройстве

У меня много проблем с сохранением файлов в Android.
Проект представляет собой гибридное приложение, разработанное с помощью Ionic с этими плагинами:

com.phonegap.plugins.fileopener 1.0.0 "File Opener"
com.telerik.plugins.nativepagetransitions 0.4.2 "Native Page Transitions"
cordova-plugin-compat 1.0.0 "Compat"
cordova-plugin-crosswalk-webview 2.0.0 "Crosswalk WebView Engine"
cordova-plugin-file 4.2.0 "File"
cordova-plugin-network-information 1.2.2-dev "Network Information"
cordova-plugin-whitelist 1.2.3-dev "Whitelist"
cordova-plugin-wkwebview-engine 1.0.4-dev "Cordova WKWebView Engine"
ionic-plugin-keyboard 2.2.1 "Keyboard"

Версия платформы Android 5.2.1
Устройство, которое я использую, является Samsung A7

Это реферат от AndroidManifest.xml

<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

Случай 1

если я попробую с этим фрагментом (на самом деле работает над другим проектом)

var storagePath = "/storage/emulated/0";
var fileDir = cordova.file.externalDataDirectory.replace(cordova.file.externalRootDirectory, '');
var fileName = $scope.ngDocument.documentId + ".pdf"
var filePath = storagePath + "/" + fileDir + fileName;
$cordovaFile.writeFile(filePath, BINARY_ARR, {'append': false}).then(function(result) {}, function(err) {});

я получил {"code":5,"message":"ENCODING_ERR"} как Обратный звонок от $cordovaFile.writeFile, независимо от того, если я использую абсолютный путь, относительный путь, просто имя файла, и файл никогда не создается.

Вариант 2

С этим фрагментом

window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {
  console.log('file system open: ' + fs.name);
  fs.root.getFile(fileName, { create: true, exclusive: false }, function (fileEntry) {
    console.log("fileEntry:" + JSON.stringify(fileEntry));
    writeFile(fileEntry, BINARY_ARR);
  }, function(data){});
}, function(data){});

случаются две разные вещи

Случай 2.1

Если параметры конфигурации не указаны в config.xml приложение создает пустую папку в /storage/emulated/0/Android/media/{myAPP}

Дело 2.2

с этими двумя предпочтениями

<preference name="AndroidPersistentFileLocation" value="Compatibility" />
<preference name="AndroidExtraFilesystems" value="cache" />

файл в /storage/emulated/0 (внешний SSD) создан и в logcat ошибки:

E/Vold    ( 2280): Failed to find mounted volume for /storage/extSdCard/Android/data/{myApp}/files/
W/Vold    ( 2280): Returning OperationFailed - no handler for errno 0
W/ContextImpl(13364): Failed to ensure directory: /storage/extSdCard/Android/data/{myApp}/files
E/Vold    ( 2280): Failed to find mounted volume for /storage/extSdCard/Android/data/{myApp}/files/
W/Vold    ( 2280): Returning OperationFailed - no handler for errno 0
W/ContextImpl(13364): Failed to ensure directory: /storage/extSdCard/Android/data/{myApp}/files
E/Vold    ( 2280): Failed to find mounted volume for /storage/extSdCard/Android/data/{myApp}/cache/
W/Vold    ( 2280): Returning OperationFailed - no handler for errno 0
W/ContextImpl(13364): Failed to ensure directory: /storage/extSdCard/Android/data/{myApp}/cache

Странный факт в том, что /storage/extSdCard (символическая ссылка для /mnt/extSdCard) не подключен, а внешний SSD установлен на /mnt/sdcard

Пожалуйста, помогите: я трясу головой.
Первый фрагмент работал как очарование в другом проекте. Это может быть версия ngCordova?

2 ответа

Решение

РЕШИТЬ:

после нескольких попыток я решил таким образом

в config.xml:

<preference name="AndroidPersistentFileLocation" value="Compatibility" />
<preference name="AndroidExtraFilesystems" value="files,cache, sdcard, cache-external, files-external" />

и основная функция:

window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {

    //var absPath = "file:///storage/emulated/0/";
    var absPath = cordova.file.externalRootDirectory;
    var fileDir = cordova.file.externalDataDirectory.replace(cordova.file.externalRootDirectory, '');
    var fileName = "somename.txt";
    var filePath = fileDir + fileName;

    fs.root.getFile(filePath, { create: true, exclusive: false }, function (fileEntry) {
        writeFile(fileEntry, BINARY_ARR).then(function(){
          //do something here
        });
    }, function(err) {});
}, function(err) {});

function writeFile(fileEntry, dataObj) {
    return $q(function (resolve, reject) {
        fileEntry.createWriter(function (fileWriter) {
            fileWriter.onwriteend = function () {
                resolve();
            };
            fileWriter.onerror = function (e) {
                reject(e);
            };
            fileWriter.write(dataObj);
        });
    });
}

Казалось, что:

<preference name="AndroidPersistentFileLocation" value="Internal" />

это конфигурация по умолчанию, не позволяющая приложению записывать на внешний диск (физический или эмулированный). Вместо этого разрешено приложение только для записи в /data/data/{myApp}/files

Итак, вот полное объяснение того, как сохранить файл. Используя файловый плагин cordova:

Предположим, вам нужно сохранить файл с текстом "Hello Mr. Vaibhav Mojidra" в .txt внутри внутренней памяти.

Итак, вот оно, если у вас есть кнопка в HTML, например: Теперь внутри функции SaveFile:

       var textt="";
       функция SaveFile(текст)
      {
         textt = текст; /* инициализируем глобальную переменную текстом для записи в файл */
         window.requestFileSystem(LocalFileSystem.PERSISTENT, 0,onFileSystemSuccess, сбой);

         /* Это проверит разрешение на чтение и запись в хранилище, и если разрешение получено, то 
          параметр отправки функции будет вызываться иначе, если не предоставлен, то третий параметр, т.е. 
         функция отказа будет вызвана */
      }

      функция onFileSystemSuccess(файловая система) 
      {
         fileSystem.root.getFile("Demo.txt",{create: true, эксклюзив: 
      false},gotFileEntry,fail);
        /* Это создаст файл с именем Demo.txt во внутренней памяти. и аналогично
         успешно создать, он вызовет функцию второго параметра, то есть gotFileEntry */
      }

      function gotFileEntry (fileEntry) {
        fileEntry.createWriter(gotFileWriter, сбой);
        /* Будет получен объект файла с вызовом пути createWriter, в котором 1-й параметр 
       использовать для записи содержимого в файл и второй параметр при ошибке создания писателя */
      }

      функция gotFileWriter(писатель) 
      {
         writer.write (textt);

         /* передача параметра текста, который является глобальным и инициализируется 
       сначала вызывается функция */
          writer.onwriteend = function (evt) {
            alert ("Файл сохранен");
          }; /* Эта функция будет вызываться после того, как файл будет записан с текстом и сохранен */
       }

     сбой функции (ошибка)
     {
       alert ("Ошибка","Возникла проблема \n Ошибка:"+error.code,"Хорошо");
     }
    

Используйте эту функцию для записи и создания новой папки

function writeFile(path, filename, blob) {
    return new Promise((resolve, reject) => {
        window.resolveLocalFileSystemURL(cordova.file.externalRootDirectory, function (dirpar) {
            dirpar.getDirectory(path, { create: true }, function (dir) {
                dir.getFile(filename, { create: true, exclusive: false }, function (fileEntry) {
                    fileEntry.createWriter(function (fileWriter) {
                        fileWriter.onwriteend = resolve
                        fileWriter.onerror = reject
                        fileWriter.write(blob);
                    });
                }, reject);
            }, reject);
        }, reject);
    });
}

как вызвать функцию

writeFile("AppFolder", 'file.name', blob)

образец скачать изображение и сохранить в папке

var url = "image url"

fetch(url).then(res => res.blob()).then(blob => {

    writeFile("pictures/myapp", url.substring(url.lastIndexOf("/") + 1), blob)
        .then(function () { console.log("file donwloaded.") })
        .catch(function (e) { console.error("error:", e) })

});

Используйте плагин FileTransfer: https://github.com/apache/cordova-plugin-file-transfer для загрузки и https://github.com/pwlin/cordova-plugin-pdialog чтобы отобразить диалог хода выполнения.

function saveFileDownloaded(url, nameFile) {
    var uri = url;
    var test = isEncoded(url)
    if (test == false) {
        uri = encodeURI(url)
    }
    var fileTransfer = new window.FileTransfer();
    var fileURL = cordova.file.externalRootDirectory + "Direct/" + nameFile;
     cordova.plugin.pDialog.init({
                    theme : 'DEVICE_LIGHT',
                    progressStyle : 'HORIZONTAL',
                    cancelable : false,
                    message : 'Téléchargement en cours...'
                });
    fileTransfer.onprogress = function(result) {
        var percent = result.loaded / result.total * 100;
        percent = Math.round(percent);   
         cordova.plugin.pDialog.setProgress(percent);       
    };
    fileTransfer.download(
        uri,
        fileURL,
        function(entry) {
            cordova.plugin.pDialog.dismiss();
            navigator.notification.confirm(
                'Voulez vous ouvrir le fichier', // message
                function(buttonIndex) {
                    onConfirm(buttonIndex, fileURL);
                }, // callback to invoke
                'Téléchargement terminé', // title
                ['Ok', 'Exit'] // buttonLabels
            );
        },
        function(error) {
                    cordova.plugin.pDialog.dismiss();
            console.log(error)
            alert("Erreur lors du téléchargement, vérifier votre connexion!");
            console.log("download error source " + error.source);
            console.log("download error target " + error.target);
            console.log("upload error code" + error.code);
        }
    );
}
Другие вопросы по тегам