Загрузите файл с URL-адреса в доступное для пользователя место.

Я создаю приложение, используя Nativescript/Angular 2.

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

Файл может быть любого типа, а не только изображение. Так что в основном spreadsheet, word document, pdf, png, jpg и т. д.

Я искал в Интернете и через документацию. В документации описан метод под названием getFile, который получает файл и сохраняет его на вашем устройстве.

Я реализовал это в своем коде следующим образом:

download (id) {
  console.log('Download Started');
  getFile("https://raw.githubusercontent.com/NativeScript/NativeScript/master/apps/tests/logo.png").then(function (r) {
    console.log(r.path);
  }, function (e) {
    //// Argument (e) is Error!
  });
}

Проблема с этим заключается в том, что он сохраняет его в недоступном для пользователя месте, например:

/data/user/0/com.myapp.example/files/logo.png

Обновлять:

Я также попытался указать путь напрямую с помощью:

fs.knownFolders.documents();

Однако этот метод получает папку документов для текущего приложения, которая НЕ доступна пользователю или внешним приложениям.


person RSM    schedule 13.12.2016    source источник


Ответы (6)


После нескольких безуспешных попыток я, наконец, нашел, как сохранить файл в пользовательскую папку «Загрузки» (что-то вроде sdcard/Download). Вы можете использовать метод android.os.Environment, чтобы получить эту папку.

Добавьте это в свой компонент:

import { getFile } from 'tns-core-modules/http';
import * as fileSystem from "tns-core-modules/file-system";
import { isAndroid } from "tns-core-modules/platform";
import { alert } from "tns-core-modules/ui/dialogs";

declare var android;

<...>

public download (url, fileName) {
    if (isAndroid) {
        const permissions = require("nativescript-permissions");
        permissions.requestPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, "I need these permissions because I'm cool")
            .then(() => {
                let downloadedFilePath = fileSystem.path.join(android.os.Environment.getExternalStoragePublicDirectory(android.os.Environment.DIRECTORY_DOWNLOADS).getAbsolutePath(), fileName);
                getFile(url, downloadedFilePath).then(resultFile => {
                    alert({
                        title: 'Saved!',
                        okButtonText: 'OK',
                        message: `File saved here:\n${resultFile.path}`
                    });
                }, error => {
                    alert({
                        title: 'Error',
                        okButtonText: 'OK',
                        message: `${error}`
                    });
                });
            });
    }
}

Что еще вы должны знать:

1) Нет никакого индикатора загрузки, стандартная панель загрузки системы тоже не появляется, и я не знаю, как это решить.

2) Для iOS вы можете попробовать использовать

const filePath = fileSystem.path.join(fileSystem.knownFolders.ios.downloads().path, fileName);
getFile(url, filePath).then((resultFile) => {}, (error) => {});

Я думаю, это позор, что документы NS не говорят прямо, что вы не можете сохранять файлы в доступном для пользователя месте только с функциями NS. Я понял это только когда прочитал комментарии в файле /node_modules/tns-core-modules/file-system/file-system.d.ts

Надеюсь, это поможет вам.

person Andy Infin    schedule 20.11.2018

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

download (id) {
  console.log('Download Started');
  var folder = fs.knownFolders.documents();
  var file = fs.path.join(folder.path, "logo.png");
  var url = "https://raw.githubusercontent.com/NativeScript/NativeScript/master/apps/tests/logo.png"
  getFile(url, file).then(function (r) {
    console.log(r.path);
  }, function (e) {
    //// Argument (e) is Error!
  });
}

отказ от ответственности: сам никогда не пробовал, просто прочитал документы...

person alebianco    schedule 13.12.2016
comment
Я знал об этом, метод fs.knownFolders.documents() получает папку документов для текущего приложения, которая НЕ доступна пользователю или внешним приложениям. - person RSM; 14.12.2016
comment
Невозможность указать местоположение файла и местоположение, являющееся приватным для приложения, кажутся мне двумя разными проблемами. В любом случае вам просто нужно указать общедоступный путь вместо использования fs.knownFolders.documents(). Я думаю, что fs.knownFolders.ios.downloads() должен дать вам папку загрузок iOS, но нет эквивалента для Android или других, поэтому вам придется создать свой собственный - person alebianco; 14.12.2016
comment
Я также пробовал этот путь на ios, не работает. По этой причине я публикую сообщение о переполнении стека для некоторой помощи. - person RSM; 14.12.2016
comment
Возможно, вам придется работать с каждой платформой отдельно — с {N} это относительно просто. На андроиде единственной другой общедоступной папкой являются папки хранения SD-карты (внутренняя и внешняя). - person dashman; 14.12.2016

Чтобы заставить его работать на iPhone, вы можете сделать следующее (TypeScript):

import { knownFolders, path } from "tns-core-modules/file-system";

let destination = path.join(knownFolders.documents(), "file_name.txt");
// logic to save your file here ...
// the important thing is that you have to save your file in knownFolders.documents()

Затем в Info.plist вы должны добавить следующие разрешения:

<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
<key>UIFileSharingEnabled</key>
<true/>

Теперь, если вы зайдете в приложение Files на своем iPhone › On My iPhoneYour App's Name, вы должны увидеть там файл.

По сути, папка Documents — это личная папка внутри каталога вашего приложения, которую можете видеть только вы. Однако, когда вы включаете два вышеуказанных разрешения, он разрешает общий доступ к файлам, чтобы ваш пользователь мог получить доступ к папке и ее содержимому.

person ttmtran    schedule 14.01.2021

Я понимаю, что это старая тема, но, возможно, это может помочь кому-то:

Если вы используете currentApp() вместо documents(), вы можете получить доступ к нужной вам папке. Например:

var directories = fs.knownFolders.currentApp();
var folder = directories.getFolder('./nameofaccessiblefolder');
person ngiottz    schedule 01.09.2018

Вы можете указать путь к файловой системе напрямую, например:

var folder = fs.Folder.fromPath('/sdcard/Download');

Обратите внимание, что /sdcard/Download будет работать только на Android; вы можете заменить его любой (общедоступной) папкой, в которую вы хотите сохранить свои данные.

Пока не существует кросс-платформенного способа выбора пути к папке, поэтому вам придется что-то делать вручную. Дополнительную информацию см. в этой ветке GitHub.

person Hippo    schedule 21.10.2018

Я знаю, что эта ветка существует 3 года назад, но если у вас возникнет та же проблема, я надеюсь, что это решение сэкономит вам время.

Я решил ту же проблему, добавив android:requestLegacyExternalStorage="true" в файл AndroidManifest.xml.

person Arjorie Sotelo    schedule 17.07.2020