Does updating iOS apps delete library directory files? - ios

I keep save files in a private directory in my iPad app, namely the one returned when I use:
paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
documentsDirectory = [paths objectAtIndex:0];
documentsDirectory = [documentsDirectory stringByAppendingPathComponent:#"Private Documents"];
Notice that I also append a subdirectory to it. When I update the app, users are telling me that their progress in the app is getting destroyed. Are files in this NSLibraryDirectory destroyed every time I update the app? If so, should I be using NSDocumentDirectory instead?
Additionally, is there no way to make a further update to my app to remedy this without destroying all my my current users' save files? It doesn't seem like there is.

When a user downloads an app update, iTunes installs the update in a new app directory. It then moves the user’s data files from the old installation over to the new app directory before deleting the old installation. Files in the following directories are guaranteed to be preserved during the update process:
Application_Home/Documents
Application_Home/Library
Although files in other user directories may also be moved over, you should not rely on them being present after an update.
This is provided by apple officially. See this link :
iOS Developer Library - File Saved During App Updates

I would also like to add this info as a personal experience with a big online game. You can't rely at 100% that your "Document" and "Library" folder will always be there. In fact, you can't rely that your app folder will still be at the same place on your device after an update.
Let me explain it a little bit more. When you install an app on your device, the real path will be /var/mobile/Applications/[some class id]/[your app].app/...
We're not sure who defines the class id of your app (either the iOS or app store), but this Id can change when updating the game resulting in having your app in a totaly different folder so your old files aren't there anymore. Our QA experienced it and our users too.
I won't go through the details on how we found that out and how we managed to get around this (private company stuff, usual shit...), but you need to consider it if you're doing an app that affects tons of users and might be updated a couple of times. It might have been fixed since, but it's always good to have a backup plan.

You should save them in the Documents folder, it is persistent across updates.
Monotouch: documentsDirectory = environment.specialfolder.personal;
Objective-C: NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)

Related

download file to update-independent directory in objective c

I'm developing an IOS app which download some video and save it, but after update app or reinstall it the directory of app change, and app can not access to previous downloaded files.
Is there any way to save downloaded file to location out of application domain directory?
the code for generating path to save file is.
NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
I cannot verify the update part of your question.
I use the application's Documents all the time and after an update that is untouched, so I can still use any files added to it in a previous version.
For the reinstalling (i.e. first delete the app, then re-download it from the AppStore and run it) there is obviously no such way, unless you consider what ravi.p suggested in his comment (adding it to PhotosAlbum). That would beat the entire purpose of a reinstall. If a user deletes the app they want to delete all its data. That's why the warning dialog specifically makes that clear. If you could circumvent this would beat the intention, wouldn't it?
The previous Documents directory isn't changed in this case, it is deleted and on the reinstall a new one is created.
I didn't check it recently, but I believe even the full path of the Documents directory doesn't change after an update, including the hashed part that is created by the sandboxing mechanism. My guess is that you're either confusing something with the update process or simply get a different file name in the newer app version.
Edit:
Okay, so apparently the application's folders can change on an update, at least according to what you further explained in your comment. :)
Then I am wondering how you can find your sqlite file again, but in ay way there is an easy solution to your problem:
Do not save the full path in your database. That is bad practice anyways, since the method you already used to get it in the first place (after downloading the file) is meant to be used for accessing the folder. So you only save
[response suggestedFilename]
in your database (going from your posted code).
In places where you need to access the file you then simply rebuild your path in just the same way you do in the first line of code you posted.
You can even write a convenience method for this in some place (a model class or the class taking care about DB access).
And by the way: Again, updating and reinstalling are two different things, especially the process in which Xcode copies your development build onto your development device is a different one from how users ultimately update your app from the store.

Storing/loading PNGs from In App Purchase

I'm developing IAPs for my app. I'm able to create the IAP package, upload to iTunes Connect and download to my to app from the App Store sandbox, and read the contents. What I'm still unclear on though is where to copy the contents of the IAP to store/load them most efficiently.
The contents of the IAP package is a set of PNGs that the user can use to customize their appearance with while using the app. The user gets a default set of PNGs with the app itself.
A few couple questions this has led to:
Where is the preferred location for storing the PNGs from the IAP? Some tutorials recommend NSDocumentDirectory while others recommend NSApplicationSupportDirectory. What are the advantages of one over the other?
How can I load the PNGs without having to track which ones are in the main bundle and which are in the IAP directory? For example, the default PNGs in the main app bundle can be loaded with:
UIImage *newHat = [UIImage imageNamed:#"fancyHat.png"];
While the PNGs from the IAPs have to be loaded like this (assuming I've copied them to the Document directory):
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *inAppImagePath = [documentsDirectory stringByAppendingPathComponent:#"iapTopHat.png"];
UIImage *newHat = [UIImage imageWithContentsOfFile:inAppImagePath];
Is it possible to reconcile these, so I don't have to track which PNGs are IAPs and which are in the main bundle and then use two separate methods to load them?
It seems like ideally I could copy the PNGs to the main app bundle so I could use UIImage imageNamed:. But that seems to not be allowed and not preferred anyway.
Any assistance or guidance is greatly appreciated.
Here is a good start for what Apple suggests for data storage locations: https://developer.apple.com/icloud/documentation/data-storage/index.html
You have multiple options for digging into the bundled vs purchased content. In your example, your image name is prefixed by something that could be used to differentiate categories of content, so you can use that to determine which loading mechanism to use. You could reverse the method you ponder in the post, that is to check for the existence of the asset (whatever the name) in the bundle first, and load from there or the purchased location if not found. You could also create symlinks into the bundle if you wanted to unify the sets "on disk", but this one is trickier as you'll need to make sure your symlinks get updated if the base App UUID changes (which it will and often) during development.

iOS Application Library directory <uid> always gets changed

After reading Apple documentation, I used URLsForDirectory to obtain the Library destination within my app, and my objective is to download content from a hosted service & cache it in the Library folder, so that User cannot interact with the contents through iTunes.
NSArray *docPaths= [[NSFileManager defaultManager] URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask];
NSLog(#"%#",[docPaths description]);
NSString *docPath=[(NSURL *)[docPaths objectAtIndex:0] path];
docPath = [docPath stringByAppendingPathComponent:#"audios"];
Running & executing the code several times(various simulators, and iOS 8.0 device) I realized that somehow the content being fetched seems to be no longer accessible, so I logged the library destination path, and after running app every time the destination path seems to have changed:
/var/mobile/Containers/Data/Application/83725F33-C7EA-4F89-B69F-0AECF26FA77A/Library/"
/var/mobile/Containers/Data/Application/4627FC86-C3A4-4A1A-9721-AF73D808433E/Library/"
/var/mobile/Containers/Data/Application/709CCA84-936A-4596-933A-D6779758FF85/Library/
Has anybody faced a similar issue? If so how did it got corrected? And is there anything I've missed out here?
I had the same issue. I think the variable part changes only when the code is recompiled (ie not if you just rerun without making changes), so should not affect a live app. But I decided in the end not to save the path - just to use the same code (as you use above) both when saving and retrieving the data. It seems to work, in spite of the fact that the path actually changes between runs (so the simulator must copy the files across, or rename the folder).

App Updates, NSURL, and Documents Directory

I have an app in the app store that uses Core Data to persist much of the data.
The exception is storing images. I store images in subdirectories to the Documents directory and store an NSURL reference to that image in the appropriate object attribute in the core data store.
We have noticed that, when an update makes it to the app store, those images are not found, and thus don't display, using the references stored with the previous version of the app.
Now, I have a suspicion that the problem is that, since we are using development devices for testing, this issue propagates because the Directory in the Applications directory to which the dev app uses differs from the one the App store is creating/using. I have noticed differences between the App store directory for the app in Applications and the one created while debugging versions in Xcode.
As such, the URL stored in core data points to the wrong applications folder.
This is kinda hard to debug, as I cannot download an older app version, once the new version has been released in the store.
So I have a couple questions. Can I guarantee that the Applications subdirectory in which folks who download versions of the same app will be the same, rendering this a non-issue for non-development devices?
Should I be storing relative image url's or strings to represent the location of these resources, or should I be fine with storing what ends up being the absolute urls?
Thanks so much,
Felipe
You should use relative URLs to store references to files. The absolute URL is likely to change after an app update
Files Saved During App Updates
When a user downloads an app update,
iTunes installs the update in a new app directory. It then moves the
user’s data files from the old installation over to the new app
directory before deleting the old installation. Files in the following
directories are guaranteed to be preserved during the update process:
Application_Home/Documents
Application_Home/Library
Although files
in other user directories may also be moved over, you should not rely
on them being present after an update.
https://developer.apple.com/library/ios/#DOCUMENTATION/iPhone/Conceptual/iPhoneOSProgrammingGuide/PerformanceTuning/PerformanceTuning.html
Thx to the sandbox, the application home is also the user home. So it is possible to use the unix tilde which is a short hand to the user home, i.e. ~/Documents, ~/Library and so on.
Use -[NSString stringByAbbreviatingWithTildeInPath] to turn a full path into a relative ~ path. And reverse it with -[NSString stringByExpandingTildeInPath].
I think what you're looking for is the following:
NSString *appDocumentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];

app data loss on version upgrade

although this is an older question to ask, but i didn't got any suitable solution for this. That's why i am asking for help about this issue.
I have an iphone app, which contains a sqlite db in it's resource folder. Now, when i upgrade it to the later version from iTunes, all the data in the database are lost.
Suppose a user entered 1000 entry in the database. So if he lost his data in case of upgrading the application from iTunes, he will definitely not gonna love to upgrade his app's version. He should be then notified first that, "you will loss all of your previous data" or the previous data should be kept unchanged in the new version.
What procedure i should follow in the new version to keep all the old data in the new version...?
I can't modify the previous versions. So, i have to do something in the latest version so that all the data from the previous version should be kept in this newer one.
This is an emergency problem. Users are upgrading the application & they are loosing their previously stored data in the database. Even they are not being notified that they will lost all the data. !
When not using Core Data, the only way to preserve user data is to store your database in the user Documents directory as well as the Library directory.
Documents
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"UserData.sqlite"]];
Library
[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
These are also the only directories write-accessible to your app. If you have include a "blank" database in your Resources folder, it is copied to the bundle. From there, you need to check whether the db exists in the Documents directory, if not, then copy it from the bundle.
This is the only way to ensure that data is protected on app upgrades.
On another note, if the user does not backup their device, uninstalls the app then re0installs the app, the data will be gone.
In regards to the user not being notified they will lose their data, the only thing that will prompt the user about loss of data is when they decide to remove the app from the device, or if you implement some way to notify the user of any data change.
Where do you store your data? You are supposed to do it in Documents directory of your application bundle. Directories other then Documents and Library are not preserved during app updates (During update your app is actually installed in other directory, and its data is copied back).
Here's a good overview of iOS file system: iOS Standard Directories: Where Files Reside (File System Programming Guide)
You may use a separate sqlite db file for user's data which you should not loss.
PS: When new update is downloading from App Store. iOS moves old files to another folder. When download and installation complete iOS move old files to the application's folder.
If you would have set the version number to your database for your iphone could have been easily handle, save your version number into your db and whenever database is called, compare the version against the expected version
If new version > older version change the schema (this is needed if you would have changed the schema of your database) with using SQL ALTER statements and update the app version number.
So whenever user is going to update or fresh installation, it will check the new version with your older version, if it differ then update schema, and if its same no need to make any changes.
If you would not have made any schema related changes (for example
adding new column..) then you do not need to worry, user will not lose
the data.

Resources