Keep Data out of Code
Moving any resources, such as long strings, or tables, out of code and
into external files will make the final download smaller, because
external files compress more efficiently than when the data is
compiled into a binary. See iOS App Store Specific Considerations for
full technical background.
How much does strings affect binary size in iOS apps, being in code versus their own file?
Is this something significant? Right now my binary size from code is 4mb, but it has a lot of long texts. How much can it decrease?
Related
I always thought these words are just file format that use some special compression method, but recently I find a file format "DDS" that can use DTX1 as the compression method. So I'm curious, if they are all just compression algorithm, do that mean I could for example use DXT1(ETC1, PVR) as compression method to get a PNG image?
They are hardward supported binary compression formats (not file formats).
DXT1, DXT3, DXT5 are supported on desktop GPUs
ETC1 is supported on most mobile GPUs
PVRTC is supported on GPUs made by PowerVR/Imgtec which is all iPhones (and some Androids?)
If you want to use them you generally run some offline tools to generate them and then either write a loader for the format the tools spits out or roll your own. You then pull the data out of the file and call gl.compressedTexImage2D(...) with the data.
The advantages to compressed texture formats are that they take less GPU memory so you can use more of them and also that they can take less memory bandwidth meaning they can potentially run faster. The disavantage is that although they are compressed they aren't compressed nearly as small as say a .jpg (generally) so they may take longer to transmit over the internet. For games stored on your local machine like a game you install from Steam you really don't care about how faster the game downloads, you expect it to take 10 minutes to several hours. For a WebGL game meant to be played on a webpage most users will not wait very long so there's a trade off.
Another issue with these formats is like it says above they only work on certain devices. To support them across devices you'd need to do something like query WebGL by calling gl.getExtension for the various compression formats and then request from your server the correct set of textures for the user's device. For native games that's generally not an issue since an Android app is made separtely from an iPhone app and that's separate from a desktop app but for a web page ideally you'd like any device to be able to run the same page. A desktop machine, a tablet, maybe a smartphone. (although for android there are many GPUs so the problem is similar there for native android apps)
Here's an article that explains PVRTC and another about DXT/S3TC
I've successfully built the camera demo from the ios_example and it's running perfect. The problem is that the binary size is comparatively large (Around 11MB binary footprint per CPU architecture). What i'm trying to do now is to shrink the binary size as much as possible.
There is a part named 'Reducing the binary size' in the official document: https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/ios_examples . In the last paragraph it said:
After that, you can manually look at modifying the list of kernels included in tensorflow/contrib/makefile/tf_op_files.txt to reduce the number of implementations to the ones you're actually using in your own model.
So i removed a bunch of items from tf_op_files.txt and rebuilt iOS binary by executing compile_ios_tensorflow.sh, hoping it would reduce the generated binary size. However, the size didn't change at all, not even a single bit. I've tried serval times, i also tried to clear all the content of tf_op_files.txt, but still got the same result.
I guess i was doing wrong somewhere. Does anyone know how to do it right? Or is there any other way to reduce the binary size except those from the official documentation?
Any information is appreciated. Thanks!
TF already has to tool to do 8-bit Quantize. It can largely decrease the model size but may hurt the precision.
If I store important values in a plist in xcode, is that less secure than if it was hard coded in a class? Could jail broken devices mess with those values easily? I know there's a certain level of risk with everything, but can someone explain the relative risks of a flat file vs hard coded values (in a MyClass.m file)?
Sub question:
How do you go about storing large amounts of initial data for a game/app to run on? It's fine if the values are readable, I just don't want them easily writable.
as for reading data:
plist data is not secure at all - getting plist content takes virtually no time! (and as the ipa is just a renamed zip you don't even need a device ;))
Extracting compiled code is 'harder' but in case of plain text strings only by a small margin.
(again: no need for a device)
as for writing to it:
data is you deliver is never writable without breaking the code signature. Therefore any method is fine. Often one ships CoreData databases when using CD, but I also use xmld, jsons, plists.. to deliver my content. whatever suits the needs best
note: breaking the code signature makes the app unusable on a stock iOS device but I think It'd remain usable on a jailbroken phone as the kernel doesn't really check the signature there
The values stored in you source files (.m) are safe, it is quite hard to access them. On the other hand accessing an app's plist, image sources, and other files are quite easy, there programs to achieve this (for example: Iexplorer) and it doesn't have to jailbroken at all.
So if you have sensitive information stored in your plist, it worth to encode the file, or store it in your source code.
Anyone can access a .plist file. But if is hard coded in a class is much more secure, use the second option. Nothing is 100% secure, but hard-coded in a class if someone want to access this value, the work is more hard.
You can store your Data into NSDictionary, then convert it to NSData, then do some simple crypto (re-order bytes for ex), then write to you application folder. When you want to read them, just take the content of the file, then decrypt, then re-create NSDictionary.
convert NSDictionary to NSData:
NSData *someDatas = [NSKeyedArchiver archivedDataWithRootObject:aDictionary];
convert NSData to NSDictionary:
NSDictionary *aDictionary = (NSDictionary*) [NSKeyedUnarchiver unarchiveObjectWithData:someDatas];
The data is secure in the way that the user cannot modify the content the right way cause the data won't be valid while application read it.
If you're looking to store sensitive values that you don't want jailbroken devices or reversed engineered app to get access to, you can easily think of using UAObfuscatedString.
As quoted:
When you write code that has a string constant in it, this string is saved in the binary in clear text. A hacker could potentially discover exploits or change the string to affect your app's behavior.
UAObfuscatedString only ever stores single characters in the binary, then combines them at runtime to produce your string. It is highly unlikely that these single letters will be discoverable in the binary as they will be interjected at random places in the compiled code. Thus, they appear to be randomized code to anyone trying to extract strings.
Having values hard coded in code or in a plist file is considered risky for sure.
I am encrypting downloaded files and saving them locally in app's documents directory.
To read them you must decrypt those file and store some where temporarily.
My concerns are:
1.if I store them in doc directory for time they are being used, for that time window one can get those files using tools like iExplorer.
2.My idea is to store them in memory for the time they are being used and flush the vault after use.
This option is good for small files but for large files say 50 MB or video of 100 MB, I am afraid that app will receive memory warning in result will terminate abruptly.
I want to know the best approach for doing this.
There is no perfect security storing local files in a safe way. If a person has full access to the device, he can always find a way to decrypt the files, as long as your application is able to decrypt it.
The only question is: How much effort is necessary to decrypt the files?
If your only concern is that a person may use iExplorer to copy and open these files, a simple local symmetric encryption will do the trick.
Just embed a random symmetric key in your application and encrypt the data block by block while you download it.
You can use the comfortable "Security Transforms" framework to do the symmetric encryption. There are some good examples in the Apple Documentation.
When you load the files, you can use the same key to decrypt them while you load them from the file system.
Just to make things clear: This is not a perfect protection of the files. But to decrypt the files, one has access to your app binary. Analyse this binary in a debugger and searching for the decryption part to extract your symmetric key. This is a lot effort necessary just to decrypt the files.
Split your files into smaller sizes before saving them, then decrypt on load.
Later edit: I noticed this is mentioned in the comments. I agree splitting files isn't the easiest thing in the world, but presumably you'll only need this for video. About 100MB is a lot of text or audio. If your PDF weights as much, it's probably scanned text, and you can change it into a series if images.
And yes, splitting better be done server-side, don't want the user waste battery in video processing.
Decrypt them, obfuscate them with a toy algorithm (e. g. XOR with a constant block), and store them in documents. When needed, load and decrypt.
Since the problem has no solution in theory (a determined enough attacker can read your process memory after all), it's as good a solution as any.
It seems info about zip performance on iOS is a bit sparse, so I'm hoping someone can elaborate a bit on the subject (or do some testing since I do not have that option).
I've written a pure C project for use in an iOS application (for iPad 2/3) which uses some pretty large data files (5x ~300 MB) and I know these can be compressed quite well (5x ~90 MB). Currently the application will select one of the 5 unzipped data files and memory map it - this can be changed on the fly.
Because the data files are unzipped this action happens pretty much instantly, but it's quite a large app, so obviously I'm wondering - what if we unzipped the data files on the fly? How long would a switch (delete current data file, unzip new data file) take?
I'm hoping the answer can also be helpful to others who'd like a quick lookup for iOS zip performance.
Anyway you should uncompress these files to the flash drive, not to the memory (since there is not too much memory on iDevice), so your app will require ~1Gb of free storage to run.
So, since this storage can not be used in any other good way, I would recommend to uncompress the data on the first run (and, probably, not deliver data files with the app but to download them from your site).
And, yes, decompressing ~500Mb file would take a while on iDevices.