Storing/loading PNGs from In App Purchase - ios

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.

Related

iOS Disk access based restore function

I am trying to code a hard disk based restore function into an existing demo Photo Application for iOS devices. The idea is to allow users to restore the last applied effects and all, even after restarting the application/unexpected crash etc.
I am saving one image file (the latest effects applied to it) into the NSCachesDirectory:
NSData* data = UIImagePNGRepresentation(image);
[data writeToFile:[self getFileAtIndex:getPath] atomically:YES];
On going to the recover option, the file saved at this path is recovered using:
image = [[UIImage imageWithContentsOfFile:[self getFileAtIndex:getPath]]retain];
The code is working fine in my test device (iPhone 4s). But somehow I doubt if this is the best practice for coding a restore function.
Moving into a real world app, if things were stored in NSCachesDirectory, do you think it will be backed up into iCloud? Is there any possibility of a conflict with other apps?
How exactly is NSCachesDirectory directory managed for multiple apps accessing it simultaneously?
I would like to know the best practice for doing this.
Please help/comment.
As Mr. Bonjour mentioned in the comment, on iOS, every app has its separate file system, so there can never be any conflict with other apps.
Caches directory is not backed up on iCloud and you shouldn't rely on files in caches directory to persist across launches. You should use caches directory for temporary files only. If you allow restore only during one session, then using caches directory is fine, but if you want to allow restore across multiple launches, you should store them in library/documents directory. But be aware that Apple has a strict review policy for storing files in Documents directory since it takes up space on user's cloud storage.

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.

Does updating iOS apps delete library directory files?

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)

How can I retrieve files from an iPad development tool app?

I'm not sure how best to word the Title of this, so if someone can suggest a better one, please feel free to edit.
I'm writing an app for iPad that requires me to create some of the app data files with the iPad itself during development, i.e. a tool I am building with the iPad will be used by the developers themselves to create sample files that can be played by the app itself.
My question is, how can I best do this? I tried writing files to a local dir on my mac while the iPad was connected but I get a crash. Ideally if there is some way for me to generate an output file on my iPad and get it transferred to my Mac while my dev build is running, I'd do that.
Suggestions?
It looks like the trick it to use Apple's File Sharing to place files in a folder accessible through iTunes, explained here:
Standard Application Behaviors
The gist is to add a UIFileSharingEnabled plist key set to true and then query the Documents folder for your application like so:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];

Resources