Recommended Android/IOS file chooser plugin

Hi all,

My apps need choose file pdf, docx, excel,… and upload to server.

I have search and find some plugins:


but don’t support IOS.

Can you recommended plugin?

Thank you so much!

2 Likes

please help @mhartington

I have same question!
Anybody reply please!
@snailred @mhartington

Thanks

Well either plugin will work for android so you can use which ever you want.
For iOS, you sadly don’t have a file browser/chooser.
Not going to be possible sadly.

1 Like

Apparently there’s this one, haven’t tried it and sadly it’s only for iOS8 (and higher?):

Anyway I suppose that if you understand the physical file system structure of iOS and you have the time then you could always build a UI yourself using the Cordova File plugin. Don’t know about iCloud and so on though.

By the way I tried https://github.com/don/cordova-filechooser and it worked perfectly.

The other one (https://github.com/cdibened/filechooser) seems more complicated to set up and gave me build errors on my initial attempt, so I went with the other one.

Hi @leob,

please share some code for how to use cordova-filechooser in ionic.

Well I’ve done it like this, this should work on Android and on iOS but I’ve only tested it on Android:

      function checkFileType(path, fileExt) {
        return path.match(new RegExp(fileExt + '$', 'i'));
      }

      function chooseFileOk(deferred, uri, fileExt) {
        $log.debug('FileManager#chooseFile - uri: ' + uri + ', fileType: ' + fileExt);

        if (!checkFileType(uri, fileExt)) {
          deferred.reject('wrong_file_type');
        } else {
          deferred.resolve(uri);
        }
      }

      function chooseFileError(deferred, source) {
        $log.debug('FileManager#chooseFile - ' + source + ' error: ' + JSON.stringify(error));

        // assume operation cancelled
        deferred.reject('cancelled');
      }

      var chooseFile = function (fileExt) {
        var deferred = $q.defer();

        // iOS (NOTE - only iOS 8 and higher): https://github.com/jcesarmobile/FilePicker-Phonegap-iOS-Plugin
        if (ionic.Platform.isIOS()) {

          FilePicker.pickFile(
            function (uri) {
              chooseFileOk(deferred, uri, fileExt);
            },
            function (error) {
              chooseFileError(deferred, 'FilePicker');
            }
          );

        // Android: https://github.com/don/cordova-filechooser
        } else {

          fileChooser.open(
            function (uri) {
              chooseFileOk(deferred, uri, fileExt);
            },
            function (error) {
              chooseFileError(deferred, 'fileChooser');
            }
          );
        }

The main function is called “chooseFile” and I can pass it a “fileExt” parameter to restrict the kind of files that can be selected (e.g. only ‘pdf’ files).

Typically you’d package the function inside a service. It returns a promise so you then use it like:

   FilePickerService.chooseFile('.pdf').then(function(url) {
       // do something with the selected file
   }).catch(error) {
       // something wrong, log it or show a message
   });

The code uses 2 plugins: FilePicker for iOS and fileChooser for Android. Install them as follows:

ionic plugin add https://github.com/jcesarmobile/FilePicker-Phonegap-iOS-Plugin.git
ionic plugin add https://github.com/don/cordova-filechooser

Does that make sense?

2 Likes

can you now tell if filechooser for ios is workable anyway ?

Thanks for sharing such a nice solution…
I faced Issue in Pdf filtering in above script. In android file extension was not available in uri. to solve this issue I used cordova-plugin-filepath for getting native file path.
1 plugin used.
cordova plugin add cordova-plugin-filepath
I modified function chooseFileOk() see below …

` function chooseFileOk(deferred, uri, fileExt) {
$log.debug('FileManager#chooseFile - uri: ’ + uri + ', fileType: ’ + fileExt);

                window.FilePath.resolveNativePath(uri, function(localFileUri) {
                    if(localFileUri!= 'undefined' && localFileUri!="" )
                    {
                        if(localFileUri.match(new RegExp(fileExt + '$', 'i'))){
                            console.log("This must execute.....");
                            deferred.resolve(uri);
                        }else{
                            deferred.reject('wrong_file_type');
                        }
                    }else{
                        deferred.reject('URI NOT Resulted to any File in system');
                    }
                });
        }`

Thanks.

As an addition to this post, the original cordova-plugin-filepath does not work on Android 6, due to the permission system.

I forked the code, and updated the plugin, although it requires Cordova 6.0.0 now (originally, it required Cordova 3.4.0).

Version 1 of the updated plugin can be found at:

Installation:

Either:
cordova plugin add cordova-filepath-resolver

Or:
ionic plugin add cordova-filepath-resolver

… whichever you prefer.

[EDIT] Plugin is in the repo’s now, updated the links

hi leob,

I use this code.but i get following error

filechooser.chooseFileok is not a function

How can i access only audio files in both internel and externel storage using fileChooser plugin.

Please Advice me…

Thanks & Regards,

Probably you didn’t install the Cordova plugins then? You need to do:

ionic plugin add https://github.com/jcesarmobile/FilePicker-Phonegap-iOS-Plugin.git
ionic plugin add https://github.com/don/cordova-filechooser

I think that’s the reason for the “missing function”.

And regarding the audio files, you can set file name filters on the plugin.

hi leob,

again i reinstall plugin
ionic plugin add https://github.com/jcesarmobile/FilePicker-Phonegap-iOS-Plugin.git
ionic plugin add https://github.com/don/cordova-filechooser

This is my code

MediaSrv.chooseFile(’.mp3’).then(function(url) {
console.log(url);
});

and

app.factory(“MediaSrv”, function($q) {
var deferred = $q.defer();

function checkFileType(path, fileExt) {
    return path.match(new RegExp(fileExt + '$', 'i'));
  }
  function chooseFileOk(deferred, uri, fileExt) {
    $log.debug('FileManager#chooseFile - uri: ' + uri + ', fileType: ' + fileExt);

    if (!checkFileType(uri, fileExt)) {
      deferred.reject('wrong_file_type');
    } else {
      deferred.resolve(uri);
    }
  }
  function chooseFileError(deferred, source) {
    $log.debug('FileManager#chooseFile - ' + source + ' error: ' + JSON.stringify(error));

    // assume operation cancelled
    deferred.reject('cancelled');
  }
 var chooseFile = function (fileExt) {
    //function chooseFile(fileExt){
   var deferred = $q.defer();

    // iOS (NOTE - only iOS 8 and higher): https://github.com/jcesarmobile/FilePicker-Phonegap-iOS-Plugin
      if (ionic.Platform.isIOS()) {

      FilePicker.pickFile(
        function (uri) {
          chooseFileOk(deferred, uri, fileExt);
        },
        function (error) {
          chooseFileError(deferred, 'FilePicker');
        }
      );

    // Android: https://github.com/don/cordova-filechooser
    } else {


      fileChooser.open(
        function (uri) {
          chooseFileOk(deferred, uri, fileExt);
        },
        function (error) {
          chooseFileError(deferred, 'fileChooser');
        }
      );

}
}

    return deferred.promise;

});
But Still i get MediaSrv.chooseFileok is not a function error

Pls help me

Thanks& Regards,

The definition of your factory looks a bit weird.

Why does your factory start with declaring a deferred, and end with returning a deferred? And the function ‘chooseFile’ itself isn’t exported from the factory. Maybe that’s the reason why it says “chooseFileOk” unknown.

Have a look at my implementation:

;(function () {
  "use strict";

  angular.module('app.image')

    //
    // https://github.com/apache/cordova-plugin-file
    // http://www.raymondcamden.com/2014/08/18/PhoneGapCordova-Example-Getting-File-Metadata-and-an-update-to-the-FAQ
    // http://www.html5rocks.com/en/tutorials/file/filesystem/
    // http://community.phonegap.com/nitobi/topics/dataurl_to_png
    //

    .factory('FileManager', function ($q, $log, $cordovaFile, $cordovaFileTransfer) {

      var downloadFile = function(sourceURI, targetDir, targetFile) {

        var deferred = $q.defer();

        $log.debug("FileManager#downloadFile source (original): '" + sourceURI + "'");
        sourceURI = decodeURI(sourceURI);

        var targetPath = targetDir + targetFile;
        var trustHosts = true;
        var options = {};

        $cordovaFileTransfer.download(sourceURI, targetPath, options, trustHosts).then(
          function(result) {
            deferred.resolve(result);

          }, function(error) {
            deferred.reject(error);

          }, function (progress) {
            //$timeout(function () {
            //  $scope.downloadProgress = (progress.loaded / progress.total) * 100;
            //})
          });

        return deferred.promise;
      };

      var getFileInfo = function (baseDir, filePath) {
        var deferred = $q.defer();

        $log.debug("FileManager#checkFile baseDir = '" + baseDir + "', filePath = '" + filePath + "'");

        $cordovaFile.checkFile(baseDir, filePath).then(
          function (fileEntry) {
            fileEntry.getMetadata(
              function (result) {
                deferred.resolve(result);
              },
              function (error) {
                deferred.reject(error);
              }
            );
          },
          function (error) {
            deferred.reject(error);
          }
        );

        return deferred.promise;
      };

      var removeFile = function (baseDir, filePath) {
        $log.debug("FileManager#removeFile baseDir = '" + baseDir + "', filePath = '" + filePath + "'");

        return $cordovaFile.removeFile(baseDir, filePath);
      };

      //function checkFileType(path, fileExt) {
      //  return path.match(new RegExp(fileExt + '$', 'i'));
      //}

      var checkFileType = function (uri, fileType) {
        var deferred = $q.defer();

        $log.log("FileManager#checkFileType uri = " + uri + " fileType = " + fileType);

        // See: https://github.com/hiddentao/cordova-plugin-filepath and:
        // stackoverflow.com/questions/31338853/cordova-camera-plugin-obtain-full-image-path-from-gallery-android
        window.FilePath.resolveNativePath(uri,

          function (result) {
            var fileURI = 'file://' + result;

            $log.log('FileManager#checkFileType uri = ' + uri + ' fileURI = ' + fileURI);

            // See: https://github.com/cfjedimaster/Cordova-Examples/wiki/PhoneGap-Cordova-File-System-FAQ#meta
            window.resolveLocalFileSystemURL(fileURI,
              function (fileEntry) {

                fileEntry.file(function(file) {
                  var s = "";
                  s += "name: " + file.name + " ";
                  s += "localURL: " + file.localURL + " ";
                  s += "type: " + file.type + " ";
                  s += "lastModifiedDate: " + (new Date(file.lastModifiedDate)) + " ";
                  s += "size: " + file.size;

                  $log.info('FileManager#checkFileType uri = ' + uri + ' fileURI = ' + fileURI + ' INFO: ' + s);

                  if (file.type && file.type === fileType) {
                    deferred.resolve(file);
                  } else {
                    $log.warn('FileManager#checkFileType uri = ' + uri + ' fileURI = ' + fileURI +
                      ' wrong file type: ' + file.type + ' instead of ' + fileType);

                    deferred.reject('wrong_file_type');
                  }
                });
              },
              function (error) {
                $log.error('FileManager#checkFileType uri = ' + uri + ' fileURI = ' + fileURI +
                  ' ERR = ' + JSON.stringify(error));

                deferred.reject(error);
              }
            );
          },
          function (error) {
            $log.error('FileManager#checkFileType uri = ' + uri + ' ERR = ' + JSON.stringify(error));

            deferred.reject(error);
          }
        );

        return deferred.promise;
      };

      function chooseFileOk(deferred, uri) {
        $log.log('FileManager#chooseFile - uri: ' + uri);

        deferred.resolve(uri);
      }

      function chooseFileError(deferred, source) {
        $log.debug('FileManager#chooseFile - ' + source + ' error: ' + JSON.stringify(error));

        // assume operation cancelled
        deferred.reject('cancelled');
      }

      var chooseFile = function () {
        var deferred = $q.defer();

        // iOS (NOTE - only iOS 8 and higher): https://github.com/jcesarmobile/FilePicker-Phonegap-iOS-Plugin
        if (ionic.Platform.isIOS()) {

          FilePicker.pickFile(
            function (uri) {
              chooseFileOk(deferred, uri);
            },
            function (error) {
              chooseFileError(deferred, 'FilePicker');
            }
          );

        // Android: https://github.com/don/cordova-filechooser
        } else {

          fileChooser.open(
            function (uri) {
              chooseFileOk(deferred, uri);
            },
            function (error) {
              chooseFileError(deferred, 'fileChooser');
            }
          );
        }

        return deferred.promise;
      };

      return {
        downloadFile: downloadFile,
        checkFileType: checkFileType,
        getFileInfo: getFileInfo,
        removeFile: removeFile,
        chooseFile: chooseFile
      };
    });
}());

Hello,
I tried the code you provide and I get the file browser to show up and I can pick a file. However, the callback is not getting triggered…

I see this error in the android console
W/CordovaInterfaceImpl: Got an activity result, but no plugin was registered to receive it

I am using cordova 6.3.1 and SDK 23 android 5.2.2

Thanks for your help.

I’ll have a look at it, right now I’m traveling but I’ll be in a hotel with Wifi tonight, will have a look when I have some time …

Hello Leob,

Just checking to see if you had a moment to look into this issue…

Thanks

Not yet but it’s in my inbox, I’ll get around to it.

Will Same plugin work on Ionic 2, I am trying the same for Ionic 2 but getting the following error on real device
[Error] EXCEPTION: undefined is not an object (evaluating ‘a.plugins.fileChooser.open().then’)

FilePicker is Available & returning true, Following is my code

fileChooser = {
open () : Promise {
console.log(‘FilePicker will Load in new Way’);
return FilePicker.pickFile().then((uri) => {
return uri;
}, (err) => {
console.log(‘Failed to Load’);
});
},
}

Well, for Android I’m using the file chooser plugin but for iOS I’ve switched from the “FilePicker” plugin to a simple HTML5 “file” input element, which turns out to be easier to use AND functionally superior … see here how to implement it:

Actually I did not literally use the code from the gist, I still had to make a few changes to get it working properly (with the code from the gist the “onchange” event didn’t always fire). If anyone is interested in my final solution then I can post it here.

And for iOS 9 and higher you need to configure “entitlements” (for iOS 10 therre’s even an additional requirement), all in all I think I spent the better part of a week just to get the iOS solution working!