How can I retrieve a file from the www-directory using PhoneGap?

Despite trying various solutions to access a file in the www folder, none seem to work for me. I am testing the application on iOS with the iOS simulator.
The specific file I want to access is test.txt located in the www folder.

Here is my current approach:

var filePathURI = getPhoneGapPath() + "test.txt";
window.resolveLocalFileSystemURI(filePathURI, onResolveSuccess, onFail);

function getPhoneGapPath() {  
    'use strict';
    var path = window.location.pathname;
    var phoneGapPath = path.substring(0, path.lastIndexOf('/') + 1);
    return phoneGapPath;
};

Unfortunately, this solution is not working as expected. I keep getting an error with errorCode = 2, indicating FileError.SECURITY_ERR. Regardless of what I try, I cannot access the file using resolveLocalFileSystemURI.

INFO: I have attempted the following filePathURIs:

  1. /Users/UserName/Library/Application%20Support/iPhone%20Simulator/7.0/Applications/GUID/AppName.app/www/test.txt
  2. file:///Users/UserName/Library/Application%20Support/iPhone%20Simulator/7.0/Applications/GUID/AppName.app/www/test.txt

If anyone has a solution that actually works, I would greatly appreciate it.

Answer №1

When it comes to loading language files using ajax, my approach is as follows...

$.get( "test.txt", function( data ) {
  console.log( "Successfully loaded data.", data );
});

In order to implement this solution, ensure that you grant read access to your app by configuring the `config.xml` file.

<feature name="http://api.phonegap.com/1.0/file" />

Answer №2

Here is a suggestion from my own set of functions. Begin by obtaining the file system and then extracting the root path. Customize it to suit your particular requirements.

Next, you can proceed as follows:

In my case, app_FileSystem serves as a global variable that is populated by GetAppFS.

Once you have obtained the FS and the root path, you can simply make an ajax call or utilize getjson with the appropriate dataType specified. This approach has proven effective for me.

Don't forget to consult the helpful documentation available here:

app_FileSystem.root.fullPath; // Retrieve the full path of the application file system root

function GetAppFS ()
{
    var self = this;
   self.state = "";                     // keep track of the process state for debugging purposes
   self.fileSystem = {};

    window.requestFileSystem ( LocalFileSystem.PERSISTENT, 0, getFileSystemSuccess, dispatchFailure );

    /**
     *
     * Upon receiving a valid file system, we need to request all documents within the file system.
     *
     */
    function getFileSystemSuccess ( fileSystem )
    {
        self.state = "Received File System";
         self.fileSystem = fileSystem;
        app_FileSystem = fileSystem;
         OnFSReady ();
    };

    /**
     *
     * All our functions have a failure callback, hence we provide dispatchFailure. If an error arises, we log it to the console and notify the associated failure function attached to self.failure(), if any.
     *
     */
    function dispatchFailure ( e )
    {
        // something went wrong :-(
        console.log ("While " + self.state + ", encountered error: " + JSON.stringify(e));
         alert ("dev FS ERROR ");
    };  
};

Answer №3

If you're looking to access the contents of the `www` folder in PhoneGap using the file plugin, I recommend utilizing the `resolveLocalFileSystemURL` method. This will allow you to use the `cordova.file.applicationDirectory` property for locating the `www` folder.

Ensure that you have installed the plugin by running:

$ cordova plugin add org.apache.cordova.file

After installing the plugin, you can create an object like the following to manage and process the files within the `www` folder:

var FileManager = {

  /**
   * Run this.entryHandler for all files and directories in PhoneGap's www folder
   */
  run: function () {

    window.resolveLocalFileSystemURL(
      cordova.file.applicationDirectory + 'www/',
      this.directoryFoundHandler,
      this.errorHandler
    );

  },

  /**
   * Successfully read the directory, now read the entries.
   *
   * @param {DirectoryEntry} directoryEntry
   */
  directoryFoundHandler: function (directoryEntry) {

    var directoryReader = directoryEntry.createReader();

    directoryReader.readEntries(
      this.entryHandler,
      this.errorHandler
    );

  },

  /**
   * Files successfully found. Parse them!
   *
   * @param {Array.<FileEntry>} entries
   */
  entryHandler: function (entries) {

    entries.forEach(function (entry) {

      // Process the files accordingly
      if (entry.isDirectory) {
        // It's a directory, may require further processing
      } else {
        // It's a file, perform desired actions
      }

    });

  },


  /**
   * Handle any errors encountered
   *
   * @param {FileError} error
   */
  errorHandler: function (error) {

    console.log("ERROR", error);

  }

};

Answer №4

Encountering the same issue without wanting to rely on jQuery, I decided to share my solution here.

An important point to note is that the files in the www directory of Cordova / Phone Gap are stored as assets in the Android environment. This implies:

  • They are bundled within the .apk distribution file, which is a compressed archive. Android accesses these files directly from the .apk file and doesn't keep them separately in the local file system.
  • As a result, these files are read-only and cannot be accessed using the Cordova File plugin.

Upon delving into the relevant Android sources of Cordova, it becomes apparent that Cordova handles URIs with a 'file' scheme, beginning with '/android_asset/', through Android's asset access functions. (It would be interesting to explore how Cordova manages this in the iOS realm.)

In essence, utilizing XMLHttpRequest is likely the most portable method for accessing files located in the www folder if direct file content access is required. (Alternative methods may suffice if only the file path is needed for certain operations.)

Below is the code snippet where filename represents the path within the www folder sans the "www/" prefix:

var readFileInWWWFolder = function(filename, onSuccess, onFailure){

    var request = new XMLHttpRequest();

    request.onload = function() {

        var arrayBuffer = request.response;

        if (arrayBuffer) {

            onSuccess(new Uint8Array(arrayBuffer));
        }
        else {

            onFailure();
        }
    };

    request.open("GET", filename, true);
    request.responseType = "arraybuffer";
    request.send();
};

This approach has been verified with Cordova 4.3.0 and Android 4.4.2 (Kitkat).

Answer №5

A helpful tip is to save each file from the www folder to Cordova's persistent file system using fs.download. You can find more information in my original post.

To start, follow these steps in Terminal:

  1. npm install cordova-promise-fs
  2. cordova plugin add cordova-plugin-file --save
  3. cordova plugin add cordova-plugin-file-transfer --save

Next, in your front-end code:

import CordovaPromiseFS from 'cordova-promise-fs'

const fs = CordovaPromiseFS({
  persistent: true,
  storageSize: 200 * 1024 * 1024,
  concurrency: 3
})

If you are using React, make sure to declare the above code before creating the component Class. The following code should be placed within its own function inside the component Class. Check out my GitHub comment for more information.

window.resolveLocalFileSystemURL(
  cordova.file.applicationDirectory + 'www/epubs/alice.epub',
    // If successful...
    (fileSystem) => {
      const downloadUrl = fileSystem.toURL()
      const localUrl = 'alice.epub' // the filename it is stored as on the device
      fs.download(
        downloadUrl,
        localUrl,
        (progressEvent) => {
          if (progressEvent.loaded && progressEvent.total) {
          console.log('progress', Math.round((progressEvent.loaded / progressEvent.total) * 100))
        }
      }
    ).then((filedata) => {
      return fs.toInternalURL(localUrl)
    })
    .then((localPath) => {
      this.setState({ epubPath: localPath })
    }).catch((error) => {
      console.log('an error occurred', error)
    })
  },
  // If unsuccessful
  (err) => {
    console.log(err)
  }
)

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

An AJAX script for dynamically adding, modifying, and removing records from a database

How can I implement a functionality where by pressing "-" the vote is removed from the database, and when any other number is selected, the vote will be updated in the database with that value? The default value of the dropdown list is votacion.votCalific ...

Firebase-admin fails to deliver iOS APN notifications

Push notifications are successfully being sent to my iOS device from Firebase Console Notifications, working flawlessly in both foreground and background. However, when attempting to send notifications with Firebase-admin by NodeJS, only foreground deliver ...

Animation using jQuery is functional on most browsers, however, it seems to

After creating an animation to simulate an opening door using jQuery, I discovered that it works perfectly on Firefox 24, Chrome 28, and IE 8. However, Safari presents a problem - the door opens but then the "closed" door reappears at the end of the animat ...

Transferring information from jQuery to AngularJS controller

Is there a way to transfer data generated by jQuery into an AngularJS controller? <textarea ng-click="showSelectedText(selection.text)" name="editor1" id="editor1" cols="118" rows="35"> Using jQuery to collect data: $( "#editor1" ).select(funct ...

Differences in behavior of jquery-ajax between Mozilla Firefox and Google Chrome

I am facing a peculiar issue. My current task involves using the Google Maps API to retrieve latitude and longitude data based on zip codes, with the following script: $(document).ready(function(){ $.ajax({ url:"http://maps.googleapis.com/maps/ ...

unable to verify identity through a web browser

When I try to launch my Android application built with Ionic 2 on my smartphone, I encounter this error: If you need a tutorial for the application, check out: https://medium.com/appseed-io/third-party-authentication-for-your-ionic-2-mobile-app-9fdd43169d ...

Retrieve the information sent back by AngularJS and pass it to a JavaScript function

I am working on a form using AngularJS to create a new object, which is returned as "marker." $scope.createMarker = function() { $http.post('/markers/create', $scope.marker) .success(function(data) { }) .error(funct ...

Using a text box in jQuery to perform basic calculations is a straightforward process

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Creating a Lens Calculator Web App</title> <link href="http://code.jquery.com/mobile/1.0a3/jque ...

Stop Chrome from automatically scrolling to the top of the page when making changes to the DOM

Currently utilizing Action Cable to create a discussion room where users can exchange questions. Upon posting a question, all participants within the room are supposed to see it. Nonetheless, I've encountered an odd issue specifically on Chrome: whene ...

Unable to modify the hover color on the image or icon

After creating a circle icon with an image in the center, I wanted to make the image change colors on hover. The main focus of the icon is the circle itself. In my attempt to achieve this effect, I included the following code for the circle icon: .circle- ...

The Access-Control-Allow-Origin error is preventing the Angularjs post request from going through

I am encountering an issue with my index.html file that is sending a post request to localhost:3000/SetUser. The error I keep receiving states XMLHttpRequest cannot load https://localhost:3000/SetUser. No 'Access-Control-Allow-Origin' header is p ...

Trigger oncopy on the body excluding specific class

Is there a way to execute a function on document.body.oncopy but exclude a certain class (defined for div elements) from this function call? I want to avoid calling the function on specific classes, is there a method to achieve this? ...

Implement the usage of plainToClass within the constructor function

I have a dilemma with my constructor that assigns properties to the instance: class BaseModel { constructor (args = {}) { for (let key in args) { this[key] = args[key] } } } class User extends BaseModel { name: str ...

Encountering a syntax error with the AngularJS ng-class expression

While navigating through a tutorial application designed for use with the Ionic platform, which is based on angular 1.2.4, I encountered a perplexing error in this Angular markup: <content has-header="true" scroll="false"> <list> ...

In JavaScript, implement event listeners exclusively on the main container and its immediate child elements

Is there a way to target just the main container and its second child elements for an event? Specifically, targeting id="container" and all elements with class="secondChild" Currently, I have a listener attached to all elements inside ...

Open in a new tab for enhanced content formatting in Prismic on NextJs

In my Prismic RichText editor, I have included two files (terms and conditions) that I would like to open in a new tab. Unfortunately, Prismic does not offer an option like target _blank for this functionality. I am currently working with NextJs and Tail ...

Get the div to occupy the rest of the available height

I am facing a challenge with two divs on my webpage. The bottom one contains content that expands the highest. The page is set to 100% height and width using the CSS property position: absolute. <style> body, html { height:100%, width:100% } ...

What is the process for importing a JavaScript file into a Vue component?

Having trouble importing JSON results into a Vue component? The results are as follows: [{"id":"d023c5e3-ca3c-4d97-933a-1112a8516eee", "score":9001, "updated":"2018-12-07T13:48:33.6366278", "player":Johanna, "category":Funny}, {"id":"398b65fb-e741-4801-b ...

Saving user-generated inputs within a React.js component's state, focusing on securely handling passwords

Curious about forms in React.js? I don't have any issues, but I'm wondering if there are potential flaws in my approach. I've set up a basic form with two inputs for email and password: <input type="email" name="email" value= ...

In Vue firebase, ensure that the prop is only passed down after it has been

I am facing an issue where I need to pass down the Firebase user as a prop from the root component to my child components. I managed to achieve this by passing the user to my router. However, the problem arises when I wrap my new Vue instance in an onAuthS ...