2

I have a web app using filesaver.js to create some files that will be downloaded later to a user's computer. I transfered the same scripts files I am using for this web app in my cordova application. Everything is working perfect except the download button I have in my app. It won't fire anything. Is there any cordova plugin to use to get access to the file system of the device or something else I can do?

Here is some markup: html

 <link rel="stylesheet" type="text/css" href="css/sliders.css">
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="css/transformations.css">
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/bootstrap.min.js"/></script>
<script type="text/javascript" src="js/save.js"></script>
<script src="js/bootbox.js" type="text/javascript"></script>
<script type="text/javascript" src="js/transformations.js"></script>


 <div class="btn btn-block btn-success" onclick="savefile('hello.txt','maamaamamamam\nu')">Download code</div>

Js

 $(document).ready(function(){
      //some functions
  });
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
    console.log(cordova.file);
}

var myFileUrl = "kk";
function saveFile (fileName, fileData) {
    // Get access to the file system
    window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fileSystem) {
        // Create the file.
        fileSystem.root.getFile(fileName, { create: true, exclusive: false }, function (entry) {
            // After you save the file, you can access it with this URL
            myFileUrl = entry.toURL();
            entry.createWriter(function (writer) {
               writer.onwriteend = function (evt) {
                    alert("Successfully saved file to " + myFileUrl);
                };
                // Write to the file
                writer.write(fileData);
            }, function (error) {
                alert("Error: Could not create file writer, " + error.code);
            });
        }, function (error) {
            alert("Error: Could not create file, " + error.code);
        });
    }, function (evt) {
        alert("Error: Could not access file system, " + evt.target.error.code);
    });
}

The problem is that by using this code i get no errors but also nothing happens.Any help would be appreciated

cssGEEK
  • 994
  • 2
  • 15
  • 38
  • 1
    Mobile devices are far more restricted regarding access to their filesystem than desktop computers and desktop browsers. I am not familiar with filesaver.js, but if it assumes a desktop environment it may not work as you expect it to work in the embedded webview of a Cordova app. – xmnboy Mar 10 '15 at 00:09
  • You can run the Cordova app in a web browser (`cordova serve`) and then provide us with any console errors; [as well as a MCVE](http://stackoverflow.com/help/mcve) that reproduces this issue. Otherwise this isn't helpful to future visitors because there's nothing for them to search off of. "Not working" is pretty vague, we need specifics and we need to see code. – George Stocker Mar 12 '15 at 12:39

1 Answers1

9

Working with files in a webview on a mobile device is quite a bit different than doing it in a browser, and the author of filesaver.js even addresses that in his docs where he points out the issue with iOS. One cross-platform solution for saving the file would be to use Cordova's File plugin (https://github.com/apache/cordova-plugin-file), then you can do something like this:

In your markup:

<a href="#" onclick="saveFile('myFile.txt', 'Some text to write into file');">Save file</a>

In your Javascript:

var myFileUrl = "";
function saveFile (fileName, fileData) {
    // Get access to the file system
    window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fileSystem) {
        // Create the file.
        fileSystem.root.getFile(fileName, { create: true, exclusive: false }, function (entry) {
            // After you save the file, you can access it with this URL
            myFileUrl = entry.toURL();
            entry.createWriter(function (writer) {
               writer.onwriteend = function (evt) {
                    alert("Successfully saved file to " + myFileUrl);
                };
                // Write to the file
                writer.write(fileData);
            }, function (error) {
                alert("Error: Could not create file writer, " + error.code);
            });
        }, function (error) {
            alert("Error: Could not create file, " + error.code);
        });
    }, function (evt) {
        alert("Error: Could not access file system, " + evt.target.error.code);
    });
}

Here is a complete working example using @cssGEEK's code from the question and stripped down to the bare essentials. The only external file that's included is cordova.js, which is automatically included in the Cordova project.

<!DOCTYPE html>
<html>
<head>
</head>
<body>
    <input type="button" value="Download code" onclick="saveFile('hello.txt', 'maamaamamamam\nu');">
    <script src="cordova.js"></script>
    <script>
        document.addEventListener("deviceready", onDeviceReady, false);
        function onDeviceReady() {
            alert("Got deviceready");
        }

        var myFileUrl = "kk";
        function saveFile (fileName, fileData) {
            // Get access to the file system
            window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fileSystem) {
                // Create the file.
                fileSystem.root.getFile(fileName, { create: true, exclusive: false }, function (entry) {
                    // After you save the file, you can access it with this URL
                    myFileUrl = entry.toURL();
                    entry.createWriter(function (writer) {
                       writer.onwriteend = function (evt) {
                            alert("Successfully saved file to " + myFileUrl);
                        };
                        // Write to the file
                        writer.write(fileData);
                    }, function (error) {
                        alert("Error: Could not create file writer, " + error.code);
                    });
                }, function (error) {
                    alert("Error: Could not create file, " + error.code);
                });
            }, function (evt) {
                alert("Error: Could not access file system, " + evt.target.error.code);
            });
        }
    </script>
</body>
</html>

You can test this as follows. Open a command prompt in the directory where you keep your source code and:

  1. Create a Cordova project and move into the project directory. At the command prompt, type:

    cordova create hello com.example.hello HelloWorld

    cd hello

  2. In the www directory inside the project directory, replace the entire contents of the www/index.html file with the above code.

  3. In the project directory, at the command prompt, type cordova plugin add org.apache.cordova.file to add the File plugin.

  4. In the project directory, at the command prompt, type cordova run android to build and deploy the app to the emulator or your device.

  5. In the emulator or on the device, wait until you see the Got deviceready alert and dismiss it; the File plugin is now available.

  6. In the emulator or on the device, click the Download code button.

You should see:

File Downloaded Successfully

Mike Dailor
  • 1,226
  • 8
  • 16
  • how can i include this plugin to my project? – cssGEEK Mar 10 '15 at 16:47
  • 1
    I see you've tagged your question with "intel-xdk", so I'm not sure whether you're building locally with the Cordova CLI (Command Line Interface) or with the XDK, If you're building locally, open a command prompt in the root directory of your project (where you keep your www folder) and: 'cordova plugin add org.apache.cordova.file'. If you're using the XDK, go to the Projects panel, select your project, click PLUGINS AND PERMISSIONS in the MOBILE APP SETTINGS panel, and check the File checkbox in the Included Plugins list. – Mike Dailor Mar 12 '15 at 11:45
  • The problem is that i get no error.Not even an alert event – cssGEEK Mar 12 '15 at 19:52
  • Also i am using intel-xdk and i have checked the file plugin – cssGEEK Mar 12 '15 at 20:11
  • 1
    Re: your comment "When I run this on a browser the only error I get is savefile is not defined."... You can't run this code sample in a browser and expect it to work, it uses a Cordova plugin and expects to be running in a Cordova app on an Android/iOS/etc. device. – Mike Dailor Mar 12 '15 at 20:54
  • 2
    And BTW why are you people downvoting my answer? This is actual working code (albeit with a bunch of "alerts()"'s added) from one of my Cordova applications that creates, writes and saves a file on the device when the user presses a button, which is exactly what the OP asked for. So what's the problem? – Mike Dailor Mar 12 '15 at 20:58
  • I was going to ask why it was getting downvoted as well. Looked good to me, and basically consistent with some code I have for file system logging. I upvoted it to help. :-) – barry-johnson Mar 18 '15 at 01:00
  • As a follow-up to this, I noticed when I clicked through to cssGEEK's profile he was actually in temporary suspension - I have not previously seen that. My guess is that he downvotes anyone who doesn't magically solve his problem when he says "can I haz the codez pls" – barry-johnson Mar 18 '15 at 03:05
  • Actually i didn't downvote you.Also when i use your code nothing happens – cssGEEK Mar 19 '15 at 21:00
  • 1
    @cssGEEK: when you say "when i use your code nothing happens": are you running it in a web browser with a file:// URL, or are you running it inside a Cordova app on an emulator or on an actual device? Because if you run it in a web browser, it's not going to work. The Cordova plugin will not get loaded, there is no `deviceready` event, and that's right, nothing happens. – Mike Dailor Mar 29 '15 at 16:59
  • i use it on a device(Nexus 5) but i use both deviceready and $(document).ready() – cssGEEK Mar 29 '15 at 17:07
  • 1
    I added a working example based on your code to my answer. Please give that a try, this works for me in the Nexus 7 emulator and on a Nexus 7 1st gen tablet. – Mike Dailor Mar 29 '15 at 22:50