Crittercism is awesome and free, so why the heck aren't you using it!? a rubymotion thought by colinta
View the source at github.com/colinta/thoughts
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
rvm use 1.9.3
rvm gemset create crittercism
rvm gemset use crittercism
gem install bundler
echo "source :rubygems"$'\n'"gem 'sugarcube'" > Gemfile
- Modify the Rakefile:
require 'motion/project' # add: require 'bundler' Bundler.require # ...
- 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 @window.makeKeyAndVisible true end end class FirstController < UIViewController end
Let's get this party started
To install Crittercism, we start at their site, so go there now.
- Go to downloads
- 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
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' end
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.
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) @window.makeKeyAndVisible true end end
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!!" end self.view << crash_button end end
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:
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!!" end
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") Crittercism.showCrittercism(self) end self.view << feedback_button end
When I run the app now, I end up with this:
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