Archive for the ‘iOS’ Category

03With iOS 8, getting the right launch screen has become a real pain. If you support only iOS 8, and you don’t need iPad, or everything is Portrait or some such, you’re fine.

With one of the apps I work on for Five Pack Creative, I need to support Landscape-only, iPad and iPhone, iOS 7 and 8. And man, getting the Launch screen correct has been tough. There are several choices — launch image catalogs, a launch nib/xib, and launch filenames. For Landscape, both types of device, both iOS versions, I’ve only found one approach that works for sure.

First, for iOS 7, you need to use the filenames approach. If you have any entries in your Info.plist related to launch screens, delete them. Just use the standard filenames.

  • Default.png : 320×480 rotated — not used, but it’s the base filename
  • Default@2x.png : 640×960 rotated — for the iPhone 4, 4s on iOS 7.x
  • Default-568h@2x.png : 640×1136 rotated — for the iPhone 5, 5c, 5s on iOS 7.x
  • Default-Landscape.png : 1024×768 — for the iPad 2 and Air
  • Default-Landscape@2x.png : 2048×1536 — for retina iPads

Don’t use an Asset Image Catalog for iOS 7!! Just create a folder, then add those screens to your project, creating a Group for the Folder as they are copied in. The folder will be created under your project. This is IMPORTANT — don’t just drag in individual screens. It’ll work, but not when you have another target, e.g. a free version and a paid version of your app. You’ll need the exact same filenames with different images for the various versions of your app. Putting them in differently-named folders before adding the entire folder (and create a group) works best. DON’T use Folder references — iOS can’t find your launch images if they are under a folder reference — it must be a group.

Now, for iOS 8, you’re going to use a Launch.xib file and asset images. I’ve seen places where people assert that you can use filenames, manually editing your Info.plist. I guess that approach works for them, but I couldn’t get it for my specific situation. Using their solutions prevented iOS from properly detecting an iPhone 6 — it ran it in scaled iPhone 5 mode.

Create a new launch screen (File, New File, User Interface, Launch Screens). Add that to your target settings (Project, Targets, General, Launch Screen File). Select the XIB and add an ImageView to the View. Size it to match the View, then make sure you have the proper Size Class selected before adding Constraints. You want Regular/Regular (iPad Landscape).

ConstraintsWith the ImageView selected, select the class using Editor/Size Class/Regular Width/Regular Height. At the bottom of the Interface Builder screen, you should see “wRegular hRegular”, indicating the size class you are editing. Add the constraints by Ctrl-Drag from the ImageView to the View. Hold the Shift key to select multiple items — Leading, Trailing, Top, Bottom. That should create your constraints with zero as the constants. Don’t worry about the View (frame) height and width — your size class images will take care of all that.

So now you need images for your ImageView. You are going to use some of the same ones. First, if you don’t have an image asset catalog for your specific target, add one (File/New File/Resource/Asset Catalog). Add a new set (click the + button) and call it Launch.

Okay, now for the really cool part, and where it all comes together easily. When you added the Launch image set (not to be confused with a Launch Image Source setting in your Target — we could have called it “Monkeys” instead of “Launch”), you’ll see 3 spots for images (1x 2x 3x) and underneath, “Universal”. Over on the right sidebar, you should see Devices, Width, Height, etc… Change Devices from Universal to Device Specific, and select iPhone, Retina 4-inch and iPad. Change Width to Any & Regular.

Now you should have two sections: iPhone and iPad, and two rows of boxes.


All you have to do now is fill the boxes with the appropriate images, and you’re done! The [* *] and such have specific meanings. The documentation is very good for this —

  • 1x [* *] iPhone is a landscape 480×320 — same as Default.png, but not rotated.
  • 2x [* *] iPhone is Default@2x.png, not rotated
  • Retina 4 2x [* *] iPhone is Default-568h@2x.png, not rotated.
  • 3x [* *] iPhone is 2208×1242.
    • The [+ *] versions are exactly the same — but you have to copy it into both!
  • The iPad files are 1x Default-Landscape.png, 2x Default-Landscape@2x.png — for both rows.

Now go back to the ImageView on your Launch.xib and give it the filename Launch.

Woo hoo! Everything works, and all your devices come in with the correctly detected resolutions and launch screens. Note that you can check the resolution like this:

CGSize uiSize = [UIScreen mainScreen].bounds.size;
if (uiSize.height > uiSize.width) {
  // iOS8 returns bounds based on orientation
  CGSize rotatedSize = CGSizeMake(uiSize.height, uiSize.width);
  uiSize = rotatedSize;
switch ((int)uiSize.width) {
  case 736:       // iPhone 6 Plus   736 x 414
  case 667:       // iPhone 6        667 x 375
  case 568:       // iPhone 5s/5     568 x 320
  case 480:       // iPhone 4s/4     480 x 320
  default:       // iPad

 As I’ve worked building the Cartera OfferLink app on iOS, I’ve learned a little about Apple’s Push Notification service. One thing that I wanted to do from the start was avoid sending a notification when someone might be sleeping! Every once in a while, I’ll get a text message early, like 6am. I’m a late sleeper, and the BUZZ! that my phone makes will always wake me.

I really don’t like that.

So I decided early on that I’d do the best I could to avoid sending messages at inappropriate times. I know you can change your phone settings to avoid notifications at certain times, but the default – and most folks devices are set to the default – is to just deliver the message when it arrives, buzzing and binging and waking you up.

What I did with OfferLink is send the current time, local to the phone, to the server, along with its data requests. Then I calculate the seconds offset from the server and the phone’s time. This gives me the current time zone of the phone as of that request.

It’s not a perfect system – the user could fly around the world to a different time zone, and get a notification before the app refreshed its data and told the server its new time zone. But it should be a good 80/20 solution – solving for 80% of users.

// (pseudo code for handling the time zone)
localTime = time();
remoteTime = localTime + tzOffset;
if (hourOf(remoteTime) > 8 && hourOf(remoteTime) < 22) doNotify();

Please be kind to your users – handle push notifications in such a way that you don’t annoy them.

Or wake them up.

It’s finally here (or at least it’s in the App Store awaiting review)! This is the Super Conversions (aka SuperConvert) that I’ve always wanted to develop. I had some time, so I coded almost non-stop, and it’s ready to roll. This is a fully functional calculator, with Memory, sin, cos, Pi, tan and other useful functions. See the calculations at the top and the unit conversions at the bottom, with easily selected conversion categories and units. Copy either the calculated value or the converted value.

If you have a support question on this or other SuperConvert or Super Conversions apps, please post a comment below or @Super_Covert on Twitter. There are also “conversion facts” that show up every once in a while. If you have a fact you’d like to see in the App, tweet it to @Super_Convert and I’ll add it to the list. Include a link to an image if there’s an appropriate one for the fact. Note that all facts are moderated.

The design of the new SuperConvert 9.0 is actually based on an old calculator I’ve had for about 28 years. The solar powered device still works, and it’s still the primary calculator I use at my desk. Check out the picture of the app and compare it with the picture I took of my calculator. I used that picture to design most of the visual elements of the app.

If you have any support questions, or features you’d like to see, bugs to report, etc… – please post a comment below and I’ll get back to you.


I’m currently testing an iPad Dashboard app for QuickBooks Windows Desktop. It shows a few informational things about your QuickBooks company in a dashboard style app on an iPad. I have no idea yet if it’ll be useful for anyone, or if I’m showing the right kind of information. I’m using to get testers running the app before (if) it goes live in the Apple App store.

If you’ve never published into the Apple app store before, and you’ve never used TestFlight before… I have to say, it isn’t an easy process to use. It took me about 3 hours to finally get the TestFlight process down to the minimum. I installed and deleted and re-installed on my iPad.

Apple doesn’t help – if you delete a device from your allocation of 99 test devices, then re-add it, it takes up 2 slots. I added my personal iPad, then deleted it, then added it again. Presto: down to 97 devices. Avoid deleting a device if you can. Apparently my allocation will reset after a year. When I pay another $99 for the iOS developer subscription.

Intuit has, of course, a developer account and provisioning certificates and all that… but is also limited in the number of devices. When you have a dozen apps you’re testing, then the team doing the apps will need their own iOS developer subscriptions. I guess that’s okay.

And that’s step number 1: get your own iOS developer subscription.

Apple has a great product in Xcode, but make sure you have the latest version – 4.3.3. Because if you don’t, using TestFlight gets harder.

That’s step number 2: use the Mac App Store to install Xcode 4.3.3 – note that it’ll nicely, at least mostly nicely, update your Mac and get rid of the older version for you.

Step number 3 is to always use Xcode to manage your developer profiles and account – go to the Organizer in Xcode, Devices/Provisioning Profiles and click Refresh. That’ll generate the various certificates and such that you need – just click the various dialogs to automatically submit requests and such. Hey, and make sure your iPad is connected to your Mac when you do the refresh.

Next you will need to go back to the Developer site and add an Ad-Hoc Provisioning profile. That’s step number 4. Provisioning, Distribution, New Profile, Ad Hoc. That’s pretty much it – select all your devices (probably only your personal one will be there). Apple will accept that “new profile” as a request, then approve it. Apple used to take up to 24 hours, it seemed, to approve, but now it appears to happen within seconds.

Step number 5 is to go back to the Xcode organizer (after your Ad-Hoc profile is approved) and click Refresh again. That’ll download the new Ad-Hoc provisioning profile.

Step number 6 is to make sure your app is setup with the proper profile. In Xcode, go to your Target, Build Settings, Code Signing. Click the Top “Code Signing” line and select iPhone Distribution. If the Ad-Hoc is the only distribution profile you have, it’ll be the one properly selected for everything. If it isn’t the only one, you’ll have to look at the drop down and select your new Ad-Hoc profile.

Okay, that’s it for the basics. Those 6 steps don’t have to be done again. However, the next part of the process, using TestFlight, is a bit repetitive – you must do it over and over, every time a new tester is added (or at least every time you want to authorize new tester(s) for your app).

Step A: Invitations – TestFlight has a couple of ways to invite folks. I’ve found the one-off invitation form to be useful. Click on Add Teammate and you can enter an email address and a short message. The recipient will get a link to’s acceptance page, with a single button click to accept (and an optional form to fill out if they want to permanently register on

In addition to Accepting, the invitee must also install a TestFlightApp profile on their device (shows up as an Add my device type of button after Accept is clicked). It’s just a matter of “Yes, accept, yes, install, Done” type clicks.

You’ll get an email for each action – Accept and Device Added. The Device Added email will include an attachment containing the device ID for that tester.

Which brings me to Step B: Add Device. You must add that tester’s device ID to your Apple developer account list of devices. In the developer portal, click on Devices, then click Upload Devices. Select that text file that was attached to the email from TestFlight. That’ll add that tester’s device.

Next, you must add that new device to your Ad-Hoc Provisioning Profile, aka Step C. Click on Provisioning, Distribution, then click Edit and Modify next to your Ad-Hoc profile. There you can Select all the devices for that profile – the new one you just uploaded will be available but un-selected. Just select it and then click Save.

Step D: Update Xcode. Now go back to Xcode’s Organizer and click Refresh. It’ll churn for a bit, eventually updating your Ad-Hoc profile with the new one that includes the tester devices.

Step E: Compile and save your app as an IPA file. Now that you have valid testers in the Ad-Hoc provisioning profile, you can compile a version of your app that is ready for TestFlight-ing. Build for Archiving, then Archive. The organizer will pop up and you can select Distribute, Save for Enterprise or Ad-Hoc. Make sure you select the same Ad-Hoc provisioning profile in the subsequent drop down that you used to create the build. The dialog will ask you the filename to save as an IPA.

Step F: Upload your build to TestFlight. Next click on the Upload Build in TestFlight and upload your IPA. Easy peasy.

Step G: Inform your tester. After uploading, you’ll see the “Permissions” dialog in TestFlight. Select the new tester and click the Update and Notify button. That’ll send an auto-generated email to that tester with a link to install the app.

And you’re done! At least until the next time a tester accepts your invitation, because you’ll have to go back to Step A (well, really Step B since they’ve obviously been invited already) and do it all over again! Ahh well, at least it’s much easier than trying to enter those IDs manually and distribute the IPA to be installed via iTunes or other such messy means.