Marco Arment posted one of his regular iOS device and OS version stats overviews yesterday. While Marco’s stats obviously only represent Instapaper users and one has to be careful how representative the data is, these updates are nevertheless very welcome as they represent one of very few publicly available data points to estimate the adoption rate of iOS versions.
iOS 5 Adoption Rate Only at 45%
The most striking number to me is the rate of iOS 5 adoption: across Instapaper users on all iOS devices, 45% are running iOS 5. This strikes me as quite low. I would have expected a number in the range of 70–80%, especially considering that Instapaper users are probably significantly more geeky than the average iOS device owner.
How to Forcefully Exclude Older Devices From Running Your App
According to Marco’s numbers, having an app that requires iOS 5 would still exclude a lot of users at this time. Most developers should probably wait a least a few more months until they cut off iOS 4 support.For developers of apps that require a relatively high-performance device to run smoothly, that begs the question: how do I best restrict my app to only run on newer devices?
It is important to implement such a restriction in a way that enforces it not only at runtime but also at install time. Otherwise, you will (rightfully) get lots of e-mail from angry iPhone 3G owners (if your app even makes it through the review process). Here are the options you have:
1. Require a Certain iOS Version
We just learned that it is probably too early to require iOS 5.0 but what about iOS 4.3? iOS 4.3 does not run on anything that’s older than the iPhone 3GS and it has an adoption rate of 88% in Marco’s stats. In fact, that is what Marco recommends:
Developers of CPU-intensive iPhone apps and games can celebrate the continued infiltration of faster hardware, with at-least-3GS-class CPUs in 94.39% of iPhones and iPod Touches. Apps that need high performance can probably start requiring iOS 4.3 (87.8%) to forcefully cut support for the much slower old CPU in the iPhone 1, iPhone 3G, and 1-2G iPod Touches.
2. Require Certain Device Features such as OpenGL ES 2
If your app uses OpenGL ES 2, you are done because the GPUs in devices before the iPhone 3GS do not support that version. All you need to do is specify opengles-2 under theUIRequiredDeviceCapabilities key in your Info.plist file.
This is a convenient option but you should only use it if your app really uses and requires this special feature. Don’t just arbitrarily select a convenient option from the available device capabilities.
3. Require the armv7 CPU Architecture
One convenient way to sort of circumvent this rule is to explicitly require a device with a fast CPU: one of the options for UIRequiredDeviceCapabilities is armv7, which tells Apple and the OS that your app only runs on the modern CPU architecture that is used by the iPhone 3GS and all newer iOS devices. That way, you can allow iOS versions 4.0–4.2 and still restrict your app to modern hardware. (Please only do this if your app is really close to unusable on an iPhone 3G. Users of older hardware are probably used to somewhat slow performance, so they won’t necessarily hold it against you if your app stutters a bit.)
Requiring the armv7 CPU architecture in the UIRequiredDeviceCapabilities key.
Note: Patrich Burleson noted on Twitter that he heard of app rejections when apps added new requirements to the UIRequiredDeviceCapabilities in an update. I find it hard to believe that that is a general rule. It must be allowed for existing apps to switch to OpenGL ES 2.0, for example. But it’s probably good to keep in mind.
BAMSettings is a generic handler for presenting and changing settings from within your iPhone app. By adding two files to your app and pushing BAMSettings onto your navigation controller, you will have the full functionality of Apple’s Settings App from within your own app.
Why Use BAMSettings?
Okay, so you’ve carefully crafted a settings bundle for your iPhone app and you would like to give your users the ability to change settings from within your app, too. After writing several custom settings pages it has occurred to me that it would be useful to have a generic handler for this purpose. Since this is such a common occurrence, I’ve decided to release the code publicly so you use it in your apps for free.
Identical to iPhone Settings
Your existing settings bundle will be used to present an interface which is identical to the existing iPhone settings. It is fully localized and will use your strings files to present the settings in whatever language the user has selected on their phone. Your multi value fields, text fields, toggle switches, sliders and groups will be automatically populated in the same familiar way that your users have become accustomed to. In addition to the usual setting types, you can also use group footers, child panes, and title values which are less common and not in the default Xcode dropdown menus.
Even Better than iPhone Settings
While writing this, I couldn’t help but add a few small improvements: The keyboard can be dismissed by pressing the return key while there is no way to dismiss a keyboard on the iPhone settings app, BAMSettings can rotate to any orientation while the iPhone settings app only supports the portrait orientation, and in an effort to ease the debugging of your settings bundle, BAMSettings will display a table cell informing you if you use a setting type that is unknown rather than simply ignoring it. If you run across a setting type that Apple’s settings app handles but is unknown to BAMSettings, please let me know so I can update the code.
Use It for Free
I’m releasing BAMSettings publicly under the permissive Simplified BSD License (FreeBSD) to allow reuse by anyone who wants to use it. You can modify the code in any way that suits your project whether simply changing colors and fonts or even adding custom settings types. It was designed to be a great jumping off point for any in-app settings project. I would appreciate a credit and a link back to this site if you use it but it certainly is not required and I would enjoy hearing from anyone who uses this in their projects.
How to Use BAMSettings
The BAMSettings Demo post gives detailed instructions for adding BAMSettings to your project and includes a downloadable demo project.
I have chosen to leave BAMSettings sparsely commented. It is my belief that comments simply dilute the code (by decreasing the amount of actual code onscreen) when it contains thoughtful naming and is viewed by an experienced programmer. However, if others would find it useful, I would be willing to write a blog entry that explains precisely how the code within BAMSettings works.
Another quick tip: there are a bunch of defines which Apple provides you while your app is compiling and you can make great use of them. For example you whether the app will run on the device or in the simulator.
How to detect the iPhone simulator?
First of all, let’s shortly discuss. UIDevice provides you already information about the device
[[UIDevice currentDevice] model]
will return you “iPhone Simulator” or “iPhone” according to where the app is running.
However what you want is to use compile time defines. Why? Because you compile your app strictly to be run either inside the Simulator or on the device. Apple makes a define called TARGET_IPHONE_SIMULATOR. So let’s look at the code :
#if TARGET_IPHONE_SIMULATORNSLog(@"Running in Simulator - no app store or giro");
It’s that easy. Now you can take care and maybe simulate some kind of input that lacks in the Simulator vs the device or other stuff you want to take care of.
Now I’ve seen a ton of pages where some folks would just skim trough the Apple code find TARGET_OS_IPHONE and wrongly assume this define shows that the app is being compiled for the iPhone device. That’s wrong! I can’t believe there are even people complaining that Apple’s code is buggy because TARGET_OS_IPHONE is always 1.
Well let me put some light on that and please don’t make the same mistake. As the name of that define very clear explains this is a define which tells you whether the app is being compiled for the IPHONE OS ! Because even if most of the developers know only the iPhone development, actually XCode also provides development for the MAC OS X. So, if you are doing iPhone apps – yes! – TARGET_OS_IPHONE will be always 1.
How to detect the device
I feel this discussion will raise the question how to detect the device then. There’s 2 code samples you should use:
#if TARGET_IPHONE_SIMULATORNSLog(@"Running in Simulator - no app store or giro");
#elseNSLog(@"Running on the Device");
and when ONLY interested in the device
#if !(TARGET_IPHONE_SIMULATOR)NSLog(@"Running on device");
So, hope this article was helpful. Please leave comments on ping me on Twitter.
Box2D is a great physics engine, but while there are some iOS code examples out there – there really aren’t too many tutorials around utilizing the iOS platform that also demonstrate the fundamental principles used by the engine.
I’ve found one tutorial that does a great job of explaining some of the more intermediate Box2D tutorial topics utilizing Cocos2D iPhone – specifically addressing Forces, Ray Casts and Sensors. I previously mentioned the first part of this tutorial which was created using LevelHelper and SpriteHelper (which are not required for this portion of the tutorial).
The tutorial demonstrates the creation of a Kid Icarus style platform game, and utilizes sensors and ray casts so the enemies can attack the game character with intelligence, and applies forces to keep the enemies floating in the air. The tutorial also demonstrates how to create a HUD overlay in Cocos2D for the game menu, and life tracker.
Here’s a video demonstrating the tutorial in action:
Overall, I think it’s a great tutorial on building a platformer. Personally I really never thought of using Box2D for some of the functionality it’s used for in the tutorial, but it definitely makes things easier once you have a basic understanding.