Embracing errors is a good idea

I remember distincly when I read the article called “A More Useful 404”. I immediately added similar logic to my own sites, and while sifting through piles of email logs telling me about how IE6 does the weirdest CSS searching EVER, the emails have proved really useful to track down missing pages or especially missing redirects when a site is being rebranded & reogranized.

I felt the same wave of excitement when I learned about Crittercism. Once again, I immediately installed it in all the apps I was working on. With Crittercism, you will get an email whenever an unexpected crash occurs, but even better, you can present the user with a dialogue that collects some input from them. Suh-huh-huh-weeeet. If you give a darn about having good UX, this should be making you smile.

Must we always create an empty project!?

I wish the motion command could be modified to use project scaffolds. Then I could just say "run motion create -s colinta foo!". But alas, we cannot.

Someone add this ability to https://github.com/HipByte/RubyMotion/blob/master/lib/motion/project/app.rb. I am le tired.

  • motion create crittercism
  • cd crittercism
  • rvm use 1.9.3
  • rvm gemset create crittercism
  • rvm gemset use crittercism
  • gem install bundler
  • echo "source :rubygems"$'\n'"gem 'sugarcube'" > Gemfile
  • bundle install
  • Modify the Rakefile:
   require 'motion/project'
   # add:
   require 'bundler'
   # ...
  • Modify app_delegate.rb
   class AppDelegate
     def application(application, didFinishLaunchingWithOptions:launchOptions)
       @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
       ctlr = UINavigationController.alloc.initWithRootViewController(FirstController.new)
       @window.rootViewController = ctlr


   class FirstController < UIViewController

Let's get this party started

To install Crittercism, we start at their site, so go there now.

  1. Signup
  2. Go to downloads
  3. Go ahead and grab the "with in-app support forum", we'll play with that in this tutorial.

We're going to dump that zip file (at the time of this writing, 30 Sep 2012, the latest stable version is 3.3.4) into a vendor folder. So mkdir vendor && cd vendor && unzip ~/Downloads/Crittercism_v3_*.zip && cd ..

All we really need is the CrittercismSDK folder, so I would rm the Docs and CrittercismExampleApp folders, but I leave that to you.

Now we add it as a vendor'd project. In your Rakefile, we need to add CrittercismSDK and add a couple frameworks that Crittercism depends on:

# ...
Motion::Project::App.setup do |app|
  # Use `rake config' to see complete project settings.
  app.name = 'crittercism'

  app.vendor_project('vendor/CrittercismSDK', :static,
        :headers_dir => 'vendor/CrittercismSDK')
  app.frameworks << 'SystemConfiguration'
  app.frameworks << 'Crittercism'

You can run rake build now if you want to see the SDK compile:

> rake build
     Build ./build/iPhoneSimulator-6.0-Development
     Build vendor/CrittercismSDK   # <= that's all you get!
# ...

To get this running in our AppDelegate, we will need an AppID. So, we need to MAKE an AppID! https://www.crittercism.com/developers, and click the big “Register a New Application” button.

Register a New Application

I'll call mine "CrittercismTest", but you can call yours "My Uncle Bob" if you want. You'll end up back in the Apps section, click your newly created app, and then hop over to Settings. You just need the AppID, don't bother with the initialize code. As of today, the code is wrong anyway (well, it's outdated - it'll still work)

class AppDelegate
  def application(application, didFinishLaunchingWithOptions:launchOptions)
    @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
    ctlr = UINavigationController.alloc.initWithRootViewController(FirstController.new)
    @window.rootViewController = ctlr

    app_id = "12345yourappidhere67890"
    Crittercism.initWithAppID(app_id, andMainViewController:ctlr)


You can see the correct initialize code if you go to the docs section, btw.

And you should, because if you scroll down, you'll see a few more quick examples, of simple error handling (aka "it just works") and leaving a breadcrumb trail. It's like debugging with simple calls to NSLog, but you only see them when a crash occurs, which in this case is what we care about (in my imagination, Crittercism comes in at the "beta" phase, not during initial development).

Make it do something!

(I have this code in app_delegate, because this is such a small example)

class FirstController < UIViewController

  def viewDidLoad
    crash_button = UIButton.rounded
    crash_button.frame = [[0, 0], [132, 20]]
    crash_button.center = [self.view.frame.size.width/2.0, self.view.frame.size.height/2.0]
    crash_button.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth
    crash_button.setTitle("Make my day.", forState: :normal.uicontrolstate)
    crash_button.on :touch do
      Crittercism.leaveBreadcrumb("User pressed the crash_button")
      raise "ZOMG!!"
    self.view << crash_button

> rake

Go ahead, press the button.

You get... nothing!

That's because the crash isn't sent until the app is run again. Them's the rules. So run the app again.

You still get... nothing!

Wait one minute. I mean literally, wait one minute. Crash reports are "flushed" to the server after a minute, so if lots of crashes happen, you will get one email, not a bunch of them.

You get... an email!

It should look something like this:

Crittercism email report

Nice! We are on our way. If you have an enterprise account (or are in the trial period for one) you can add a breadcrumb trail. Let's see what that is all about:

crash_button.on :touch do
  Crittercism.leaveBreadcrumb("User pressed the button")
  raise "ZOMG!!"

If you open a crash report now, you can view the breadcrumb trail.

Apps >
  CrittercismTest >
    Crash Reports >
      *click on an error* >
        Breadcrumbs tab

Get user feedback, even though you will hate what they have to say.

Yes, you will have to filter through some pretty asinine remarks. Sorry, but unless you want to change your market from humans to some other sentient race, dems the breaks.

Let's add another button (because our crash button is working sooo well!) and have it display the Crittercism feedback controller.

def viewDidLoad
  # ...
  feedback_button = UIButton.rounded
  feedback_button.frame = [[0, 0], [132, 20]]
  feedback_button.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth
  center = crash_button.center
  center.y += 40
  feedback_button.center = center
  feedback_button.setTitle("Uh, this is stupid.", forState: :normal.uicontrolstate)
  feedback_button.on :touch do
    Crittercism.leaveBreadcrumb("User pressed the feedback_button")
  self.view << feedback_button

When I run the app now, I end up with this:

  • crittercism_fail.png

    Crittercism Fail Png

Uh, Houston?

I was stumped by this until, of all things, I committed my files to git, and there I saw this huge amount of stuff in vendor/CrittercismSDK/Resources/. We probably need those... Because Crittercism has assumed that it is being used in an Objective-C project, none of the calls to [UIImage imageNamed:x] will use any folder prefix (which we can do, and I think should do, using RubyMotion). So, unfortunately, we will just have to put everything in the resources/ folder and it's just gonna get all cluttered. :-/

Note: It would be neat if we could change or add other resource folders to the project.

> mv vendor/CrittercismSDK/Resources/Images/* resources/
> mv vendor/CrittercismSDK/Resources/Nibs/* resources/
> rake


  • crittercism_success1.png

    Crittercism Success1 Png

  • crittercism_success2.png

    Crittercism Success2 Png

  • crittercism_success3.png

    Crittercism Success3 Png

  • crittercism_success4.png

    Crittercism Success4 Png

  • crittercism_success5.png

    Crittercism Success5 Png

Now go forth and prosper!