Remote Nib Loading for Fun (But Not Profit)

A while ago I noticed an interesting API for creating a UINib object from data:

+ (UINib *)nibWithData:(NSData *)data bundle:(NSBundle *)bundleOrNil

At the time I didn’t have a use for it, until this exchange occurred on Twitter:

The resulting exchange was very fruitful, including this gem from ex-Apple employee Michael Jurewitz:

So I wouldn’t recommend using this in a shipping application, but I wanted to see if it worked. I created a simple app that loads a nib from a website, then tries to initialize a view controller’s view using it. You can view the whole project on GitHub, but here’s the relevant code:

Would I recommend using this in a shipping app? Absolutely not, given Jury’s recommendations. But it is an interesting idea for enterprise, in-house, or jailbreak apps, and I can see the possibility for some very cool stuff to come out of it.

Enforcing iOS Security Settings in Third-Party Applications

A while back, I was working on an  application for a client with a very specific requirement. Since it collected personal data, the application could only run on iOS devices that were protected with a passcode. This requirement, seemingly very simple from the client’s perspective, was a bit of a hassle to implement on the programming side of things. There’s no simple method on UIDevice to determine if a passcode is set, nor is there a way to force that programatically. In fact, there’s no way to force most things like that. The iOS device isn’t the programmer’s, it’s the user’s. Except when it isn’t.

One of the things that you can do is to use the iPhone Configuration Utility to make a configuration profile. These profiles can support a range of things, from requiring a passcode (or even an advanced, non-numeric passcode) to WiFi settings, VPN to CardDAV settings. Creating a configuration profile that requires a passcode, then installing that configuration profile onto the device is a no-brainer. But how do you ensure that the application will only run in that case?

Disclaimer: Before I go any further, you should know that since this was an in-house project, none of the code that I wrote made it into the App Store. Therefore, I don’t know if this is kosher in an App Store app, nor do I recommend this approach for that.

One thing that you can do is to include a self-signed certificate in a configuration profile. Those of you familiar with OpenSSL may be groaning as you realize where this horrible, horrible workaround is headed. I created a new certificate authority. With that new certificate authority, I signed a separate certificate that I had created. Verifying this certificate, then, requires that the verifying party accept the certificate authority’s certificate as valid. Well, since you can set that in the configuration profile, I did, along with the passcode requirement. Then, in the app, I bundled the certificate that I had signed with my CA.

When the app starts up, it attempts to verify the certificate. In the case where the configuration profile is installed and the CA’s certificate is in the system’s keychain as trusted, this is no problem: the certificate checks out and my app is free to go. If that validation fails, however, then I know that the certificate from the CA is in the system, so I know that the configuration profile is installed, as well.

Why this works for a passcode so well is that to install a configuration profile on a device without a passcode when the profile requires one is that you can’t install it without setting a passcode in the process. For the client, this was Good Enough, and the app shipped and worked properly. It’s worth noting, though, that the less the end-user knows about this process, the better. To circumvent the passcode restriction, all one would have to do would be to modify the configuration profile to still include the CA’s certificate, but not the pas code requirement. For that reason I can’t recommend this for anything like EMR or tax records, but for minor demographic information like we were collecting, this sufficed.

I realize this didn’t include any code, but the individual portions aren’t that hard, and I don’t have access to the original code so I’d have to re-write them all. Here they are in a nicely-formatted list for those keeping score at home:

  1. Create a new certificate authority with OpenSSL.
  2. Create a new certificate, then sign it with that certificate authority you just created.
  3. Create a configuration profile in the iTunes Configuration Utility with the settings you would like to enforce.
  4. In the “Credentials” section in the iTunes Configuration Utility, add your CA’s public-facing certificate to the configuration profile.
  5. Add the certificate you signed with your CA to your application’s bundle.
  6. In your application, verify the certificate you included.
  7. Distribute the configuration profile along with your application to end users.

Like I said, this is far from perfect. But when you’re working with an enterprise client who has Big Needs, this is one trick to keep in your back pocket when you’re up against a deadline.

Selling “Physical Goods” or “Goods and Services Used Outside of the Application” in an iOS app

Since this question has come up a few times, I thought I’d record my answer to a common question:

Can I use an iPhone app to sell something outside of the App Store?

Reading Apple’s rules for the App Store makes developers nervous. We’re walking on eggshells, hoping that our application will not run afoul of the myriad of regulations put forth by Apple for inclusion into the store. So, questions like this come up. I’ll reproduce my answer here:

Obviously, I am not a lawyer, but I think you’ll be OK. Here’s my interpretation of the three relevant rules from the developer guidelines (emphasis mine):

11.1 Apps that unlock or enable additional features or functionality with mechanisms other than the App Store will be rejected.

11.2 Apps utilizing a system other than the In App Purchase API (IAP) to purchase content, functionality, or services in an app will be rejected.

11.3 Apps using IAP to purchase physical goods or goods and services used outside of the application will be rejected.

The first rule prohibits you from unlocking anything inside of your app with something other than the App Store. This would prevent you from, say, making a game that downloads new levels from your server based on your membership to a website.

The second rule prohibits you from, say, making a game and enabling PayPal in it to unlock more levels. Apple wants you to use in-app purchase for that.

The third rule—and this is where it gets interesting—prohibits you from using in-app purchase in an application to buy “physical goods” or “goods and services used outside of the application.” Nowhere does it say, however, that you can’t use other purchasing systems.

With that third rule, I think what Apple is saying is this: anything that runs on the iPhone must be purchased through the App Store, and everything purchased in the App Store must run on iOS. For something like insurance, which isn’t new functionality in the app, I think you’ll be OK. This is absolutely worth an e-mail to Apple’s technical support staff, but if you look at Amazon’s app, you can purchase physical goods using Amazon’s checkout system.

I’d love to be proven right or wrong on this. If my reading is correct, then using an iOS app as a storefront is perfectly acceptable. If I’m reading this too charitably, then you’re better off making this type of application for a different platform.

Take Me Home Now Free

Take Me Home is an ancient, buggy iPhone app that was my “Hello, World!” in the App Store. Its sale rate has plummeted to only a couple of buyers a week and, with the prevalence of real, honest-to-God GPS apps in the store these days, its usefulness is questionable. So from here on out, it’s free. I can’t promise to continue supporting it—especially for new devices and APIs—so the best I can do may be to remove it from the store in the event that some update breaks it.