What is the best way to store strings in iPhone application? - iphone

I'm wondering what is the best way to store long strings in iPhone? e.g. I have 'about' page in my app which is basically an html page, and I load it to UIWebView.
Is there any better way so store it apart from store it as string in code? may be in resource file?
Thank you

You can add the html file directly as a resource in your bundle. Then when you want to use it you can use the following code
NSString* fileName = [[NSBundle mainBundle] fileForResource:#"myHtmlFile" withExtension:#"html"];
NSString* fileContents = [NSString stringWithContentsOfFile:fileName encoding:NSUTF8Encoding error:nil];
[webView loadHTMLString:fileContents baseURL:baseURL];

You can use a plist that is very flexible and fast to load.
If you plan to localize this text into different language you should use String File (both are available under "Resource" when you choose to create a new file in xcode)

I haven't done this myself, but I'm guessing you could simply deploy an HTML file with your bundle (just add it as a resource to your project) and point the UIWebView at it.

If the string will never change throughout the life of the application, you should use a resource packaged in your application bundle.
As the previous posts alluded to, you have several options. You can make a plist, an HTML file, or any other kind of file resource.
A nice benefit of these options is that you have the ability to make localized versions.
If the string will change through use of the application, you may also consider storing the value of the string in a local database with SQLite and CoreData.

Related

openURL a local file or force UIDocumentInteractionController to use a specific app

I wish to open a file (stored locally in my app) with another app.
Currently, I am using openURL (there is a dedicated url scheme), and it works fine if I use a file hosted on the internet, but I would like to use a local file so:
a) it works offline
b) a lot of the time my users are either out of cell zone coverage, or roaming internationally
What I have tried so far:
I have not had any luck telling openURL to use a local file, I have tried a few approaches but they are all something like this
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"test" ofType:#"ext"];
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
[[UIApplication sharedApplication] openURL:fileURL];
also
NSURL *fileURL = [[NSBundle mainBundle] URLForResource: #"test" withExtension:#"ext"];
[[UIApplication sharedApplication] openURL:fileURL];
also manually using strings with different variations of localhost/ and file:// and var/mobile etc paths
nothing works (for me anyway)
So, I looked around SO and came across UIDocumentInteractionController
I am able to use UIDocumentInteractionController to let the user open my local file with the other app - however it always present multiple options of other apps to use and for example, one of the other apps can be 'Dropbox'.
I do not want to let the user download (or upload technically) a copy of my file for their use in other ways. It contains data that I would prefer not to make so readily available.
When the file is opened by my intended app (not made by me btw) it does not allow any kind of saving or access to raw data.
I realize that by including the file in my app anyone who is serious about obtaining it will be able to, I just don't want to flash a big menu saying 'Here it is if you want your own copy to make derivative work from'
Ideally, I could use openURL but I think it is because of the 'sandbox' that the other app doesn't respond - in Android I use mode_world_readable to declare the file as readable by other apps (therefore placing it outside the sandbox, and it doesn't allow other apps to write to it, just read) - is there anyway of doing the same with iOS?
Otherwise, if I could force UIDocumentInteractionController to use a specific app and not present the menu - that would be fine too.
Similar question asked a while ago
Sorry about the long read, any help is appreciated.
Edit:
I just received an answer from Apple Tech support and they told me that this is currently impossible (just after iOS 6 released)
Yes, you're limited because of the strict sandboxing on iOS. Here are some thoughts.
You can override the functionality of the UIDocumentInteractionController by instead subclassing QLPreviewController. You can then replace the standard bar button item that displays the "Open in" menu. Take a look at this post for one solution for subclassing QLPreviewController: QLPreviewController remove or add UIBarButtonItems
Of course, I believe the way inter-app sharing works is largely out of your hands. If an app has registered to be able to handle a certain type of file, it is going to display as one of the choices in the "open in" list whether you want it to or not. I don't believe you can filter which apps display in that list.
Here are two experimental ideas I've thought about but have never tried:
You could base64 encode the data from the file you're trying to pass along--which just converts binary to text--and hand that off as part of the custom URL you use to launch the other app. Then the other app can base64 decode that same data back into binary. The down side there is that there is a limit to the length of the URL which means the "file" you're sending would have to be pretty small.
Next, and I don't even know if this is possible, but I wonder if you could use some steganograhpy algorithm to embed the document data inside an image and then hand that off to the camera roll. Then, the other app could open the camera roll and decode the image back into the data again. ... Yeah. I know... obscure, but it might be fun to try to implement. ;-)
Not sure if any of that helps, but you did say "any help is appreciated". ;-)
Best regards.

Xcode: hide / protect resource files in final iOS app?

I plan to develop an app for iOS and want to use HTML5, CSS and Javascript. The final app should be implemented as a native app using Xcode and UIWebView.
Can I hide or protect my html files in the final app? I have to put the files in the folder called "Supporting Files" in Xcode. Therefore, everyone can view the plain files after purchasing the app by extracting the .ipa file, right?
There's many ways to protect your data, depending on how good you want the protection to be. For very minimal protection against only casual hackers, you could use a string obfuscation algorithm to obfuscate and de-obfuscate the HTML content as NSStrings. Here's an example of doing that. I haven't used that particular code, but I'm also not really recommending obfuscation as a technique, unless the data really isn't very sensitive.
The better solution is to encrypt the HTML content, although that's more work, and may involve some export control issues, depending on where you are, and where you're distributing your app.
For encryption, you have lots of options.
1) Here is an open source implementation that provides a secure version of something like NSUserDefaults. I don't see an equivalent to registerDefaults: in that code, though, so it's possible that the first time your app runs, you may have to download the content from the web. But, then you could encrypt and store it in PDKeychainBindings as a string value. On subsequent runs, you could then extract stored HTML "files" like this:
NSString* webPageContent =
[[PDKeychainBindings sharedKeychainBindings] valueForKey: #"index.html"];
2) Here's another open source project that provides AES encryption wrappers. You would write some non-production code before releasing your app to encrypt the HTML content into encrypted data files that would be bundle resources. When your app runs, it opens the files and decrypts them into NSString objects which can be given to your UIWebView via loadHTMLString: baseURL:.
3) Finally, here's another example of using the underlying CommonCrypto APIs to protect bundle resources. This example uses a custom build step to automatically encrypt resources in a particular folder, which would save you some time if your protected HTML content is going to change reasonably often.
You can encrypt the files and decrypt them at runtime or you can not include them in your bundle and have a compile time script that reads them and converts them into encoded data in your app that you can just load into your UIWebView with:
- (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)baseURL
You could create all your HTML and so on also within your code and then use UIWebView's
- (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL
to manually load every HTML string as plain text. I advice you, however, not to do so. If somebody really wants to isolate every string from your compiled source code, this is possible for him (unless you really do demanding stuff).
Most of the users simply don't care about what's inside the ipa file. If you can live with < 1% who inspects it, don't worry too much about this topic.
Another aspect would be possible as well (even if this is not a fantastic idea): You could point your UIWebView to a secret website only you and your app know. This is absolutely not advisable.

iphone update some files in application

I'm creating one iphone application that uses and xml to get some data from and a few images. Lets say that originally these files will be in the application bundle. But then I want to make my application to get updates from a web service. So lets say I download a new xml and new Images.
Where do I save them? I think I will be able to save them in the application "cache" right?
But then How do I make my application check if this resource exists in the cache, then load that one...else load the one in the application bundle?
iOS to be used 4.3 but if it makes it easier we can go to 5.
You will have to use NSFileManager to save the file to and load it from the document directory. Check out the following link, which actually contains all the info you need:
http://www.friendlydeveloper.com/2010/02/using-nsfilemanager-to-save-an-image-to-or-loadremove-an-image-from-documents-directory-coding/
If [UIImage imageWithContentsOfFile:fullPath]; (fullPath being the NSString with contains the path to your image in your document directory) returns nil, then the image is not present, so you'll have to load the default image from your bundle.
You can access your default bundle files using [[NSBundle mainbundle] pathForResource:#"yourFileNameHere" ofType:#"yourTypeHere"] This will return the path to your file in your bundle and you can just pass it to [UIImage imageWithContentsOfFile:]
This example only applies to UIImage, but you can easily adapt it to use other classes. I think the UIImage example is enough for illustrative purposes though.
You'll probably want to create a versioning scheme. After the app starts (or periodically) call the web service for a very cheap call to ask what version it has. You'll know what version you have (write in a plist or have the version number in the folder structure). Another options is pushing a notification.
The next thing you'll have to think about is how the app reacts to getting a new data set. You could do it only on start up but that might block the start up experience if you're bounding it to a web call. The other option is to allow the dataset to change while the app is open. You could have a model that uses NSNotificationCenter to notify your views and controllers that the data has changed. I would probably version the storage as well (folder per) to help with the transition.
As for how, you can make web requests with something like ASIHttpRequest, NSFileManager to write to the documents directory, and plists to save settings like version.

iPhone: updated info.plist value not being read

I have an app that when first launched reads in its data from a local XML file and is then archived for subsequent loads.
In future app updates its envisioned that this XML file might be updated with more data. To determine if I should re-load the XML data I have placed a custom key/value (a version number for the XML file) in the info.plist.
Now when I update the version number from 1.0 to 1.1 in the plist file, the app still reads it as 1.0. I'm guessing there is some kind of caching going on. Is there a way I can get the updated version on each load?
NSDictionary* infoDict = [[NSBundle mainBundle] infoDictionary];
NSString* version = [infoDict objectForKey:#"IdeasVersionNumber"];
NSLog(#"version = %#",version); // always 1.0?!!
Is there a better method to do this? I didn't want to create a separate plist/XML file just to hold the version number as it seems like a waste of resources to load/parse these each time when the info.plist is always read.
Many thanks for any advice.
I am surprised by this behavior, but as it looks like the Info.plist is not always read, you might as well make a separate file for it. Or use NSUserDefaults.
A simple clean build did the trick! Thanks to #MCannon for the tip. I should have copped onto it.

How best to import a lot of text into an iphone app?

I have seemingly a lot of text that i need to get into my iphone app. It's not nearly as much as a book or anything but it would take quite some time to type it all out in xcode, and I'm sure thats not the best way. I read you can import an xml file or maybe a .txt, could someone please point me in the best direction, and maybe a tutorial or something to help me get started?
Thanks!
You can bundle any file you want with your application as a resource. Just include it as part of your project, and then you can load it in your app as an NSString* or NSData*, whichever your prefer/whichever is most appropriate to your data type.
You can also transform the data however your would like, and write some new file that contains the transformed information, and then grab the new file and package that one with the app so that the transformation step no longer needs to be run. For instance, maybe you want to parse your text data and prepopulate a Core Data model with it. You could write the code that does this, grab the .sqlite database file that is generated, and then package the database file in the deployed version of your app so that everyone starts out with an already-populated data model. If that happens to be your use-case here.
What you mean by get text into my iphone app? Do you want to show the text in your application? If yes, why don't you just use the this NSString method:
+ (id)stringWithContentsOfFile:(NSString *)path
encoding:(NSStringEncoding)enc
error:(NSError **)error
If your text needs to be formatted, I would recommend you to use webview to load formatted html files.