In a previous post I showed how to use Twitter's application-only authentication to gain access to a user's timeline via API version 1.1. Now it is time to show some love to my PhoneGap friends as well. Here is the complete code to access a user's timeline. This tutorial is also a multi-parter. Part one displays a user's timeline. Part two: shows how to do a Twitter search, similar to an older post. In both, we will use app-only authentication and use ChocolateChip-UI for our looks.
YOU WILL NEED YOUR OWN CONSUMER KEY & SECRET!
I want to say that up front to hopefully stop people from complaining that the app doesn't work later. Getting a key and secret is easy and free so there is no good reason for not getting one. The app doesn't have a working key or secret. It will build, but it won't run until you replace the mock key and secret, with real ones.
Getting Your Own Consumer Key and Secret
- Simply go to https://dev.twitter.com
- Click the "Sign in" link in the upper right hand corner
- Enter your credentials and click "Log in"
- Hover over your avatar in the upper right hand corner
- Click the "My applications" link
- Click the "Create a new application" button
- Fill out the application details
- Accept the "Developer Rules of the Road"
- Complete the captcha
- Click the "Create your Twitter application" button
- On the "My applications" page, click on your application's name
- Your consumer key and secret will listed in the OAuth settings section
Keep your consumer key and secret secure. Don't do anything foolish like publish them in a tutorial.
Before we really get going, I need to address a question I frequently get asked: How can you access Twitter's API from a PhoneGap app? Aren't you restricted by the browser's same-origin policy? The answer is no. While PhoneGap apps run in a web view, they aren't delivered by a web site, they are served from by "file://". So when you see jQuery making requests of third party sites, like Twitter, don't freak out. The restrictions on making cross site requests was never on jQuery or XHR it was on the browser.
Parts is Parts
Underscore and Backbone go hand in hand. I prefer to work with Backbone because I like the way it handles collections and views. It helps keep things conceptually neat in my head. Underscore is required by Backbone and make processing the collection easy.
Moment.js is one of my favorite libraries. Today's mobile is all about timeliness. People want to know when something happen not simply what happen. Both Twitter and Facebook display time in normal people speak. They state, "5 minutes ago", "2 hours ago", "3 Months ago", etc. This is much easier for the brain to digest than Jan 15 2014 11:00:22. Moment does a lot with time including display it in how long ago fashion.
The code for the base64 encoder comes Chris Warburton via his repo on Gitorious. Your consumer key and secret must be URL encoded, combined together, then base64 encoded.
The final library is ChocolateChip-UI. It is a relatively new for me and I am still learning it. There are somethings I don't like about it but one thing for certain is the look and feel of it is amazing. Most people don't realize they are looking at a PhoneGap app. And equally awesome that it looks like an iOS app on Apple devices and looks like an Android app on Android devices. The magic is all in the CSS file. There is one for iOS, one for Android, and even on for Window Phone. The app in the tutorial on supports iOS and Android, but I will add Windows Phone later.
I use a backbone collection named tweets.js to get the tweets. In fact most of the heavy lifting happens in this file and its associated view. The best place to begin decoding the collection is with the initialize method. Backbone will automatically call the initialize method of a collection when the object is instantiated. Once called I create a deferred object to represent the state of the authorization. This necessary since the ajax call to get authorize happens async. Once the deferred object resolves, we fire an event to let the rest of the app know. Be sure to replace the urlApiKey and urlApiSecret with your own key and secret. THE CODE WILL NOT WORK WITH OUT.
In router.js the app kicks off properly with the method rnc.resolver.initialize. Most of my PhoneGap apps have this function. Because I am using jQuery with PhoneGap there are two things which need to happen before my app is in a functional state. PhoneGap must throw the device ready event and jQuery must throw the document ready event. I have seen lots of people write code which doesn't wait for one or the other and most of the time things still work, but occasionally things act strangely and in unpredictable ways. This is usually a result of not waiting. I use a deferred object to sync up the two events and call my initialize method. This ensures that my app is in a runnable state.
Once the authorization event fires, I fetch the collection. I tweak the sync method of the collection to work with Twitter's API. Backbone collections by default work with RESTful APIs. Note that I only implement the get method since can't write, update or delete tweets. Before you ask, I only want to read tweets with this app. Once the tweets come back from twitter, I do a bit of parsing just to ensure that I got some data, then I return the array of tweets.
With the collection full of tweets we display them in the view, listings.js. This view is relatively straight forward. In its initialize function it hooks an event which, route:listings-article, it is triggered in router.js and indicates that this page has been activated. The render method spits out mark-up and the show method places the rendered markup on the page.
Note: the render method uses Underscore templates to render the contents of the tweets collections as HTML. The template is stored on the index.html page as "tweets-template".
Android or iOS
In order to get the correct look and feel for each platform I use the merges directory. In it I create a CSS folder for each platform and place the appropriate copies of "chui-3.5.0.css". Chocolatechip-UI names the Android and iOS version: "chui-android-3.5.0.css" and "chui-ios-3.5.0.css" respectively. I rename both to "chui-3.5.0.css". This way when PhoneGap builds the platform it grabs the platform specific file.
This is it for this post. This code is not ready for prime time. It works but needs more error handling and things like wait spinners. Feel free to use it however you'd like. All of my PhoneGap related post are being cleaned and polish for a PhoneGap book I am working. I plan to self publish it on Kindle in April. And finally if you like this article please +1 it.