Please help cocos2d-x to determine what's the correct path to save a file on iOS and Android

Now CCFileUtils::getWriteablePath returns different values on different platforms
* iOS
/Caches
* Android
/data/data//caches

It seems that the return value on iOS and Android is not so suitable. And i want to change the return value of CCFileUtils::getWriteablePath, but i am sure
if i am correct.

iOS

what’s the problem

Refer to this document, it says that

On iOS 5.0 and later, the system may delete the Caches directory on rare occasions when the system is very low on disk space. This will never occur while an app is running. 
However, you should be aware that iTunes restore is not necessarily the only condition under which the Caches directory can be erased.

So, it is not safe to safe a file in /Caches.

what’s correct path

There are two other path can be used to save a file in on iOS except for /Caches:
* /Documents
* /Library

Some developer told me that, Apple will reject an app if it saves a file in /Documents. I am not sure if it is true. The other problem
of /Documents is that, the contents under it will be backup. It meas that, if you save a file in /Documents, a customer
will use iTunes to checkout this file and modify it. So i think /Documents is not suitable for saving files.

Android

what’s the problem

Now CCFileUtils::getWriteablePath() returns the value returned by Context.getCacheDir(). According to this document,
it says that

public abstract File getCacheDir ()

Added in API level 1
Returns the absolute path to the application specific cache directory on the filesystem. These files will be ones that get deleted first when the device runs low on storage. 
There is no guarantee when these files will be deleted. Note: you should not rely on the system deleting these files for you; you should always have a reasonable maximum, 
such as 1 MB, for the amount of space you consume with cache files, and prune those files when exceeding that space.

So it is not suitable to save file in this directory.

what’s correct path

I think the correct path to save files is /data/data//, is it right?

Conclusion

As a result, /Library is the best choice to save a file on iOS,
and /data/data// is the best choice on Android.

Please correct me if i am wrong.

Can any body give me a suggestion?

Mingo and I discussed this issue on mails. I agree on all he said. Just one more thing to mention.
If we store data in /Library, when using itunes to backup and restore, the data should be kept (Tell me if I am wrong). But if we store data in /Library/Caches, it’s an exception, the data won’t be kept. So /Library should be good for storing data other than /Library/Caches.
Could anyone give more opinions please?

@Nichos
Thank you for your opinion.

And what do apple support engineers say about that?

I can only find this article.
It seems that //Library is the best choice too.

If any body can find more accurate information, please share with us.
Thank you.

Any ideas?

For Android you MUST use getFilesDir() for persistent data storage. This will normally return /data/data//files. However Android 4.2 adds multi user support, and the call returns a different path. /data/data/<package/files still exists but is not read/writeable by any user besides the first.

See
http://developer.android.com/about/versions/android-4.2.html#MultipleUsers
http://developer.android.com/reference/android/content/Context.html#getFilesDir()
http://developer.android.com/guide/topics/data/data-storage.html#filesInternal

Edit:
For iOS, the best place may be //Library/Documents. At least that is the folder iTunes puts the data in when iTunes document sync is available for the application.
See
http://developer.apple.com/library/ios/#documentation/FileManagement/Conceptual/FileSystemProgrammingGUide/FileSystemOverview/FileSystemOverview.html#//apple_ref/doc/uid/TP40010672-CH2-SW4

@Andre Rudlaff

>> /data/data/<package/files still exists but is not read/writeable by any user besides the first.

Then what’s the suitable path to be returned on Android?

About iOS, i think we should not return a path that can be sync by iTune. If so, the data can be modified by customers.

For Android you must use the return value of Context.getFilesDir(). Either call into JNI every time or cache the path during the application startup process.
For iOS, you cannot sync/extract the data from that directory unless your application has enabled iTunes Data sharing in its info.plist. The data is of course within the iTunes Backup where it might be modifieable (i don’t know how itunes stores the backup files).
However this is something I would expect as an iOS user. My savegames and other persistent data should be backed up by iTunes.

From the Apple Docs:

<Application_Home>/Documents/
Use this directory to store critical user documents and app data files. Critical data is any data that cannot be recreated by your app, such as user-generated content.
The contents of this directory can be made available to the user through file sharing. The contents of this directory are backed up by iTunes.

See also the ‘Where You Should Put Your App’s Files’ paragraph at http://developer.apple.com/library/ios/#documentation/FileManagement/Conceptual/FileSystemProgrammingGUide/FileSystemOverview/FileSystemOverview.html#//apple_ref/doc/uid/TP40010672-CH2-SW4
I’m not sure if there is a method on iOS to retrieve these paths, as hardcoding this path might break future apps (like it did for Android)

@Andre Rudlaff
Thank you.

So the best path are
* Android
return the value returned by Context.getFilesDir()
* iOS
/Library/Documents

Android is correct, for iOS you should probably do something like shown below instead of hardcoding the directory.

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];

Here in the iOS documentation says the Application Support directory is the recommended place for saving application data that we don’t want to be backed up by iTunes/iCloud. One of the problems with this directory is it doesn’t exist by default so we would need to try and create it the first time we tried to access it. This StackOverflow post describes how to do this.

It might be beneficial to also keep the ability to save to a cache directory. The scenario I am thinking of is where profile pictures or other data has been downloaded from the network and could be recovered if the OS needs to wipe the cache. Perhaps add CCFileUtils::getCachePath as a new method.

@Stuart McGaw
Did you mean that /Library/Documents is not suitable for writable path?

I think the documentation says /Library/Documents is for files the user has created and so would expect to be backed up. /Library/Application Support is for other files of an application. I do not think it would be wrong to use the documents directory for the writeable path but perhaps it would be better to use the Application Support folder.

I think the documentation says /Library/Documents is for files the user has created and so would expect to be backed up. /Library/Application Support is for other files of an application. I do not think it would be wrong to use the documents directory for the writeable path but perhaps it would be better to use the Application Support folder.

Just checked some of the Apps I have on my iPad, all use /Documents as storage path for Purchases and Savegames.
You can use /Library/Caches for temporary data that may get deleted any time (not sure how this is handeled on iOS)

So I think Stuart is right, we may want to introduce a second directory for retrieving a cache directory:

Persistant data like savegames, highscores, replays
Android: Contect.getFilesDir()
iOS: /Documents (Note it is NOT /Library/Documents)

Temporary data like user avatars:
Android: Context.getCacheDir()
iOS: /Library/Caches

Again, for iOS you should query the framework for retrieving the path to the documents and cache directory.

Stuart McGawAndre Rudlaff
Thank you.

#1701 is created for adding getCachePath.

Minggo Zhang wrote:

@Stuart McGaw
Did you mean that /Library/Documents is not suitable for writable path?

Hi Minggo, how to get the in iOS system? thanks!

resolved! :slight_smile:

std::string path = CCFileUtils::sharedFileUtils()->getWriteablePath() + “…/…/Documents/data.csv”;

Having had to rework an iOS project because I was saving files to the wrong location for iCloud backup purposes, I would like to clarify this as i understand it. There are should be 3 different writeablePaths for iOS

  1. /Documents - anything in here should be user generated and thus will be backed up on iCloud if the user is doing so.
  2. /Library/Cache - anything in here should be considered temporary and may be deleted by the OS at any point when the app is not running.
  3. /Library/“Application Support” - anything here will NOT be backed up but is safe from the possibility of being deleted by the OS. This is where persistent downloaded, such as non-consumable IAP, content should go, as it can be re-downloaded if the user restores their device from backup.

See the following for more details:
http://developer.apple.com/library/mac/documentation/FileManagement/Conceptual/FileSystemProgrammingGUide/FileSystemOverview/FileSystemOverview.html#//apple_ref/doc/uid/TP40010672-CH2-SW28

I suggest 3 functions: getDocumentsPath(), getCachePath(), and getSupportPath(). For all other OSs getSupportPath() can return the results from getDocumentsPath(). Alternatively, add a variable to getWriteablePath( bool flag) and on iOS if the flag is true, the return the Documents directory and if false return the “Application Support” directory; on other OSs the flag is ignored.