Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Download a file from a URL to a user accessible location

I am building an app using Nativescript/Angular 2

I want to be able to download a file from a URL and save it to the device in a location the average user would have no problems finding it. I believe downloads would be the best place for this on both iOS and Android. Please correct me if I am wrong.

The file can be any file type, not just an image. So mainly spreadsheet, word document, pdf, png, jpg, etc.

I have searched online and through the documentation. The documentation describes a method called getFile which gets a file and saves it to your device.

I have implemented this in my code as follows:

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!
  });
}

The problem with this is that it saves it to a non-user accessible location such as:

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

Update:

I have also tried specifying the path directly with:

fs.knownFolders.documents();

However, this method gets the documents folder for the current application that is NOT accessible by the user or external applications

like image 376
RSM Avatar asked Dec 13 '16 16:12

RSM


Video Answer


3 Answers

After some unsuccessful attempts, I finally found how to save file to user "Downloads" folder (something like sdcard/Download). You can use android.os.Environment method to get this folder.

Add this in your component:

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}`
                    });
                });
            });
    }
}

What else you should know:

1) There is no any kind of download indicator, standard system download bar also not appears, and I don't know how to solve this.

2) For iOS you may try to use

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

I think, it's the shame that NS docs don't talk straight, that you can't save files in user accessible location only with NS functions. I figured it out only when I read comments in file /node_modules/tns-core-modules/file-system/file-system.d.ts

Hope this helps you.

like image 84
Andy Infin Avatar answered Sep 27 '22 18:09

Andy Infin


The same documentation says that you can specify the file location like this:

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!
  });
}

disclaimer: never tried it myself, just read the docs ...

like image 41
alebianco Avatar answered Sep 27 '22 18:09

alebianco


To get it working on iPhone, you can do the following (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()

Then in Info.plist, you have to add the following permissions:

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

Now if you go to your iPhone's Files app > On My iPhone > Your App's Name, you should see the file there.

Basically, the Documents folder is a private folder inside your application's directory that only you can see. However, when you enable the two permissions above, it allows file sharing so that your user can access the folder and its contents.

like image 39
ttmtran Avatar answered Sep 27 '22 19:09

ttmtran