Our website is made possible by displaying online advertisements to our visitors. Please consider supporting us by disabling your ad blocker.

Manage Files In Android And iOS Using Ionic Framework

TwitterFacebookRedditLinkedInHacker News

You may one day find yourself needing to make an Ionic Framework Android and iOS app that downloads media or in-app purchase content from a remote web server to the users device. Maybe you created an audio app that plays music from the cloud and you decided to cache upcoming songs in your playlist like Google Music does. This will involve downloading the media files to your device in the background so it is ready to go.

Lucky for us, Apache Cordova has a set of File APIs that we can use in our Ionic project for exactly this.

Let’s start by creating a fresh Ionic Framework project with the Android and iOS platforms included.

ionic start ExampleProject blank
cd ExampleProject
ionic platform add android
ionic platform add ios

Please remember that if you are not using a Mac, you cannot add the iOS platform.

The next thing we want to do is add the Apache Cordova file plugin into our project. We can add it to our project by running the following:

cordova plugin add org.apache.cordova.file-transfer

The file plugin is quite large, so we’re only going to focus on the following items:

  • Creating and loading directories
  • Creating and loading files
  • Downloading files from remote servers

To start things off, open your www/js/app.js file and include the FileController seen below:

exampleApp.controller("FileController", function($scope, $ionicLoading) {

    $scope.download = function() {

    }

    $scope.load = function() {

    }

});

The focus of this tutorial will be loading files and downloading files. File and directory creation will be included in the process.

Let’s start by working with the download() method. It will create a directory if it doesn’t already exist, and then create a fresh file space. The remote file will then be downloaded into this fresh file space on the devices local file system.

$scope.download = function() {
    $ionicLoading.show({
      template: 'Loading...'
    });
    window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fs) {
        fs.root.getDirectory(
            "ExampleProject",
            {
                create: true
            },
            function(dirEntry) {
                dirEntry.getFile(
                    "test.png",
                    {
                        create: true,
                        exclusive: false
                    },
                    function gotFileEntry(fe) {
                        var p = fe.toURL();
                        fe.remove();
                        ft = new FileTransfer();
                        ft.download(
                            encodeURI("https://ionicframework.com/img/ionic-logo-blog.png"),
                            p,
                            function(entry) {
                                $ionicLoading.hide();
                                $scope.imgFile = entry.toURL();
                            },
                            function(error) {
                                $ionicLoading.hide();
                                alert("Download Error Source -> " + error.source);
                            },
                            false,
                            null
                        );
                    },
                    function() {
                        $ionicLoading.hide();
                        console.log("Get file failed");
                    }
                );
            }
        );
    },
    function() {
        $ionicLoading.hide();
        console.log("Request for filesystem failed");
    });
}

The above code will download remote image ionic-logo-blog.png and save it to /ExampleProject/test.png. You can get as fancy as you want with this function, but for simplicity I am just calling the file test.png.

The next thing we need to worry about is the load() method which will behave very similar to the download() method. It just never actually downloads anything and has no write permissions.

$scope.load = function() {
    $ionicLoading.show({
      template: 'Loading...'
    });
    window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fs) {
        fs.root.getDirectory(
            "ExampleProject",
            {
                create: false
            },
            function(dirEntry) {
                dirEntry.getFile(
                    "test.png",
                    {
                        create: false,
                        exclusive: false
                    },
                    function gotFileEntry(fe) {
                        $ionicLoading.hide();
                        $scope.imgFile = fe.toURL();
                    },
                    function(error) {
                        $ionicLoading.hide();
                        console.log("Error getting file");
                    }
                );
            }
        );
    },
    function() {
        $ionicLoading.hide();
        console.log("Error requesting filesystem");
    });
}

Nothing new was introduced in the load() method that didn’t already exist in the download() method. If you wanted to fancy up your code you could do a lot of optimizations to what I provided. For example, you could pull out all the nested functions and make them re-usable in your controller. I’ll leave it to you to be inventive.

Now that we have two methods for managing images, we should probably present them to the screen. In your www/index.html file, add the following code:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
        <title></title>
        <link href="lib/ionic/css/ionic.css" rel="stylesheet">
        <link href="css/style.css" rel="stylesheet">
        <script src="lib/ionic/js/ionic.bundle.js"></script>
        <script src="cordova.js"></script>
        <script src="js/app.js"></script>
    </head>
    <body ng-app="starter">
        <ion-pane>
            <ion-header-bar class="bar-stable">
                <h1 class="title">Ionic Blank Starter</h1>
            </ion-header-bar>
            <ion-content ng-controller="FileController">
                <button class="button" ng-click="download()">Download</button>
                <button class="button" ng-click="load()">Load</button>
                {{imgFile}}
                <img ng-src="{{imgFile}}">
            </ion-content>
        </ion-pane>
    </body>
</html>

In the above code, you’ll notice the stuff that I changed. The UI will have two buttons, one for downloading and one for loading. When pressed, a loading message will display until the image has processed. Then the image path and image will display on the screen.

A video version of this article can be seen below.

Nic Raboy

Nic Raboy

Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in C#, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Unity. Nic writes about his development experiences related to making web and mobile development easier to understand.