FrancescoMussi
FrancescoMussi

Reputation: 21630

Cordova: How to move file to the Download folder?

THE SITUATION:

In my mobile app I need to download a file and store in the Download folder.

The download part is working fine. The file is properly downloaded from the server and stored in the following folder:

file:///storage/emulated/0/Android/data/org.cordova.MY_APP_NAME.app/my_file.pdf

But the location is not really user-friendly.

To access it I have to go to: Internal storage / Android / data / org.cordova.MY_APP_NAME.app /

So I need to move it to the main Download folder.

The file transfer is what I don't manage to do.

I know that there are already several similar questions on SO.

I have tried them all but none really worked for me, I could never see the file in the actual Download folder.

PROJECT INFO:

I am using Quasar with Vuejs and Cordova.

PLATFORM:

For the moment I am working with Android. But ideally I am looking for a solution that works for both Android and IOS.

THE CODE:

The download code:

var fileTransfer = new FileTransfer() // eslint-disable-line
var uri = encodeURI('https://MY_SERVER_PATH')

fileTransfer.download(
  uri,
  cordova.file.externalApplicationStorageDirectory + 'my_file.pdf',
  entry => {
    console.log('download complete: ' + entry.toURL())
    this.moveFile(entry.toURL())
  },
  error => {
    console.log('download error source ' + error.source)
    console.log('download error target ' + error.target)
    console.log('download error code' + error.code)
  },
  false,
  {
    headers: {
      'Authorization': 'Basic asdasdasdasdassdasdasd'
    }
  }
)

The File transfer code:

moveFile(fileUri) {
  window.resolveLocalFileSystemURL(
    fileUri,
    fileEntry => {
      let newFileUri = 'file:///storage/emulated/0/Download'

      window.resolveLocalFileSystemURL(
        newFileUri,
        dirEntry => {
          fileEntry.moveTo(dirEntry, 'new_filename.pdf', this.moveFileSuccess, this.moveFileError)
        },
        this.moveFileError)
    },
    this.moveFileError)
},
moveFileSuccess(entry) {
  console.log('file move success')
  console.log(entry)
},
moveFileError(error) {
  console.log('file move error')
  console.log(error)
}

THE QUESTION:

How can I move a file to the Download folder?

Thanks

EDIT:

This is the console log of the cordova.file object:

applicationDirectory: "file:///android_asset/"
applicationStorageDirectory: "file:///data/user/0/org.cordova.MY_APP_NAME.app/"
cacheDirectory:"file:///data/user/0/org.cordova.MY_APP_NAME.app/cache/"
dataDirectory: "file:///data/user/0/org.cordova.MY_APP_NAME.app/files/"
documentsDirectory: null
externalApplicationStorageDirectory: "file:///storage/emulated/0/Android/data/org.cordova.MY_APP_NAME.app/"
externalCacheDirectory: "file:///storage/emulated/0/Android/data/org.cordova.MY_APP_NAME.app/cache/"
externalDataDirectory: "file:///storage/emulated/0/Android/data/org.cordova.MY_APP_NAME.app/files/"
externalRootDirectory: "file:///storage/emulated/0/"
sharedDirectory: null
syncedDataDirectory: null
tempDirectory: null

Upvotes: 3

Views: 11328

Answers (3)

FrancescoMussi
FrancescoMussi

Reputation: 21630

Okay I managed to resolve it.

  • First of all is totally unnecessary to download and then move the file. It can just be directly downloaded in the desired direction.

  • The correct path (in my case) was this:

    cordova.file.externalRootDirectory + 'download/' + 'my_file.pdf

    that correspond to: file:///storage/emulated/0/download/my_file.pdf

    and that means that to find the file inside the device you have to go to: Internal Storage / Download / my_file.pdf

  • Add the following value in the config.xml:

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

  • It's important to check for permission using this cordova plugin: cordova-plugin-android-permissions

You can make a quick test like this:

let permissions = cordova.plugins.permissions
permissions.checkPermission(permissions.READ_EXTERNAL_STORAGE, checkPermissionCallback, null)

function checkPermissionCallback(status) {
  console.log('checking permissions')
  console.log(status)
}

Most probably the result is false. And that means that we have to request permission to the user:

permissions.requestPermission(successCallback, errorCallback, permission)

In this way it will appear the alert asking for permission.

THE CODE:

To put it all together, this is the working code:

let pdfPath = 'https://MY_SERVER_PATH'

let permissions = cordova.plugins.permissions
permissions.checkPermission(permissions.READ_EXTERNAL_STORAGE, checkPermissionCallback, null)

// Checking for permissions
function checkPermissionCallback(status) {
  console.log('checking permissions')
  console.log(status)
  if (!status.hasPermission) {
    var errorCallback = function () {
      console.warn('Storage permission is not turned on')
    }
    // Asking permission to the user
    permissions.requestPermission(
      permissions.READ_EXTERNAL_STORAGE,
      function (status) {
        if (!status.hasPermission) {
          errorCallback()
        } else {
          // proceed with downloading
          downloadFile()
        }
      },
      errorCallback)
  } else {
    downloadFile()
  }
}

function downloadFile() {
  let filePath = cordova.file.externalRootDirectory + 'download/' + 'my_file.pdf'
  let fileTransfer = new window.FileTransfer()
  let uri = encodeURI(decodeURIComponent(pdfPath))

  // Downloading the file
  fileTransfer.download(uri, filePath,
    function (entry) {
      console.log('Successfully downloaded file, full path is ' + entry.fullPath)
      console.log(entry)
    },
    function (error) {
      console.log('error')
      console.log(error)
    },
    false
  )
}

Upvotes: 16

greenapps
greenapps

Reputation: 11224

 cordova.file.externalApplicationStorageDirectory. 

For that path you do not need to request any permission in manifest or require any permission at all.

But for others like external storage and so you need them.

You are #1244 with this problem this year.

Google for runtime permissions.

You can than directly download to the Download directory.

Upvotes: -1

Neeraj Vishwakarma
Neeraj Vishwakarma

Reputation: 122

var fileTransfer = new FileTransfer() // eslint-disable-line
var uri = encodeURI('https://MY_SERVER_PATH')
var fileURL =  "///storage/emulated/0/Download";

fileTransfer.download(
  uri,
  fileURL+ 'your_file.pdf',
  entry => {
            console.log('download complete: ' + entry.toURL())
            this.moveFile(entry.toURL())
           },
  error => {
            console.log('download error source ' + error.source)
            console.log('download error target ' + error.target)
            console.log('download error code' + error.code)
           },
      false,
      {
       headers: {
       'Authorization': 'Basic asdasdasdasdassdasdasd'
      }
    }
 )

you can directly save downloaded file to your path

Try above code and let me know if its work.

Upvotes: 0

Related Questions