The Right Way to Create an iCloud-enabled Mac App in Xcode

By · Published · apple, objective-c, xcode, mac, osx

Because I've encountered this problem twice, I'm going to do a little write-up about it. As much for me as for the next person who encounters this problem. In a very un-Apple way, this process is very poorly documented and very un-intuitive from a user-developer standpoint. Everything that's here, I've culled from Googling about aimlessly and finding on Stack Overflow.

*Symptom: *You create a new app in Xcode with no changes and launch it. It launches just fine. You then go to the target summary settings and click "Enable Entitlements" and have an iCloud key/value store and or containers. Now you launch it and nothing happens. Nothing appears, but Xcode still thinks the app is running.

*What's Happening: *To understand what is happening, you have to go have a look in the Console application (note, the actual system Console.app, not the debug console in Xcode). Open that up and select "All Messages". Look for something that looks like this:

1/28/12 7:49:03.945 PM taskgated: killed <your app ID>[pid 43838] because its use of the com.apple.developer.ubiquity-container-identifiers entitlement is not allowed

What's happening is that taskgated is killing your app because it's not properly signed to use iCloud. And for some reason that is not entirely clear to me, the app being killed is not at all reported back to Xcode - Xcode thinks the app is running. So you just sit there waiting for something to happen with no clue that this sinister lurking background process has killed your app.

How to fix it:

There are two ways you can go from here to fix this. The first and easiest, if you are just turning on entitlements and aren't intending to use iCloud, you can just remove the iCloud Key/Value Store and iCloud containers from the target summary. After doing this, it should work.

But, if you are making an iCloud-enabled app, there's a long list of things you need to do. First, understand that you need to be a paid member of Apple Developer Program.

  1. Log into ADC. Go to the Mac Dev Center, and the Developer Certificate Utility.

  2. Create an App ID by going to App IDs and clicking the Create App ID button in the upper right.

  3. Enter the name of your app and the bundle identifier. It usually looks something like "com.company.app". Click Continue. Your app ID should be entered.

  4. Click the App ID you just entered, then click "Enable for iCloud." Click save.

  5. Next, go to Certificates. If you haven't created any certificates yet, click "Create Certificate" in the upper right and follow the directions. Note, you need both a development and an application certificate.

  6. Next, go to Systems. Be sure you've added your Mac (and, for good measure, any others you'll use for development).

  7. Finally, go to Profiles.

    1. Click Create Profile in the upper right.
    2. Select "Development Provisioning Profile"
    3. Give it a name.
    4. Select the app you created in step 3.
    5. Select the certificate you want to use.
    6. Select the systems you want to use (I did all).
    7. Click "Generate" It may take a few seconds, then it will give you a download.
    8. Open the downloaded profile. It will open in the "profiles" preference pane (which doesn't seem to appear until you try to install a profile). Click install.
  8. Now, in Xcode:

    1. Go to Window > Organizer.
    2. Select "Devices" on the top, and "Provisioning Profiles" on the left.
    3. At the bottom, select "Automatic Device Provisioning" at the bottom, and click "Refresh". If you've never done this before, you'll need to log in with your ADC username and password.
    4. Give it a second, it should pull in your profiles.
    5. Go to your project, select your app target and select "Build Settings." Scroll down to "Code Signing." You may need to go to "All" from "Basic" in the predicate selector.
    6. Under Code Signing Identity, select the dev profile you just created. Note: don't use the wildcard one - it doesn't seem to work.

Whew. Now, if everything went as planned (and you sacrificed a goat to Tim Cook and Tim found your sacrifice pleasing) you should be able to launch your app with no errors.

But help! I got a weird failure on build!

If you get a failure on build that looks like this:

Command /usr/bin/codesign failed with exit code 1

Then it is possible that your developer certificate is set to "Always Trust" in Keychain. It needs to be set to "System defaults" for reasons that escape me entirely.

Note, this may not be entirely accurate and may even be cargo-cultish. But I've encountered this "issue" twice now (once in December, and once now) so I decided to write down my steps so that, in a few months when this befuddles me again, I'll know where to look for the answer.


What An Awesome Future We Live In

By · Published · ramblings

Sometimes it's easy to forget what an amazing modern world we live in. Even if I think back just 10 years ago, it blows my mind how much has changed. Just in technology, even.

In 2002:

  1. Nokia was the largest cellphone manufacturer. Their top selling model that year was the Nokia 6100. I actually had one of these as a loaner phone once. At the time I was carrying this more modest model - a Qualcomm QCP-2700, complete with green screen.

  2. Tablets as we know them today didn't exist. Oh sure there were primitive early tablets - Palm Pilots and the Newton come to mind. But they had as much in common with today's tablets as a horse does with a Ferrari.

  3. HP was the leading computer manufacturer that year - following their purchase of Compaq. The same HP that almost sold it's computer division late last year.

  4. Facebook and Twitter didn't exist, and the best site on the web for tech news was still Slashdot. Wikipedia had just opened the year before and was still seriously lacking content.

  5. Mac OS X 10.1 was released that year, and I spent all summer lusting over the Titanium Powerbook G4 with it's PowerPC processor running at a blazing 800 megahertz and a huge 40gb drive.

  6. If you wanted to read a book, you bought a paper book. e-Book readers, while the existed, were clunky and difficult to use, and titles were mostly restricted to technical publications. Nothing like the Kindle, Nook, iPad and other readers.

  7. Using the Internet on a mobile device, if it was available at all, was extremely limited. Remember WAP? I remember being amazed in college that I could use my phone to check the scores of other games while I was at an Auburn game.

  8. Wanted to find your way around? You had a map or directions. GPSs as we know them today didn't exist, and certainly weren't integrated into phones.

Contrast that to today. The phone in my pocket is more powerful, has more storage, than that laptop I spent a whole summer lusting over, and can be used to surf the web just as well as any computer. The tablet I carry with me has access to a whole library of books, can connect wirelessly to the Internet almost anywhere, and can be held with as single hand. If I ever get lost, I can pull up a map on my phone that pinpoints my location to within a few yards of my area, and can give me turn by turn voice directions to get where I'm going.

Facebook and Twitter connect millions of people together. I can even connect to the Internet on my laptop _in an airplane at 35,000 feet! _Downstairs, I have a 60" widescreen TV that's 1.5" thick and weighs so little that I could mount it on the wall.

Every time I hear people complaining about how things suck, I'm reminded of this video. Because everything really is amazing right now. We are living in an amazing futuristic world full of fascinating advancements that are are happening all the time. And what is most amazing of all is how quickly we got here. The world of tech between now and 10 years ago are so different.

What will the world of 10 years from now be like?


Mac Oil Price Widget, Version 2.0 released

By · Published · apple, dashboard widgets, dashcode, mac, osx

After a far longer wait than was intended, the Mac Oil Price Widget version 2.0 has been released.

It was completely rewritten – like, I didn’t even look at the old code – and uses Bloomberg Energy as it’s information source. The display was also simplified – I really didn’t care about the chart in the old version, so the new version prominently displays the price and how much it’s changed.

Download Here!


dystill 0.2.1 released

By · Published · dystill, e-mail, python

Just a little announcement about a maintenance release to dystill. 0.2.1 has been released, which brings with it a couple of bugfixes for issues I ran into recently. First, it will now optionally try to create new maildirs when they don't exist (this is configurable in the config file). There's also some more error checking to hopefully prevent crazy behavior.

As always, the source is on github.


PHP, methods, functions, and the global scope

By · Published · php

It's funny. Even after nearly 10 years with the language, there are still little gotchas that sometimes get me. I ran across one today.

Say you have two objects, and the look like this:

<?php
class ObjA {
    public static function test() {
        global $test;
        var_dump($test);
    }
}

class ObjB {
    public static function test() {
        $test = 1;
        ObjA::test();
    }
}

ObjB::test();
?>

It doesn't work. You get NULL.

Say I were to do something like this:

<?php 
class ObjB {
 public static function test() {
     $test = 1;
     global $test;
     var_dump($test);
 }
}

ObjB::test();
?>

You also get NULL. And this:

<?php 
function a() {
    $test = 1;
    b();
}

function b() {
    global $test;
    var_dump($test);
}

a();
?>

Also fails.

The reason is that the global scope on PHP is just that: global. Any time you're in a function or method, you're in a local scope and all local scopes are independent of each other. So you can't global in something from one local scope to another. Variables are either global or local.

That much I get and makes sense (and is in the documentation). What threw me for a loop was that PHP won't copy something into the global scope from a local scope that is already defined *and will happily overwrite your local scope with a null value from the global scope if one doesn't exist in the global scope, *in the process of creating the variable in the global scope. If you want a variable in the local scope to be global, you have to declare it as global before you write a value to it.

Or, to put it another way:

<?php 
class ObjA {
    public static function test() {
        global $test;
        var_dump($test);
    }
}

class ObjB {
    public static function test() {
        global $test;
        $test = 1;
        ObjA::test();
    }
}

ObjB::test();
?>

Works beautifully.


App Store Entitlements, and the Crippling of an App

By · Published · apple, objective-c, xcode, mac, osx

A few months ago, I decided I wanted to try exploring the Mac App Store ecosystem as a developer. I've been writing little Objective-C apps for myself for awhile, and I decided I wanted to see what it was like from the other side.

So I wrote this little app called Airplane Setting. It was a stupid simple little app that made it easy to turn off your radios with a single action. I wrote the app and paid my $99 admission fee. And after a month of back and fourth with Apple and a couple of rejections for what I consider to be dubious reasons as best (especially seeing as how I could point out existing apps in the store that broke the "rule" they said my app was breaking, but whatever, their store, their rules...), my little App was finally approved for sale. It did moderately well, passing 1,000 downloads with virtually no advertising from me.

I had big dreams for this little app. Plugins, global hotkey support, localization, Applescript support, and more potential functionality. But all that was dashed by "Entitlements" and Apple's requirement that all apps must be sandboxed.

Look, in theory, the idea of sandboxing an app is not bad. The problem here is Apple's all-or-nothing approach to sandboxing. The selection of entitlements are just so limited as to be nearly useless for anyone creating a unique, new or complex app - especially one that requires hardware access. Your choice is either to sandbox your app, choosing from the available selection of entitlements, or not sandbox it and not be in the Mac App Store at all starting in March. There's no reason to only provide such a limited subset of functionality that a developer must choose from. Would it not be better to provide us a wider set of entitlements and allow us to justify our reasons for needing them when we submit our app?

The reason Apple gives for requiring sandboxing is to prevent "rogue apps" from destabilizing the system. But when you consider that the App Store itself is curated, this requirement makes even less sense. If Apple is curating the store, how does a "rogue app" end up in the App Store?

I'm a huge Apple fanboy. I have almost all Apple hardware in my house, from my iMac to my Macbook Pros, to my iPad and iPhone and my wife's iPod Touch. I had AppleTVs before they were cool (and there's one on every one of my TVs now). I love Apple. But as an developer ... I [expletive] hate Apple for this "innovation" that crippled my once-promising little app.

So, at this point, my options are:

  1. Leave Airplane Setting in the App Store. Doing so will mean no further updates so I'll likely cease development.

  2. Remove Airplane Setting from the App Store and start distributing it exclusively from the website.

My original intent with Airplane Setting was to explore what it was like to be an App Store developer. I guess ... now I know what it's like to be an App Store developer, and living in constant fear of Apple as a sword of damocles hanging over your head.


Goodbye GoDaddy

By · Published · news, ramblings

Using GoDaddy as my registrar is one of those things I've always felt vaguely ashamed of. Something I knew all the "cool kids" didn't do, but I was already so neck-deep in them that I didn't want to transfer. Not to mention I had my DNS hosted with them as well so the thought of going through all that trouble to move just seemed like too much of a hassle to deal with without good reason.

In my last entry, I talked about setting up your own DNS server. This was the first part of my attack on moving my domains away from GoDaddy. But I didn't have a real timeline to move away from them.

Then came the news of GoDaddy's support for SOPA - one of the worst attacks on the Internet since 1996's Communications Decency Act.

Now, to be sure, GoDaddy's position on SOPA was not the first thing they've done to anger me. Their overtly misogynistic advertising has always bothered me, and their CEO Bob Parsons' elephant killing and shameless exploitation of the natives angered me so badly that I almost left in April. But their aggressive support of SOPA was the final straw for me. I'd been a customer since 2003, but I simply could not take it anymore.

So over the course of about 4 days, I transferred all my domains to Namecheap. Having never transferred a domain before, the process was surprisingly quick and easy. Once again, it makes me wonder why I haven't done it sooner.


The Stupid Simple Guide to Setting Up Your Own DNS Server

By · Published · linux, networking

I'm a developer, first and foremost. I like writing code. To me, maintaining servers, configuring things, troubleshooting network issues and the like -  these are things I do to support my primary interest and job as a developer. I'm not ignorant of these things, but all things considered they're not my favorite things to do.

One thing I will admit I've been ignorant over the years is DNS. Oh sure, I know at a high level how it works. I even know a bit about the different record types. I knew enough to have my own domain name, configured using Godaddy's DNS servers to point to my server. But actually running my own name server? Something I've never done and, for some reason, had this unnatural fear of.

Well, no more. I'm now running my very own shiny new name server and, actually, it wasn't really as difficult as I thought. And because this was a learning experience for me, I figured I'd walk you through what I did as well.

Picking  a Server

There are two big players in the "DNS Server software" space: BIND and djbdns. BIND is the 900 pound gorilla that has been around forever and ever, and is insanely difficult to configure. djbdns is from the same guy who wrote qmail - I'll let you be the judge of that. But after researching and actually attempting to install both of these, I eventually gave up. Both just came across as being too complex for a simple name server handling a couple of domains, and the documentation for both was equally complex.

That's when someone on Twitter pointed me to MaraDNS. I looked it over and was surprised to find good, readable and simple documentation that made it look easy to install. So I decided to give it a whirl. Here's what I did. Note that this install is for a Gentoo system. Yours will be different if you're using something else.

Installing and Configuring MaraDNS

First step is to install it.

emerge maradns

And let Portage do its thing. Once it's installed, you really only have to worry about a few files. In /etc/mararc, you need to check to be sure you're binding to the right interfaces. In my config, I bound it to the loopback and to the main interface:

ipv4_bind_addresses = "x.x.x.x, 127.0.0."

After that, you tell it to be authoritative, and what domains you are wanting to serve records for.

csv2 = {}
csv2["robpeck.com."] = "zones/robpeck.com"

Note the period at the end of the domain name - it's important. Each entry in the csv2 array should map to a zone file. I put mine in the "zones" subdirectory (which, in Gentoo, lives under /etc/maradns).

mkdir -p /etc/maradns/zones

Then, with your favorite editor (which should be vi :P), you create your zone file. The one for robpeck.com (partially) looks like this:

robpeck.com.       NS ns1.epsilonthree.com.
robpeck.com.       NS ns2.epsilonthree.com.
robpeck.com. +3600 A x.x.x.x
robpeck.com. +3600 MX 0 robpeck.com.

www.robpeck.com. +3600 CNAME robpeck.com.

So what are we doing here? Well, here it helps to know something about the different types of DNS records. I'm not going to cover all the different types of records - this is a good list of common ones and Wikipedia has a full list. The important ones you need to know are NS (Name Server), A (the main record), MX (mail server records), and CNAME (alias). The "+3600" is setting a timeout on the records to one hour (3,600 seconds). By default, the server will send one day (86,400 seconds).

Here, I'm telling the server what the name servers are (strictly speaking, this isn't required, but I added it all the same) and that the main address for people requesting "robpeck.com" is this IP address. I'm also saying that people who request "www.robpeck.com" should get the IP address for "robpeck.com." I also add an MX record that points to robpeck.com with 0 as the priority (the first (and only) server).

That's it! Restart MaraDNS:

/etc/init.d/maradns restart

And you can test it out.

dig @localhost robpeck.com A

You should get a big long printout, but what you want to see is these two lines:

QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 0
robpeck.com. 3600 IN A x.x.x.x

Assuming the above is the correct address, congratulations, your DNS server is now resolving properly locally.

Delegating your Domain

The next step is delegating your domain to your own server. I'm not going to cover this in too much detail because how it happens depends on the registrar. In general, this is a two step process:

  1. Register your name server's IP address to a name. At NameCheap, when you're in the domain screen this is done under Advanced Options > Nameserver Registration. Under GoDaddy, this is under the "Hosts" section of the domain information screen. You need to add at least two "nsX.domain.com" entries, but they can both point to the same IP.

  2. Delegate your domain to the names you just created. At NameCheap, you would go General > Domain Name Server setup, and Specify Custom DNS Servers. Then, enter the two (or more) names you just created "nsX.domain.com". I can't remember how I did this in GoDaddy, but I remember it was pretty apparent.

That's it! They say it takes 24-48 hours, but I started seeing requests hit the new name server within about an hour. Of course, since I wasn't actually changing IP addresses, there was no real downtime.

As of now, all my domains are being served off my own nameserver. It's kind of a neat feeling of accomplishment, knowing you're not relying on someone else's DNS setup - they're just providing you a name. This makes domain transferring much easier and adding new records much easier. And seeing as how I'm currently in the process of transferring all my domains away from GoDaddy, this will ease the transition.


Goodbye, Eclipse.

By · Published · apple, pc, php, windows, mac, osx

Dear Eclipse,

We've known each other a long time, haven't we? I remember when we first met. It was way back in 2005, two jobs ago when I was working at interactive Point of View. I was still a young, naive kid, just out of college. At the time I was just getting my start writing serious PHP code, and you were a breath of fresh air compared to what I had been using before (Dreamweaver). You seduced me with your awesome power and functionality.

I used to love being able to have code on top and a browser window underneath. Ironically enough, one of my favorite features would eventually be something I couldn't care the slightest about.

Later that year I would move on to Asteria, and I took you with me. This was the first time I had two monitors on my desk, and I kept Eclipse in one, and a browser in the other while programming. Again, your raw power made complex tasks easy. I discovered Subversion integration, which made Tortoise (I was still on Windows at the time) irrelevant to me. Your Subversion tools turned me into a huge fan.

When I moved jobs again, to dealnews, I again took you with me. Much to the chagrin of my coworkers, I preached the gospel of Eclipse. When I first started I was still in the Windows environment and my setup was much like it was at Asteria. Later that year when I switched to Mac, I again took you with me. You occupied a place of honor in my dock.

We upgraded together. Through Callisto, Europa, Ganymede, Galileo, Helios and Indigo. We upgraded through Leopard, Snow Leopard and Lion together.

Sure, we had our occasional disagreements and outright fights. I remember one time when you would absolutely choke on the size of dealnews' code tree. I would try other editors and IDEs. I tried jEdit, Coda and TextMate. But I always came back to you.

But all things change, and this time I think we're finally through together.

The first sign you were no longer interested in me was the dropping of the official PHP build - the one I had been using for years. But you knew I was worried - you even said so on your website and pointed me to PDT - PHP Development Tools. This aphrodisiac, you told me, would make our relationship just like we were kids again.

But what you didn't tell me was that PDT would make you crazy and unstable in the worst kind of way. Your behavior has become increasingly erratic whenever you take PDT. You developed bugs, including ones that I could no longer justify. Ones that were literally costing me time every day. You said PDT could auto-complete code and when it does it works great. But when it doesn't, the display glitches up the file so badly that the only way to get back into a usable state is to close the file and reopen. Now imagine doing this four or five times for every file you're editing, every time you try to auto-complete some HTML. Your ill tempered behavior is costing me time and money.

I tried to talk with you about it, but all you could say was NullPointerException.

So, I've thought a lot about this. It's been a good six year run, but I think it's time we ended our relationship together.

The truth is that I know about your other boyfriend, too. I know his name is Android, and I know you guys have been spending a lot of time together. And I'm okay with it. Really. All things change and we all have to adapt. The truth is I've been fooling around some with your cousin Netbeans, and I think we're really hitting it off. In many ways, she reminds me of you. The difference is, Netbeans has herself together, is trying hard to improve herself and hasn't forgotten who her friends are, instead of getting strung out on PDT and spending all her time hanging out in the backseat of Android's Pinto.

So goodbye, Eclipse. What we had was wonderful while it lasted and I'll always treasure our time together and the memories we made. I hope your new life works out. Maybe we'll see each other from time to time, but I honestly I don't think that would be fair to Netbeans. She's my new IDE now.

-Rob Peck Eclipse User, 2005-2011