Protecting my JSON-based level configuration data in Swift - ios

I am making a game in Swift with SpriteKit that I envision to have (for now) about 100 levels. They're broken out into areas (20 levels per area). Most areas are free, but I'd like to make one or two very special areas that require some hard work to get the ability to play. Maybe i'll even make one require a purchase if it's worth it.
So to make things easy, I just made all the levels as JSON configuration files when needed, and my reader will pull the settings and hydrate the level class from that. Thus I have 100 level files.
I was thinking about this, and realized that there isn't anything stopping an attacker from using a tool like ifunbox to browse to the JSON files, find the premium ones, take the contents, overwrite the non-premium ones, and then play the premium content for free.
Should I keep the JSON files and just encrypt them? I was thinking another alternative would be to keep level hashes of each level and do a comparison, but that would require 100 hashes in my code file.
Could someone offer me a suggestion as to protect my level configuration data a little better so premium content stays premium?
Thanks!

Maybe you should use apples On Demand Resources so that the files arent actually in the app to begin with, and it will only download the premium maps once the purchase has been made
Benefits of On-Demand Resources
Some of the main ways apps can benefit from on-demand resources
include:
Smaller app size. The size of the app bundle downloaded by the user is
smaller resulting in faster downloads and more storage room on the
device.
Lazy loading of app resources. The app has resources that are
used only in certain states. The resources are requested when the app
is likely to enter the appropriate state. For example, in a game with
many levels, the user needs only the resources associated with the
current and next levels.
Remote storage of rarely used resources. The
app has resources that are used infrequently. The resources are
requested as they are needed. For example, an app tutorial is usually
shown once after the app is opened for the first time, and may never
be used again. The app requests the tutorial on first launch, and then
requests the tutorial only when needed or when new features are added.
Remote storage of in-app purchase resources. The app offers in-app
purchases that includes additional resources. The resources for
purchased modules are requested by the app after it is launched. For
example, a user purchases the SuperGeeky emoticon pack in a keyboard
app. The app requests the pack after it finishes launching.

Related

Too Many Files Open while monitoring file changes

I am developing a document-browser-based app for the iPad. I have been using SKQueue to monitor changes to the files in order to make sure their metadata remains current when the user performs actions in the document browser. The code for initiating monitoring:
// Set up the queue
let delegate = self
queue = SKQueue(delegate: delegate)!
// Remove all existing paths
queue?.removeAllPaths()
// Get the list of PDF URLs using a function that enumerates a folder's contents
let pdfFiles = getFolderContents(rootFolder: myDocumentsFolder, extensionWanted: "pdf")
for pdfFilePath in pdfFiles.filePaths {
queue?.addPath(pdfFilePath.path)
}
for pdfFolderPath in pdfFiles.folderPaths {
queue?.addPath(pdfFolderPath.path)
}
I developed my own logic to respond to notifications from this queue, but I do not remove any items from the queue during the app's runtime.
The problem - it seems that when the number of items watched is over 200 (files and folders) the system hits a wall and the console reports error 24: Too Many Files Open. After that, no reading/writing of any file can be performed.
From what I was able to gather from searching, it seems that iOS and iPadOS do not allow more than 256 files descriptors to be accessed at the same time, and that would mean that the GCD approach to monitoring file changes would suffer from the same limitation.
Is there any way to monitor files changes that is not subject to such a limitation? Any other suggestions?
After a lot of research and experimentation, I can finally verify that indeed, the default maximum number allowed of open file descriptors is 256 - for MacOS, iOS and iPadOS. This can be changed easily in MacOS - see article here. However, iOS and iPadOS being much more closed in nature, there is no reliable way of changing this limit on these platforms.
Good practices are therefore:
Try to avoid designing an app that would call for so many file descriptors open.
Monitor directories, and not individual files. With most tools available for monitoring the file system, you get notifications for any file change within a monitored directory. Just implement your logic from there, by enumerating the folder and comparing its new state with a saved state. You can find good code for that in the top two answers of this SO thread.
Note: I recommend enumeration rather than other methods of getting the file system state, because other methods tend to give incompatible results between the simulator and actual devices (different treatment of symlink resolution).
Make sure your method of choice for monitoring the file system can be queried for the number of items being watched, and issue an alert if the user approaches a set limit. Remember that the 256 open files must also include all files used by the app, including ones in the app's bundle and ones that are in actual use. So take a nice safety margin.
In my case, my app uses a UIDocumentBrowserViewController, or in other words - Apple's own Files app, to allow users to manage their files. I have to keep my metadata up-to-date with the file system state, and I have no control over the file management habits of my users. To complicate matters, the Files app itself can be used to modify the app's file system - while my app is not active.
Therefore, I do two things:
I save a detailed state of the file system from the App Delegate's applicationDidEnterBackground and applicationWillTerminate methods into a json file in Application Support, and on the app's launch I compare it to a fresh enumeration of the file system - and alert the user for any mismatch, suggesting to use the app's own file browser next time.
I created my own swift package, named SFSMonitor, for monitoring the file system. It is based on the wonderfully convenient SKQueue (which I highly recommend), but instead of monitoring kevent, it uses Dispatch Sources - a more modern approach, which Apple advocates. It is similar to Apple's own Directory Monitor (reference to which you can find here), but instead of monitoring one directory, it allows you to create and manage a whole queue of them. This class allows you to set a maximum number of monitored file descriptors, and be notified when that limit is reached.

Co-mingling "default" data with user-supplied data in Core Data

I know Apple will reject apps that backup data that can be reloaded from the app bundle. However, in the app I'm working on, we'll be providing some basic data that users will want to keep in the Core Data store along with the new data they have created and entered. So, users will use the "library" data we provide by integrating it with their own data as they work with the app.
My concern is whether Apple will require me to segregate these data in some way such that data from the bundle is not backed up to iCloud? Once the data are co-mingled, disaggregation would be complex and burden the app excessively.
So, my question is whether I have to concern myself with the co-mingling of user data with that data which is supplied in the app bundle?
TIA for any input on this as I've not found anything about it in the docs.
I had a similar situation in my app. It has sample data, but the sample data is designed to be edited by the user, and has metadata attached to it that is user specific. In other words, the data is mutable, and belonged with the rest of the user's personally created data.
At one point, the app was rejected. I first appealed to the reviewer, explaining that the data was mutable, and personal to the user — it would not be possible to reproduce the data purely from the app bundle. The reviewer would not budge, so I appealed, and they sided with the reviewer. Game over.
You may be able to get away with a small amount of data loaded from your bundle (<1MB). If you plan to include images or anything that will push up that amount, they will likely reject you.
I also heard from another developer rejected for including data downloaded from a web service in the user's store. Apple claimed that the data could be re-downloaded, which may be partially true, but ignores the fact that the web service was operated by a third party, and the downloaded data could be unshared at any time. It also ignores that the user can edit the downloaded data, and that the client app is attaching user-specific metadata that cannot be downloaded.
That developer was rejected as well. He eventually got the app through review by introducing a complex set of procedures to import the data: the user had to first download the data to a temporary holding area that was not backed up. They then had to explicitly import the data, and dismiss a wordy dialog warning that the imported data would contribute to their iCloud backup quota. Horrible. But that is apparently what Apple wants.
The rule is pretty mindless, in my view, and Apple seem to be completely oblivious to the implications in terms of user interface changes and drastic refactoring of an app's model. I can't imagine any engineers were involved in forming the rule, because they surely would have realized how much unnecessary complexity it would impose on developers. We can only hope they see reason at some point.

Storing a small number of images with potential for IAP

I'm making an app. Part of the app is to choose from 5 preset images.
These will be available at install and so need to be bundled with the app.
However, there is also potential to "add" more images through in app purchases.
I'm looking for the "best" way to store these images on the device with the potential to add/unlock more images.
My thoughts are that "CoreData" is too heavy for this. I could do some sort of plist thing to reference the initial five images. But then how do I add more through IAP?
With IAP, do I download the additional images upon purchase? Or should they also be bundled into the app at install and then unlocked when purchased?
Never done IAP stuff before and my previous apps all used Core-Data as they were very data heavy.
There are two things to consider -
Do you want to add more images after you've shipped?
Are the images small enough that they can be download quickly on demand?
If the answer to either is yes, I would recommend going the hosted content route. Apple even allows you to host content on their servers.
Otherwise, just bundle everything in your app and unlock as required.
Small note on security: I would not worry about piracy at all since there is no way you can stop people from pirating content/apps. Besides, the number of people who JB is quite small (23m / 90% * 500m ~ 5%) and the number of people who pirate is even smaller.

Has Apple fixed the CoreData + iCloud sync issues? [closed]

There has been a lot of discussion lately about the issues with iCloud and Core Data and how Apple's APIs are currently broken in iOS 5 and possibly iOS 6.
Is it possible, given the current state of Apple's Core Data API, to reliably sync across multiple devices using iCloud?
If so, how would you do this? If not, please recommend an alternative approach.
This blog post will lead you to a chain of recent articles about the travails of developers attempting this approach.
From my own understanding and experience, I believe it is doable, but don't buy into the idea that you will get anything "for free". Depending on your data model, you may be better off syncing your whole persistent store as a document rather than using the documented core data / iCloud approach.
You may have better luck if you're already comfortable with Core Data. Just be sure you think through how to handle several important cases.
One is what to do if the user signs out of their iCloud account. When this happens, the local ubiquitous persistent store is deleted. If it makes sense for the user to still have access to their data, you'll need to manage a copy in local storage, and then manage resynchronizing when they sign back in.
Another is that changes can apparently be quite slow to propagate by default, so you may want to consider an alternative mechanism, such as the key value store, to quickly propagate sufficient information to avoid a bad user experience.
Conflict management is perhaps the most challenging (depending on your model). While the framework provides a mechanism to inform you of conflicts, you are on your own for providing a mechanism to resolve them, and there are reports that the conflict notifications may not be reliable (see linked articles), which seems strongly linked to the lag in updating.
In short, if you go into this understanding that the actual support is pretty bare bones and that you'll need to code very defensively, you may have a chance. There aren't any good recipes out there, so if you do make it work, please come back and tell us what works!
It depends on what you want to do. There are two types of Core Data-iCloud integration, as described here: http://developer.apple.com/library/ios/#releasenotes/DataManagement/RN-iCloudCoreData/_index.html
There are broadly speaking two types of Core Data-based application that integrate with iCloud:
Library-style applications, where the application usually has a single persistent store, and data from the store is used throughout the application.
Examples of this style of application are Music and Photos.
Document-based applications, where different documents may be opened at different times during the lifetime of the application.
Examples of this style of application are Keynote and Numbers.
If you're using the library-type, this article is the first of a series that goes into a lot of the problems that will come up: http://mentalfaculty.tumblr.com/post/23163747823/under-the-sheets-with-icloud-and-core-data-the-basics.
You can also check out sessions 218 (for document-based) or 227 (for library-style) of this year's wwdc.
As of iOS 7, the best solution is probably the Ensembles framework: https://github.com/drewmccormack/ensembles
Additionally, there is a promising project which will essentially allow you to do the same thing using a different cloud service.
Here is a link to the repository: https://github.com/nothirst/TICoreDataSync
Project description:
TICoreDataSync is a collection of classes to enable synchronization via the Cloud (including Dropbox) of Core Data-based applications (including document-based apps) between any number of clients running under Mac OS X or iOS. It's designed to be easy to extend if you need to synchronize via an option that isn't already supported.
Reasons for why iCloud is not currently reliable:
"Sometimes, iCloud simply fails to move data from one computer to another."
"Corrupted baselines are [a] common obstacle.... There is no recovery from a corrupted baseline, short of digging in to the innards of your local iCloud storage and scraping everything out, and there is no visible indication that corruption has occurred — syncing simply stops."
"Sometimes, when initializing the iCloud application subsystem, it will simply return an opaque internal error. When it fails, there’s no option to recover — all you can do is try again (and again…) until it finally works."
"[W]hen you turn off the “Documents & Data” syncing option in the iCloud system preferences, the iCloud system deletes all of your locally stored iCloud data[.]"
When you sign out of iCloud, the system moves your iCloud data to a location outside of your application’s sandbox container, and the application can no longer use it.
"In some circumstances (and we haven’t been able to figure out which, yet), iCloud actually changes the object class of an item when synchronizing it. Loosely described, the object class determines the type of the object in the database[.]"
"In some cases (again, not all the time), iCloud may do one of the following:
Owner relationships in an item’s data will point to the wrong owner;
Owner items get lost in synchronization and never appear on computers other than the one on which they were created. (This leads to the item never appearing in the UI on any other machine.) When this happens, bogus relationships get created between blob items and an arbitrary unrelated owner."
"Sometimes (without any apparent consistency or repeatability), the associated data for an object (for example, the PDF data for a PDF item, or the web archive data for a Web Archive item) would simply fail to show up on the destination machine. Sometimes it would arrive later (much later — minutes or hours)."
Quoted and paraphrased from these sources:
http://www.imore.com/debug-12-icloud-core-data-sync
http://rms2.tumblr.com/post/46505165521/the-gathering-storm-our-travails-with-icloud-sync
Note: I have seen one article where the author mentions getting it to work for iOS 6+, but they don't provide any examples: http://zaal.tumblr.com/post/46718877130/why-you-want-to-use-core-data-icloud-sync-if-only-it
As a reference, here are Apple's docs on iCloud + Core Data:
http://developer.apple.com/library/ios/#releasenotes/DataManagement/RN-iCloudCoreData/
http://developer.apple.com/library/ios/#documentation/General/Conceptual/iCloudDesignGuide/Chapters/DesignForCoreDataIniCloud.html
http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/CoreDataVersioning/vmCloud/vmCloud.html
And here is an example app:
http://developer.apple.com/library/ios/#DOCUMENTATION/General/Conceptual/iCloud101/Introduction/Introduction.html
The Apple developer tutorial on using the iCloud API to manipulate documents might be a good place to start.
Your Third iOS App introduces you to the iCloud document storage APIs. You use these APIs to store and manipulate files in a user’s iCloud storage.

Syncing Core Data across multiple devices using iCloud

There has been a lot of discussion lately about the issues with iCloud and Core Data and how Apple's APIs are currently broken in iOS 5 and possibly iOS 6.
Is it possible, given the current state of Apple's Core Data API, to reliably sync across multiple devices using iCloud?
If so, how would you do this? If not, please recommend an alternative approach.
This blog post will lead you to a chain of recent articles about the travails of developers attempting this approach.
From my own understanding and experience, I believe it is doable, but don't buy into the idea that you will get anything "for free". Depending on your data model, you may be better off syncing your whole persistent store as a document rather than using the documented core data / iCloud approach.
You may have better luck if you're already comfortable with Core Data. Just be sure you think through how to handle several important cases.
One is what to do if the user signs out of their iCloud account. When this happens, the local ubiquitous persistent store is deleted. If it makes sense for the user to still have access to their data, you'll need to manage a copy in local storage, and then manage resynchronizing when they sign back in.
Another is that changes can apparently be quite slow to propagate by default, so you may want to consider an alternative mechanism, such as the key value store, to quickly propagate sufficient information to avoid a bad user experience.
Conflict management is perhaps the most challenging (depending on your model). While the framework provides a mechanism to inform you of conflicts, you are on your own for providing a mechanism to resolve them, and there are reports that the conflict notifications may not be reliable (see linked articles), which seems strongly linked to the lag in updating.
In short, if you go into this understanding that the actual support is pretty bare bones and that you'll need to code very defensively, you may have a chance. There aren't any good recipes out there, so if you do make it work, please come back and tell us what works!
It depends on what you want to do. There are two types of Core Data-iCloud integration, as described here: http://developer.apple.com/library/ios/#releasenotes/DataManagement/RN-iCloudCoreData/_index.html
There are broadly speaking two types of Core Data-based application that integrate with iCloud:
Library-style applications, where the application usually has a single persistent store, and data from the store is used throughout the application.
Examples of this style of application are Music and Photos.
Document-based applications, where different documents may be opened at different times during the lifetime of the application.
Examples of this style of application are Keynote and Numbers.
If you're using the library-type, this article is the first of a series that goes into a lot of the problems that will come up: http://mentalfaculty.tumblr.com/post/23163747823/under-the-sheets-with-icloud-and-core-data-the-basics.
You can also check out sessions 218 (for document-based) or 227 (for library-style) of this year's wwdc.
As of iOS 7, the best solution is probably the Ensembles framework: https://github.com/drewmccormack/ensembles
Additionally, there is a promising project which will essentially allow you to do the same thing using a different cloud service.
Here is a link to the repository: https://github.com/nothirst/TICoreDataSync
Project description:
TICoreDataSync is a collection of classes to enable synchronization via the Cloud (including Dropbox) of Core Data-based applications (including document-based apps) between any number of clients running under Mac OS X or iOS. It's designed to be easy to extend if you need to synchronize via an option that isn't already supported.
Reasons for why iCloud is not currently reliable:
"Sometimes, iCloud simply fails to move data from one computer to another."
"Corrupted baselines are [a] common obstacle.... There is no recovery from a corrupted baseline, short of digging in to the innards of your local iCloud storage and scraping everything out, and there is no visible indication that corruption has occurred — syncing simply stops."
"Sometimes, when initializing the iCloud application subsystem, it will simply return an opaque internal error. When it fails, there’s no option to recover — all you can do is try again (and again…) until it finally works."
"[W]hen you turn off the “Documents & Data” syncing option in the iCloud system preferences, the iCloud system deletes all of your locally stored iCloud data[.]"
When you sign out of iCloud, the system moves your iCloud data to a location outside of your application’s sandbox container, and the application can no longer use it.
"In some circumstances (and we haven’t been able to figure out which, yet), iCloud actually changes the object class of an item when synchronizing it. Loosely described, the object class determines the type of the object in the database[.]"
"In some cases (again, not all the time), iCloud may do one of the following:
Owner relationships in an item’s data will point to the wrong owner;
Owner items get lost in synchronization and never appear on computers other than the one on which they were created. (This leads to the item never appearing in the UI on any other machine.) When this happens, bogus relationships get created between blob items and an arbitrary unrelated owner."
"Sometimes (without any apparent consistency or repeatability), the associated data for an object (for example, the PDF data for a PDF item, or the web archive data for a Web Archive item) would simply fail to show up on the destination machine. Sometimes it would arrive later (much later — minutes or hours)."
Quoted and paraphrased from these sources:
http://www.imore.com/debug-12-icloud-core-data-sync
http://rms2.tumblr.com/post/46505165521/the-gathering-storm-our-travails-with-icloud-sync
Note: I have seen one article where the author mentions getting it to work for iOS 6+, but they don't provide any examples: http://zaal.tumblr.com/post/46718877130/why-you-want-to-use-core-data-icloud-sync-if-only-it
As a reference, here are Apple's docs on iCloud + Core Data:
http://developer.apple.com/library/ios/#releasenotes/DataManagement/RN-iCloudCoreData/
http://developer.apple.com/library/ios/#documentation/General/Conceptual/iCloudDesignGuide/Chapters/DesignForCoreDataIniCloud.html
http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/CoreDataVersioning/vmCloud/vmCloud.html
And here is an example app:
http://developer.apple.com/library/ios/#DOCUMENTATION/General/Conceptual/iCloud101/Introduction/Introduction.html
The Apple developer tutorial on using the iCloud API to manipulate documents might be a good place to start.
Your Third iOS App introduces you to the iCloud document storage APIs. You use these APIs to store and manipulate files in a user’s iCloud storage.

Resources