I'm really happy that we can publicly talk about iOS 8 in its beta state.  That said, this post cannot contain screenshots because of some remaining limitations in the NDA.  Also, since this was written at the time of Beta 1, what I discuss here has a chance of completely changing.  It's well after midnight as of the original writing of this post, so sample code will follow at some point.  That said, now onto the post...

There's quite a dearth of documentation on widgets, a new feature on iOS 8.  This is a tutorial that will hopefully help you avoid some of the pain points I experienced so that you can get up and running.

First off, debugging extensions of any kind appears to be broken.  In some cases I setup a debug label to show stuff on my widget to help me troubleshoot.
There is a workaround below.

Creating a widget involves creating a brand new target.  You can go to your Xcode project file and add a new target.  A dialogue window will drop down and one of the target categories will be Application Extension.  Select that, then Today Extension.  Give it a product name and select the target that you want to embed it in.

Designing the Widget

When you create the new widget target, you'll get an Info.plist, a view controller subclass, and a storyboard.  To get running quickly, you can just customize the view controller in the storyboard, adding additional programmatic setup in the code files.  Creating a widget is very, very easy and leverages your existing Cocoa Touch skills.

Sharing Data

Naturally, you're going to want to surface content from your main application inside a widget.  But even though the widget will be embedded in your app, it is its own app and has its own sandbox.  The individual sandboxes cannot mix, but Apple has created a shared container that both applications can read from and write to.  This shared container is created by enabling App Groups. This is a feature that you can turn on in the Capabilities tab of your target properties.  When enabled, you can create a new App Group and it should start with group.  This capability must be enabled on both your application and widget targets and the group ID must match.

Once this is enabled on both apps, you'll need to both read from and write to the shared container.  In iOS 7, Apple added an API to NSFileManager called containerURLForSecurityApplicationGroupIdentifier:.  This will construct an NSURL instance that can be used to reference files inside the container.
NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.com.companyname.app.widget"];

containerURL = [containerURL URLByAppendingPathComponent:@"data.plist"];

Launching The App

Another feature that may be very useful for your users is launching your app from the widget in the Notification Center.  There is a new set of APIs for doing just this that are specific to widgets.  There is a new class called NSExtensionContext that exposes a method openURL:completionHandler: that can be used to launch the custom URL in your app.  Just pass it a valid NSURL instance that your app responds to, and away it goes.
// Inside your widget view controller
NSExtensionContext *context = self.extensionContext;
[context openURL:deepDiveURL completionHandler:^(BOOL success) { // logic here }];


Debugging currently has some...limitations...that require you to attach to the process manually, if running on simulator.  Follow these steps (thanks to Daniel Kao):
  1. Build and Run your widget in simulator
  2. Go to Notification Center, include your widget in notification center, then press Done button
  3. Your widget should appear now
  4. Go back to Xcode, Debug, Attach to process by Process Identifier(PID) or Name, enter widget process ID or process name (should be the bundle identifier of your widget)

If you're doing this on device, you can just hit the run button, at which point you'll be asked to choose an app to run.  In this case, you'll want to choose 'Today', since that is the app the runs the extensions for the Today view in Notification Center.  I have found that debugging widgets on-device is very unstable, often crashing SpringBoard.  Pick you poison, I suppose.

'Wearables' as they are called is an interesting space right now.  Dominated with fitness bands that seem more fad than useful, saying that the state of the technology is in its infancy is being nice.  My biggest criticism of what's currently out there is lack of 3rd party developer support.  It could be argued that the iPhone (and by extension, Android) wouldn't be nearly as successful as it has been without other developers to build things that OEMs didn't originally think of or consider.

One of the stand-outs from this perspective is Pebble.  It has had 3rd party dev support practically since day one.  Its first release was quite rough, but v2.0 really unlocked some potential, allowing devs to persist data to the device, for example.  Even still, the path is far from well-tread and is beset with quite a few issues that are less than friendly to figure out.  Here's hoping that you can learn from my own mistakes.

Low Level Programming
C is a marvel.  The programming language can run practically everywhere and Dennis Ritchie definitely deserved receiving the National Medal of Technology because of his association with C, Unix, and other foundational technologies that we now take for granted.

But it is also a pain.  And the pain gets worse because you'll be writing a stripped down version of it that doesn't contain functions and libraries you may be accustomed to using.  The reason why: your Pebble app must fit in 24k of RAM. Yes, twenty four kilobytes of gold plated random access memory.

Get ready to get your hands dirty.  If nothing else, low-level programming makes you appreciate what higher-level languages and tools do for us. :)

There is no debugger.  I'm sorry.  This is a watch that connects with your phone via BlueTooth.

The Pebble 2.0 SDK comes with some higher-level logging capabilities, but require your phone to even see them.  I ended up using a 'debug label', a label added to the screen, for printing debug output.  It isn't incredibly useful when you're trying to debug memory issues, but it's better then trying to conduct a seance with your watch to tease out issues.

Build Your App In Stages
Because debugging is a pain, build your Pebble app in stages.  Have a plan for how you're going to build things, but don't try and do it all at once.  Start small and work big.  Commit or stash frequently so that if things go awry, you can roll changes back.  This is common sense when you're developing for a new platform, but sometimes we forget this important lesson.

Sample Apps and Documentation
The documentation that Pebble provides is...complete...but lacks clear examples on how to use all of the APIs.  Even though the SDK includes several sample applications, the coverage leaves a little to be desired.  This problem is compounded by the vast changes that were made between 1.x and 2.0 SDKs and all the search engines mostly giving back 1.x results.

Only when I had concluded making my first Pebble app did I stumble across this site that is very illustrative on how to build Pebble 2.0 apps.  I leveraged the excellent info here to add animations to my app.  It has really good basic examples and the author was even gracious to post all the code to GitHub.

Preparing for the Pebble App Store
Congratulations!  You got your Pebble app ready.  You got your iPhone code ready.  But you are actually far, far away from being ready.  Preparing for the Pebble Store is not something you do last.  You should start early in the development process.

Because the Pebble is an official Made For iPhone (MFi) accessory, there are a couple of hoops that you have to jump through that will add time to the review process. Take these steps, and the amount of time it takes to follow them, into consideration when planning your release.  If you do things right, you'll have done a bunch of this work ahead of time.  I did not and have had to learn the hard way:

  1. Create a Pebble App Store profile for your app.  This will create a Pebble Store ID for your Pebble app, which will be required in the next step:
  2. Fill out a white list request with Pebble.  Among other things, this form will ask you what the Pebble Store ID is for your Pebble app, as well as the bundle ID of your iPhone app.
  3. Go on vacation.  Seriously.  Pebble only submits their whitelist requests to Apple once a week (a Monday), so if you miss the cutoff, then you'll be stuck in the queue until the following submission.  Apple will take its sweet time as well, adding them a few days after Pebble submits the change.  Once Apple has whitelisted it, it could take 24-48 hours for the system to actually register in its systems for the reviewers.
  4. Once you have received word from Pebble that Apple has added your information to their Made For iPhone (MFi) program, you're now free to submit your iPhone app to the App Store for review.
I did all these steps at the very end of development.  With the back-and-forth with this process, it has taken more than three weeks (and still counting) to get my app through review.  YMMV, but DO NOT save this step for last.  You should be able to coordinate all of this such that everything is ready to go when your code is also ready to send off.

Wrap Up
Hopefully these things didn't dissuade you from thinking of building a Pebble app.  Pebble is just starting as a platform, but the promise is certainly there.  I really can't wait to see what happens with it and other wearables in the future.
I really buy into the premise: drive better, be fuel efficient. But this has loads of problems and ultimately makes my driving more stressful.

After nearly three months of using Automatic I got my first perfect score last week. But not for a lack of trying. The sensor dings me for accelerations that are not sudden (it's very unforgiving for standard transmissions), dings me for breaking that is not hard, and dings me for driving 69 mph (somehow the sensor thinks 69 > 70). I have a digital display telling me how fast I am, so either my car is lying to me or the device is dead wrong. Or how about when I set the cruise control to 68 and I get to 70 because I'm going downhill.  Yeah, that was totally my fault.

The fuel efficiency is wrong. Sometimes it eats trips. It's maddening.

They don't allow a data export, yet they blog about all this interesting information amassed from the user base. Allow me access to my data, please.

I'd really like to see huge improvements to their algorithms used to determine 'bad driving', data export, and even things to help me shift better (wouldn't that be cool and fuel efficient???).

Ultimately, I've decided to put this device away and *maybe* pull it back out when some HUGE improvements have been made--if I don't sell the sensor first.

UPDATE 3 MAR 2014:
Isn't social media awesome?

There is an alpha developer API for data.  Building some apps around it sound like fun, except I'd like to be able to access the link, as well.  I won't pretend that this will ever happen (and rightly so) but it's fun to wish.

As reported here, the dash speedometer may be a few MPH off from what appears through the ODB link.  My response:

@waynehartman Actually, speedometer dash display can be off by a couple MPH from actual speed. More here: http://t.co/if225gIXj9 ^AM

@automatic OK…since you know that it’s off, why not match the link with what the display shows?

@waynehartman We just take the data directly from the OBD port. But I can check in w/ the engineers about that. ^AM

@automatic Not likely available via OBD, but it would stand to reason with so much aggregate data you have an idea of which cars are off.

I have 'legacy code'.  It has been a few years since an app I wrote first debuted on the App Store, but it all still works.  With iOS 7, I decided to sprinkle in some AutoLayout to bring some parts of the app into the modern era, but ran into some problems and decided after a few commits that I wanted to back out.  I decided to roll the XIB back to it's original pre-iOS 7 self.  Except when I tried to open it, I got this really odd error: 

The document could not be opened. Could not determine the type of data.

At this point Xcode can't determine what kind of document it is, for some reason, and just gives up. I scoured the Internet for a half-hour before it donned on me: Xcode 5 makes updates old XIBs to a new XML structure when they are opened to make them more stream-lined and easier to diff, like storyboards. In order to rollback to the old version it takes a few steps:

  1. DO NOT revert your code first.
  2. Go into the document inspector in Interface Builder and change the "Opens in" attribute to "Xcode 4.6"
  3. Accept the warning that you'll lose iOS 7 capability.
  4. Roll back the changes in git.
  5. Change the "Opens in" attribute back to "Default (5.0)".
  6. Presto-chango: you have now rolled back to the old revision of your XIB and it's now in the new Xcode 5 format.
  7. Commit and push (you don't want to have to do this again, do you?)

I suspect what is happening is that Xcode attempted to parse the old format, thinking it was in the new format, and then gets discombobulated.  Interesting bug and a use case that does not appear to be in a unit test. :)

As an independent app developer I have had an opportunity to learn quite a bit about consumer behavior, how to run a business, and what it means to interact with the end user. When developing a product or service, support is often viewed as a cost center, not a revenue generator. This may seem obvious, but one of the things I have found is that support can actually be used to indirectly generate revenue.

Whether it's bugs, user error, poor interface design, or even enhancements, users seek out help after they have made a purchase. This is a golden opportunity to take what may be a less than ideal experience and turn users into advocates for your product. I have had countless instances where irate users contact me for support of my apps and because of an excellent support experience, end up giving the app favorable reviews, or in some cases, even referring friends and family to make a purchase. In a crowded marketplace, support can be a key differentiator between products.

As you are making decisions on how best to interact with your users, it is important to consider how you can make your support operation scale and align with your goals. Some important considerations might include:

  • How much do you charge for your product or service?
  • What percentage of your users do you expect to seek support and/or give feedback?
  • What expectations do your customers have for support? Conversely, what expectations have you set?
  • What methods of communication will you be willing to allow for users to interact with you?

For example, I have an app, Webmail++, that I sell on the App Store for $2.99. I offer in-app support that generates a standard email template that I have the user fill out. I make it really easy for the user to contact me on this channel. The reason I do this is because the user has paid what they think is a premium amount for an app. I try to respond to these emails within a few hours of receiving them, sometimes minutes.

Many users are very surprised by this for a couple of reasons. First, they are surprised that someone even answered. I am dead serious. People's expectations are that their support requests fall into a black hole somewhere never to be seen again. Their request was just a placebo of sorts to make them feel justified in being upset about a problem they have. Second, the promptness of a response demonstrates that I take seriously the things I do.

Fortunately, I don't have many support requests; support requests/sales per week comes out to be 2%. In this instance, support costs are minimal, but in any case I view support not as a dirty word, but as an opportunity to win over the customer and gain valuable feedback.

One last example involves another app called Trip Receipts. This was an app created over a few days to scratch a particular itch I had. I really embraced 'iterative development' by creating a minimum viable product and getting it into the app store as soon as possible. I created a very bare site and relegated support to a link at the bottom of the page in small font. I sell this app for 99 cents. I knew up front that there were going to be rough edges and things to improve over time, so I wanted to minimize support impact so that I could spend more time refining and quickly making enhancements.

By setting a low price and making the user hunt for support, I am setting expectations that support isn't necessarily going to be 'top drawer'. Interestingly enough, I have still gotten a few support requests, but they were more geared towards enhancements than reporting issues. (As a side note, these were enhancements that were slated for later iterations, anyway.)

In closing, when you're creating a new product or service it is important to consider how you are going to support it. Make sure that you have made some sort of assessment on how you expect to handle support and in turn reinforce those expectations with the end-user. And remember, support doesn't necessarily mean putting a strain on your revenue. It can actually be a means to boost it and your brand.