Committed! Would be great to get more platforms on board. These are super useful!
On Tue, May 13, 2014 at 9:53 PM, Andrew Grieve <agri...@chromium.org> wrote: > I don't think we should try to make cross-platform-compromise decisions on > this one (e.g. mapping desktop to /mnt/sdcard). requestLocalFileSystem() > gives a x-platform "data" and "temp" directory. What I want to expose here > are the platform-specific directories (requires users to know their > platform). > > This puts properties on "cordova.file.fooDirectory". > Paths that don't exist on a platform are set to null. > > > > Proposed patch (missing docs, but I'll add before committing): > > From 1a5d8e3306e9b31aa5a4dec136451b92264ee01a Mon Sep 17 00:00:00 2001 > From: Andrew Grieve <agri...@chromium.org> > Date: Tue, 13 May 2014 21:46:13 -0400 > Subject: [PATCH] CB-285 Add cordova.file.*Directory properties for iOS & > Android > > --- > plugin.xml | 9 +++++++ > src/android/FileUtils.java | 20 +++++++++++++++ > src/ios/CDVFile.m | 30 +++++++++++++++++++++++ > www/fileSystemPaths.js | 61 > ++++++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 120 insertions(+) > create mode 100644 www/fileSystemPaths.js > > diff --git a/plugin.xml b/plugin.xml > index 3bced58..2154ed7 100644 > --- a/plugin.xml > +++ b/plugin.xml > @@ -135,6 +135,10 @@ xmlns:android=" > http://schemas.android.com/apk/res/android" > <js-module src="www/fileSystems-roots.js" > name="fileSystems-roots"> > <runs/> > </js-module> > + <js-module src="www/fileSystemPaths.js" name="fileSystemPaths"> > + <merges target="cordova" /> > + <runs/> > + </js-module> > </platform> > > <!-- amazon-fireos --> > @@ -208,6 +212,11 @@ xmlns:android=" > http://schemas.android.com/apk/res/android" > <runs/> > </js-module> > > + <js-module src="www/fileSystemPaths.js" name="fileSystemPaths"> > + <merges target="cordova" /> > + <runs/> > + </js-module> > + > <framework src="AssetsLibrary.framework" /> > <framework src="MobileCoreServices.framework" /> > </platform> > diff --git a/src/android/FileUtils.java b/src/android/FileUtils.java > index 5fbe1f6..9233a62 100644 > --- a/src/android/FileUtils.java > +++ b/src/android/FileUtils.java > @@ -344,6 +344,8 @@ public class FileUtils extends CordovaPlugin { > callbackContext.success(requestAllFileSystems()); > } > }, callbackContext); > + } else if (action.equals("requestAllPaths")) { > + callbackContext.success(requestAllPaths()); > } else if (action.equals("requestFileSystem")) { > final int fstype=args.getInt(0); > final long size = args.optLong(1); > @@ -850,6 +852,24 @@ public class FileUtils extends CordovaPlugin { > return ret; > } > > + private static String toDirUrl(File f) { > + return Uri.fromFile(f).toString() + '/'; > + } > + > + private JSONObject requestAllPaths() throws JSONException { > + Context context = cordova.getActivity(); > + JSONObject ret = new JSONObject(); > + ret.put("applicationDirectory", "file:///android_asset/"); > + ret.put("applicationStorageDirectory", > toDirUrl(context.getFilesDir().getParentFile())); > + ret.put("dataDirectory", toDirUrl(context.getFilesDir())); > + ret.put("cacheDirectory", toDirUrl(context.getCacheDir())); > + ret.put("externalApplicationStorageDirectory", > toDirUrl(context.getExternalFilesDir(null).getParentFile())); > + ret.put("externalDataDirectory", > toDirUrl(context.getExternalFilesDir(null))); > + ret.put("externalCacheDirectory", > toDirUrl(context.getExternalCacheDir())); > + ret.put("externalRootDirectory", > toDirUrl(Environment.getExternalStorageDirectory())); > + return ret; > + } > + > /** > * Returns a JSON object representing the given File. Internal APIs > should be modified > * to use URLs instead of raw FS paths wherever possible, when > interfacing with this plugin. > diff --git a/src/ios/CDVFile.m b/src/ios/CDVFile.m > index 11b8dd3..b22b7cf 100644 > --- a/src/ios/CDVFile.m > +++ b/src/ios/CDVFile.m > @@ -458,6 +458,36 @@ NSString* const kCDVFilesystemURLPrefix = @"cdvfile"; > [self.commandDelegate sendPluginResult:result > callbackId:command.callbackId]; > } > > +- (void)requestAllPaths:(CDVInvokedUrlCommand*)command > +{ > + NSString* libPath = > NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, > YES)[0]; > + NSString* libPathSync = [libPath stringByAppendingPathComponent:@ > "Cloud"]; > + NSString* libPathNoSync = [libPath stringByAppendingPathComponent:@ > "NoCloud"]; > + NSString* docPath = > NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, > YES)[0]; > + NSString* storagePath = [libPath stringByDeletingLastPathComponent]; > + NSString* cachePath = > NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, > YES)[0]; > + > + // Create the directories if necessary. > + [[NSFileManager defaultManager] createDirectoryAtPath:libPathSync > withIntermediateDirectories:YES attributes:nil error:nil]; > + [[NSFileManager defaultManager] createDirectoryAtPath:libPathNoSync > withIntermediateDirectories:YES attributes:nil error:nil]; > + // Mark NoSync as non-iCloud. > + [[NSURL fileURLWithPath:libPathNoSync] setResourceValue: [NSNumber > numberWithBool: YES] > + forKey: > NSURLIsExcludedFromBackupKey error:nil]; > + > + NSDictionary* ret = @{ > + @"applicationDirectory": [[NSURL fileURLWithPath:[[NSBundle > mainBundle] bundlePath]] absoluteString], > + @"applicationStorageDirectory": [[NSURL > fileURLWithPath:storagePath] absoluteString], > + @"dataDirectory": [[NSURL fileURLWithPath:libPathNoSync] > absoluteString], > + @"syncedDataDirectory": [[NSURL fileURLWithPath:libPathSync] > absoluteString], > + @"documentsDirectory": [[NSURL fileURLWithPath:docPath] > absoluteString], > + @"cacheDirectory": [[NSURL fileURLWithPath:cachePath] > absoluteString], > + @"tempDirectory": [[NSURL fileURLWithPath:NSTemporaryDirectory()] > absoluteString] > + }; > + > + CDVPluginResult* result = [CDVPluginResult > resultWithStatus:CDVCommandStatus_OK messageAsDictionary:ret]; > + [self.commandDelegate sendPluginResult:result > callbackId:command.callbackId]; > +} > + > /* Creates and returns a dictionary representing an Entry Object > * > * IN: > diff --git a/www/fileSystemPaths.js b/www/fileSystemPaths.js > new file mode 100644 > index 0000000..8ef0bb8 > --- /dev/null > +++ b/www/fileSystemPaths.js > @@ -0,0 +1,61 @@ > +/* > + * > + * Licensed to the Apache Software Foundation (ASF) under one > + * or more contributor license agreements. See the NOTICE file > + * distributed with this work for additional information > + * regarding copyright ownership. The ASF licenses this file > + * to you under the Apache License, Version 2.0 (the > + * "License"); you may not use this file except in compliance > + * with the License. You may obtain a copy of the License at > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, > + * software distributed under the License is distributed on an > + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY > + * KIND, either express or implied. See the License for the > + * specific language governing permissions and limitations > + * under the License. > + * > +*/ > + > +var exec = require('cordova/exec'); > +var channel = require('cordova/channel'); > + > +exports.file = { > + // Read-only directory where the application is installed. > + applicationDirectory: null, > + // Root of app's private writable storage > + applicationStorageDirectory: null, > + // Where to put app-specific data files. > + dataDirectory: null, > + // Cached files that should survive app restarts. > + // Apps should not rely on the OS to delete files in here. > + cacheDirectory: null, > + // Android: the application space on external storage. > + externalApplicationStorageDirectory: null, > + // Android: Where to put app-specific data files on external storage. > + externalDataDirectory: null, > + // Android: the application cache on external storage. > + externalCacheDirectory: null, > + // Android: the external storage (SD card) root. > + externalRootDirectory: null, > + // iOS: Temp directory that the OS can clear at will. > + tempDirectory: null, > + // iOS: Holds app-specific files that should be synced (e.g. to > iCloud). > + syncedDataDirectory: null, > + // iOS: Files private to the app, but that are meaningful to other > applciations (e.g. Office files) > + documentsDirectory: null > +}; > + > +channel.waitForInitialization('onFileSystemPathsReady'); > +channel.onCordovaReady.subscribe(function() { > + function after(paths) { > + for (var k in paths) { > + exports.file[k] = paths[k]; > + } > + channel.initializationComplete('onFileSystemPathsReady'); > + } > + exec(after, null, 'File', 'requestAllPaths', []); > +}); > + > -- > 1.8.3.4 (Apple Git-47) > > > > On Tue, May 13, 2014 at 6:32 PM, Jesse <purplecabb...@gmail.com> wrote: > >> I think it is acceptable to have the desktopDirectory, and userDirectory >> point to the same dir as documentsDirectory on devices that do not support >> un-sandboxed file locations. >> >> On Android, this would mean desktop, user, documents all equal : >> /mnt/sdcard >> >> And on iOS : >> /var/mobile/Applications/uid/Documents >> >> Having these there is more just for when we incorporate more desktop >> environments, ie Win32 and/or Mac. >> I am fine with removing them, however, we have to be mindful that there >> are >> potentially many more file locations. For example, WinRT ( Windows8.1 + >> WP8.1 ) support the downloads folder, as well as 'known' folders [1] [2] >> >> >> [1] >> >> http://msdn.microsoft.com/en-ca/library/windows/apps/windows.storage.knownfolders.aspx >> [2] >> >> http://msdn.microsoft.com/en-ca/library/windows/apps/windows.storage.downloadsfolder.aspx >> >> >> >> @purplecabbage >> risingj.com >> >> >> On Tue, May 13, 2014 at 1:57 PM, Andrew Grieve <agri...@chromium.org> >> wrote: >> >> > Thanks Jesse, >> > >> > Less async is definitely nicer. >> > >> > Providing URLs vs DirectoryEntry I don't think is a huge difference >> either, >> > so fine with that (although it means you need to do an async call on the >> > URL to get a DirectoryEntry in order to create a file). Often though, >> you >> > just use the URLs with Camera FileTransfer, so there are some cases >> where >> > it's nice. >> > >> > Don't think desktopDirectory or userDirectory make sense since apps are >> > sandboxed these days. >> > >> > Will take a stab at a commit and report back via pull request. >> > >> > >> > >> > On Tue, May 13, 2014 at 4:37 PM, Jesse <purplecabb...@gmail.com> wrote: >> > >> > > Okay, here goes. >> > > >> > > Re: >> > > >> > > >> > > cordova.plugins.file.getDirectoryForPurpose(purpose, options, win, >> fail) >> > > Where purpose can be one of: >> > > var Purpose = { >> > > 'data': 0, // General application data (default) >> > > 'documents': 1, // Files that are meaningful to other >> applciations >> > > (e.g. Office files) >> > > 'cache': 2, // Temporary files that should survive app restarts >> > > 'temp': 3, // Files that can should be deleted on app restarts >> > > 'app-bundle': 4 // The application bundle (iOS only) >> > > } >> > > // And the aliases >> > > cordova.plugins.file.getDataDirectory(syncable, win) >> > > cordova.plugins.file.getDocumentsDirectory(win) >> > > cordova.plugins.file.getTempDirectory(win) >> > > cordova.plugins.file.getCacheDirectory(win) >> > > >> > > >> > > Ultimately these will never change while the app running, why not just >> > have >> > > them be properties that are populated on startup? >> > > Also, given that they won't change, the async alias calls would not >> > > required. >> > > >> > > My suggestion is based in part on the Adobe Air File class which >> solves >> > > many of the same problems[1] >> > > >> > > I would rather see an API that looked like : >> > > >> > > // a storage directory unique to each installed application >> > > File.applicationStorageDirectory; >> > > // the read-only directory where the application is installed (along >> with >> > > any installed assets) >> > > File.applicationDirectory; >> > > // the user's desktop directory, not available on all devices >> > > File.desktopDirectory; >> > > // the user's documents directory, not available on all devices >> > > File.documentsDirectory; >> > > // Cached files that should survive app restarts >> > > File.cacheDirectory; >> > > >> > > // temp will only live for the lifetime of the app, so if you want a >> ref, >> > > you will have to keep it. >> > > // note also that you can create several temp directories if you want. >> > > var tempDir; >> > > File.createTempDirectory(function onSuccess(dirResult){ >> > > tempDir = dirResult; >> > > },function onError(errResult){ >> > > tempDir = null; >> > > console.log("Error creating temp directory :" + >> > > JSON.stringify(errResult)); >> > > }); >> > > >> > > As an altenative, a root temp dir could be created when the app >> launches, >> > > making this async call unnecessary, and then these could be referenced >> > just >> > > like the other dirs >> > > That would make this just : >> > > >> > > // location unknown, and volatile >> > > File.tempDirectory; >> > > >> > > >> > > [1] >> > > >> > > >> > >> http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/filesystem/File.html >> > > >> > > >> > > >> > > @purplecabbage >> > > risingj.com >> > > >> > > >> > > On Tue, May 13, 2014 at 9:02 AM, purplecabbage < >> purplecabb...@gmail.com >> > > >wrote: >> > > >> > > > Yeah almost. Still brewing a little. >> > > > Give me a couple hours. >> > > > >> > > > >> > > > >> > > > > On May 12, 2014, at 10:05 AM, Andrew Grieve <agri...@chromium.org >> > >> > > > wrote: >> > > > > >> > > > > Now that email works again - Jesse, were you thinking of >> proposing a >> > > > tweaks >> > > > > API, or something different altogether. >> > > > > New related bug here: >> > > > > >> > > > > https://issues.apache.org/jira/browse/CB-6670 >> > > > > >> > > > > >> > > > >> On Tue, May 6, 2014 at 6:21 PM, Brian LeRoux <b...@brian.io> wrote: >> > > > >> >> > > > >> That is a very good point! I say it is good enough for now. >> > Something >> > > to >> > > > >> flag for our W3C friends to look at and consider in the spec. >> > > > >> >> > > > >> >> > > > >> On Tue, May 6, 2014 at 1:43 PM, Andrew Grieve < >> agri...@chromium.org >> > > >> > > > >> wrote: >> > > > >> >> > > > >>> There are two types of config for file: >> > > > >>> 1. You can do is disable parts of the filesystem (doubt anyone >> > would >> > > do >> > > > >>> this) >> > > > >>> 2. You can switch where PERSISTENT filesystem maps to (sane >> place >> > vs >> > > > >> legacy >> > > > >>> place) >> > > > >>> >> > > > >>> What's missing is a way to retrieve the paths that you might >> want. >> > No >> > > > >>> configuration required for this part. >> > > > >>> >> > > > >>> I'd like to avoid making the calls look like they are a part of >> the >> > > > file >> > > > >>> spec, so that users won't be tempted to think that it would work >> > in a >> > > > >>> non-Cordova environment. >> > > > >>> >> > > > >>> >> > > > >>>> On Tue, May 6, 2014 at 1:47 PM, Brian LeRoux <b...@brian.io> >> wrote: >> > > > >>>> >> > > > >>>> This plugin is helpful though I can't help but wonder if we >> can't >> > > > >>> shoehorn >> > > > >>>> into specs (or at least provide spec feedback). >> > > > >>>> >> > > > >>>> Right now all config is done w/ config.xml instead of >> programmatic >> > > (?) >> > > > >>>> >> > > > >>>> >> > > > >>>> On Tue, May 6, 2014 at 7:06 AM, Andrew Grieve < >> > agri...@chromium.org >> > > > >> > > > >>>> wrote: >> > > > >>>> >> > > > >>>>> Closer than ever to resolving this (woo!) >> > > > >>>>> >> > > > >>>>> The file plugin is now able to read & write to roots on the >> > > > >> filesystem >> > > > >>>>> beyond PERSISTENT and TEMPORARY on iOS, Android, and >> BlackBerry >> > > (and >> > > > >>>> maybe >> > > > >>>>> others?) >> > > > >>>>> >> > > > >>>>> However, you still can't query for the location of these >> places >> > > > >> (doh!) >> > > > >>>>> >> > > > >>>>> There's a file-extras plugin in cordova-labs: >> > > > >> >> > > > >> > > >> > >> https://git-wip-us.apache.org/repos/asf?p=cordova-labs.git;a=blob;f=file-extras/fileextras.js;h=1f8f88f7222bd4022f2f802f6825c189b10445d9;hb=aaf61d4 >> > > > >>>>> >> > > > >>>>> That was used to experiment with an API for this. I think the >> API >> > > is >> > > > >>>> pretty >> > > > >>>>> much fine, and I'd like to add it to the core file plugin >> rather >> > > than >> > > > >>>> have >> > > > >>>>> it as a separate plugin. >> > > > >>>>> >> > > > >>>>> This would add: >> > > > >>>>> cordova.plugins.file.getDirectoryForPurpose(purpose, options, >> > win, >> > > > >>> fail) >> > > > >>>>> >> > > > >>>>> Where purpose can be one of: >> > > > >>>>> var Purpose = { >> > > > >>>>> 'data': 0, // General application data (default) >> > > > >>>>> 'documents': 1, // Files that are meaningful to other >> > > > >> applciations >> > > > >>>>> (e.g. Office files) >> > > > >>>>> 'cache': 2, // Temporary files that should survive app >> > restarts >> > > > >>>>> 'temp': 3, // Files that can should be deleted on app >> > restarts >> > > > >>>>> 'app-bundle': 4 // The application bundle (iOS only) >> > > > >>>>> } >> > > > >>>>> >> > > > >>>>> And also add convenience wrappers: >> > > > >>>>> cordova.plugins.file.getDataDirectory(syncable, win) >> > > > >>>>> cordova.plugins.file.getDocumentsDirectory(win) >> > > > >>>>> cordova.plugins.file.getTempDirectory(win) >> > > > >>>>> cordova.plugins.file.getCacheDirectory(win) >> > > > >>>>> >> > > > >>>>> >> > > > >>>>> Any comments on this? >> > > > >> >> > > > >> > > >> > >> > >