I'm currently in the process of adapting an existing iOS app into what will be a family of very similar apps (each app instance will probably map to a different country/region).
I'm planning on having a different build target for each of these instances, and the only differences between them should be:
Images (probably just the splashscreen and icons)
Localizations
String variables: base URL for remote services, application ID, support e-mails, etc (possibly half a dozen of such variables)
The code itself should be the same on all apps.
What I'd like to know is what you consider to be best practices for managing a family of applications like this.
Regarding images and localizations (or resources in general), it should simply be a matter of adding/removing the appropriate files from the target (and I guess I can even use the same name for images, in different directories).
The main thing I'm not sure about are the other configuration variables.
I've heard / thought of a few options:
Using preprocessor macros and a main configuration header file with the different URLs, IDs, etc
Loading them from a plist (or similar configuration file) whenever the application launches, and having one such file per target
Creating an empty .sqlite file (this app already uses Core Data) and populating it with the default configuration variables, and having one such file per target
I think the first option is the fastest to get out of hand once I have a few instances of this app, plus I have to recompile every time I change one of these settings.
The third option I'm also not sure about, because I'll be adding entities to my database which don't feel like they belong there, plus it kind of feels like overkill for what will probably be 5-10 settings. I'm also not sure about how to add new settings on updates.
So I'm leaning more towards the second option.
Thoughts? Any alternatives to these?
UPDATE #1:
Regarding the second option, there is also a drawback that those strings (ids, URLs, etc) will be slightly more exposed (i.e. if someone was to open the app and look through the plist) than if they were in the source code. Not that this is that big of a problem, but it's just something to consider.
Update #2:
How about using the app's info.plist directly and storing it there? (thus having an info.plist for each target configuration) Even though originally I was thinking of having a separate plist, and having a "configuration singleton" which would load everything from there on startup, I think it may be simpler to simply have it in the info.plist and then reading it via [[[NSBundle mainBundle] infoDictionary] objectForKey:#"com.example.mykey1"].
I would take the preprocessor option. You can put all your preprocessor in one file/method and it will not be too messy. Like oefe said, change the .sqlite is overkill. And with the multiple plist, you will find yourself dragging things around and doing a lot of error prone actions.
However, I would not make a lot of apps. I would just make one app, let the user select his city at launch. You could also add in-app purchases to let the user add more cities when he wants to.
Your app will be easier to maintain : do you want to upload, change description and screenshots for 10+ apps at each update? I find this painful to do with 1 app...
You will not spam the AppStore : having 10+ more apps in the AppStore with the exact same purpose is ridiculous... That's exactly why Apple made in-app purchases, to avoid that situation.
You will have to find different icon for each of your city : your icon is one of the most important aspect when selling your app on the AppStore. You want it to be as polished as possible. Apple won't allow multiple apps to have the same icon and differentiate icon by putting a label on it is not a good option.
I ended up going for the plist, but instead of creating a new one I used the info.plist file for this, thus no need for extra files per target, as I already needed to have a separate info.plist for each one. I simply load them directly from the bundle with:
[[[NSBundle mainBundle] infoDictionary] objectForKey:#"com.example.mykey1"]
I also used preprocessor (with flags set on the target settings) for a couple of things, but that was mostly for when I wanted to disable/remove completely some parts of the app (e.g. to make sure I got everything I commented out enumeration values and even includes in a couple of places).
I think it's relatively clean and I can easily replicate this for future builds without too much of a mess.
Given that the variation is per country/region, and these variables are strings, why don't you simply treat them as localizable strings, thus reducing the problem to one already solved?
Otherwise, I would go for the plist. Sqlite seems to be an overkill, and is not source-control friendly. And conditional compilation will get messy fast.
Related
How does this sound conceptually.
I wanted to store some text and add tags to it thats easily retrivable. Coredata is the obvious solution, but i also needed that data across the cloud, not just iCloud like dropbox. So I thot i'd use Coredata + textFiles.
obvious approach
use coredata with two entities. One for text and one for tags. Works awesome BUT not ready for syncing.
1. using icloud coredata combo will hurt me badly, its still unreliable, and i cant afford to keep stabilising it.
2. i dont just have ios devices, need it on my computer too.
the solution
Add text in a simple textview.
Add tags to the text as well using some kinda delimiters.
Save the document as a text file (that includes tags) and give the document some unique name
Put that file in dropbox or icloud or whatever as a document But Also, parse it locally in the iOS app so that the text in file is separated into text and tags each of which enters its entity in coredata.
advantage for the solution
I can use the text in a useful way locally (in iphone) and if needed will get those text files from the cloud.
problem with the solution
Data in the cloud (as textfiles) is only so useful. But nonetheless, its there, i can live with this.
SYNCING: how do i make sure that each file is synced appropriately. Im not sure I should use UIManagedDocument? I'm already using coredata locally, dont know how i'd complicate things if i use UIManagedDocument.
My question is, im confused about the syncing and saving part, what should i do to keep it neat and clean.
While writing this question i feel like I screwed up the whole idea.
I can write at design time a setting bundle, but I need to make its content appear according to certain condition
can I do that , if yes any sample code, and where to put this code
Best regards
You can't dynamically create a Settings.bundle and write it out while your application is running on the iPhone. It needs to be included in the code signed application package.
What you can do, though, is customize your already created bundle's content & UI based on those certain conditions. E.G. different preferences load different strings or graphics.
When releasing to the application store someone wrote in an offhand comment that you need to avoid embedding your images into the executable.
How do you do that?
I've seen code in various books that suggests encoding images as C byte array constants in the source code, and I can say that that's definitely a bad idea for reasons ranging from inefficient pixel formats to unsalvageable memory. That would qualify as "in the executable file" in a way that bundle resources don't, since bundle resources are packaged alongside the executable rather than within it.
I am not sure if I get you correctly, but maybe he meant accidentally adding image files to the Compile Sources category in your build target? This usually does not happen with images, but i have seen it happening with js files.
Perhaps they meant that you should only include images in the bundle that are essential.
The bundle is essentially read-only so you cannot remove an image from the device that is in the bundle. Therefore placing lots of example images that you expect a user to remove/not want is not a good idea because when the user deletes the images from inside your app no space on the device will be reclaimed.
Of course it is fine to place images in the bundle just make sure that they are required and are not taking up unnecessary space that the user cannot reclaim.
Sweet..I bought myself a 1TB portable harddrives this week. Don't you just love how much data you could store on one of these disks? The fact that I could store my bluray rips on to my portable harddisk and that my lg lcd tv can do HD rips right from the drive - that's amazing practicality right there! However, life it seems, is never so simple. I have 100s of movies unorganized in one huge folder, which is exactly what I needed to annoy myself while browsing the same on my tv to play a single movie. That got me thinking...
What if I had an automated way to organize movies into folders such that my folder-browsing-on-a-lcd-tv-or-a-comp would make my life a little easy?
I started thinking about this... I browsed a little in this context and I realized that if only I could "tag my movies somehow and create folders on-the-fly based on tags using hardlinks", I would have addressed my problem. I googled a bit to find software that works in the above fashion, only to find none.
A few more days of serious thought (as you know by now.. I think a lot.. and I guess this question is starting to sound like a blog rant/post of sorts...), in the interest of humanity, I thought I should come up with a generic way to address this: What if someone wanted to organize photos... organize music.. organize software?!
Turned my grey cells off for a while and here is an approach I came up with to solving my what-if scenario.
Tag / Group tag individual files (rely on a slick GUI to do it fast and do it good) - Adobe Flex/Eclipse RCP to do this?
Create hardlinks to each of the tagged files.
The first point is self-explanatory. The second (coz I am talking windows here), refers to making use of mklink.exe.
Consider a scenario where I have 2 movie files: I have a movie file "Transformers.avi" tagged as "english, action, bluray, sci-fi, imdb-top-50, must-watch-with-kids" and another movie file "The Specialist.avi" tagged as "english, bluray, thriller, adult". Here are a few of the possible locations I want to see my Transformers to be found:
[root directory]->all-tags->english
[root directory]->all-tags->bluray
[root directory]->all-tags->english->all-tags->bluray
[root directory]->all-tags->bluray->all-tags->action
[root direcotry]->all-tags->english->all-tags->action->bluray->all-tags->imdb-top-50
Given that windows has a limit of 1024 hardlinks to a single file, I probably would be allowed 7 unique tags per file. Each sub-folder will have an "all-tags" folder. Having it named "all-tags" makes it more accessible when order by name.
I believe this approach when automated to let you configure tags you want and where the hardlinks are created for you, helps you organize stuff effectively.
I don't know if there are better things out there. I would like your inputs on this approach and other possible ideas. I would like to gather inputs here and release something to sourceforge for everyone to use in a couple of weeks. I am sure, I can count on your positive response as always.
I believe hardlinks are not a good approach. Reason? A standalone player won't play them, and I wouldn't like a program who's made for tagging to tell me to stop making so many tags because of a Windows limitation on hardlinks (remembering each tag will increment the number of links exponentially).
Plus, "help" is not a good tag.
And I've had an idea once that I'm still planning to make some day to sort my own files - put the files in a big storage each below a GUID foldername (filename untouched) and store metadata in a sqlite database to be used by a smart file browser.
I was considering doing something similar to this with music for detecting duplicate songs and auto-organize funcationality.
For your application, I wouldn't recommend using any shell programs through Java. Exception handling becomes difficult, and your application becomes bound by the shell interface and implementation (i.e. windows versions or installations affect your application behavior).
I would use a database with a few tables: Files, Tags, and an association table.
The Files table would list the physical location of each file, the filename, and a unique identifier. This way, you can maintain information about each file without having to modify it for every tag association.
The Tags table would list each tag, and any metadata you want to store for each tag.
A third table, maybe 'FileTags' would store the assocation between tags and files. When adding tags to the stack, you would add a statement to the WHERE clause, and the list of files with all of the tags would be returned. This structure would also allow open your codebase up to other designs, such as include/exclude (autocomplete with X buttons), or possibly search.
If implemented in Java, your app would be platform independent, and would allow a very large number of tags and files. You can then use the system default application for opening the media file, and the user can make the selection in their native OS.
Reiser4?
...
(I mean nevermind Hans, but the tech...)
[disclaimer: Not a hacker. I know nothing of programming/coding, never mind filesystems & databases. I can barely code decent HTML even, if at all. Hey y'all! :D]
[footnote: does plain HTML5 work here? Too lazy to close my tags hehe :p]
Um, I working on a dictionary app and currently trying to add narration for each article. I have about 97000 AAC-files. They are tiny - about 3-5 kilobytes each, but there are so many of them! I don't need SQL DB for access management because filenames are identical to the primary keys, so given the key I will be able to pick a proper sound file from disk and play it (I expect so).
The thing I worry about are issues related to huge number of files. I don't really want to mess up with CoreData.
Will there be any problems if I just add all these files to the application bundle? Will Xcode be angry at me? Will iOS be OK with that?
If not what should I use then? How to handle huge (~100'000) number of files properly?
There is no restriction on the number of files that can be added to your application bundle.
It would be better for you if you can put the files on a folder(say audio) in the app bundle.