Some Great BlackBerry PlayBook Blog Posts

You may have noticed that a lot of us at Adobe are spending time talking about the BlackBerry PlayBook and doing a bunch of blogging. We’ve all been heads down testing content, building apps, and creating samples so when the PlayBook launches (and even before) you guys will be able to find helpful articles to build apps. The team I’m on, Kevin Hoyt’s team, has been spending a lot of time doing blog posts and I thought I’d share some of the cool ones. No matter if you’re a Flex or an AS3 developer, there’s a lot of great content.

Using OAuth for Twitter Authentication on the BlackBerry PlayBook

OAuth is becoming critical for any app developer who wants to access data from a 3rd party source on behalf of their users. If you aren’t familiar with OAuth there is an excellent intro doc over at Hueniverse. I had some difficulty wrapping my head around OAuth the first few times I tried to use it so I’ll provide a quick explanation below as I walk through the sample.

OAuth is a way of providing access from a 3rd party site (in this case Twitter) to your application without needing the user to type their 3rd party credentials into your application. Instead, OAuth lets you register with the 3rd party site and uses a series of tokens, which eventually give you access to the data. One of the main benefits with OAuth is that if an application does something nefarious with the data, the user can immediately revoke access. For this example I’ll be walking through the Twitter API and using the very excellent OAuth-AS3 library by Shannon Hicks, the founder of Pintley, which you should check out if you’re the kind of person who likes to drink beer.

The first step to using OAuth is to register with the site you want to get data from. Twitter has a very easy way to do this with their App portal. Fill in the necessary info (select the type as client since this won’t be a web-based application) and Twitter will provide a bunch of random strings that you’ll use to request access to the data and then request the data itself. The data that we’re most worried about is in the OAuth 1.0a Settings section and includes a consumer key, consumer secret, request token URL, access token URL, and authorize URL.

Getting information out of Twitter has the following flow:

  1. Use the consumer key and the consumer secret to create an OAuthConsumer object.
  2. Use the OAuthConsumer object to ask Twitter for permission to access data.
  3. Prompt the user to authorize your application to access their specific data.
  4. Request the user’s data and perform operations on their behalf.

This is all done with a series of tokens until the last stage when you get an access token that you will use to access data after the user gives you permission. I set those up as private field variables so they can be accessed from any method in this example and set the unchanging data as static variables.

private static var CONSUMER_SECRET:String = "<YOUR CONSUMER SECRET>";
private static var CONSUMER_KEY:String = "<YOUR CONSUMER KEY>";
private static var REQUEST_TOKEN_URL:String = "https://api.twitter.com/oauth/request_token";
private static var ACCESS_TOKEN_URL:String = "https://api.twitter.com/oauth/access_token";
private static var AUTHORIZE_URL:String = "https://api.twitter.com/oauth/authorize";
private static var API_URL:String = "https://api.twitter.com";
private static var SIGNATURE:OAuthSignatureMethod_HMAC_SHA1 = new OAuthSignatureMethod_HMAC_SHA1();
 
private var _consumer:OAuthConsumer;
private var _authRequest:OAuthRequest;
private var _accessRequest:OAuthRequest;
 
private var _requestToken:OAuthToken;
private var _accessToken:OAuthToken;

The first step is to have our application log into Twitter with the consumer secret and the consumer key so that it can make the authorization request. In the init() function I set up the UI as well as create the consumer and my first OAuthRequest object, the authorization request. This will just go out to Twitter and make sure that the consumer key and secret are registered to an application. If they are, then Twitter will return a request token that I can use to request access from the user for his or her data. In that init() method I have a button that will start the process and the event handler on the button uses the buildRequest method of my _authRequest object to format the URL string correctly and then I send it off to Twitter.

protected function init():void
{    
     _consumer = new OAuthConsumer(CONSUMER_KEY,CONSUMER_SECRET);
     _authRequest = new OAuthRequest(OAuthRequest.HTTP_MEHTOD_GET,REQUEST_TOKEN_URL,null,_consumer);
 
     _loginContainer = new Container();
     _loginContainer.align = ContainerAlign.MID;
 
 
 
     var button:LabelButton = new LabelButton();
          button.label = "Login to Twitter";
          button.addEventListener(MouseEvent.CLICK,onClick);
 
 
     _loginContainer.addChild(_spacer);
     _loginContainer.addChild(button);
     _loginContainer.setSize(1024,600);
     addChild(_loginContainer);
 
}
 
protected function onClick(event:MouseEvent):void
{
     var urlRequest:URLRequest = new URLRequest(_authRequest.buildRequest(SIGNATURE));
     var loader:URLLoader = new URLLoader(urlRequest);
     loader.addEventListener(Event.COMPLETE,onRequestComplete);
}

With that response I can now build the _requestToken, which I can use to let the user grant me access to his or her data. The next step is to prompt the user to authorize my application. Once I get the response back from Twitter’s servers I save that information as the request token and then build a UI to let the user start the authorization process.

protected function onRequestComplete(event:Event):void
{
     _requestToken = getTokenFromResponse(event.currentTarget.data);
 
     _authContainer = new Container();
     _authContainer.align = ContainerAlign.MID;
 
 
     var authBtn:LabelButton = new LabelButton();
          authBtn.label = "Authorize this application";
          authBtn.addEventListener(MouseEvent.CLICK,onAuthClick);
 
     _authContainer.addChild(_spacer);
     _authContainer.addChild(authBtn);
     _authContainer.setSize(1024,600);
 
     removeChild(_loginContainer);
     addChild(_authContainer);
}

When the user clicks the button my application will send them to Twitter where they will have to log in and authorize my application to use their data. They’re prompted either to deny my app or allow it.

Twitter Authorization Form

If they click Allow, then Twitter provides a PIN number that the user has to enter back in the application to complete the authorization process. For web-based applications there is a callback URL which is where the user is sent after they authorize the application. But for client-side applications, Twitter uses the PIN number and asks the user to enter it back in the application.

Getting the PIN Number

In the code, I first create the UI elements I need to track the PIN number and then make a URLRequest using the key that Twitter provided in the request token.

protected function onAuthClick(event:MouseEvent):void
{
     _verifyContainer = new Container();
     _verifyContainer.align = ContainerAlign.MID;
 
     var label:Label = new Label();
          label.size = 100;
          label.sizeUnit = SizeUnit.PERCENT;
          label.text = "Enter the PIN from Twitter.com";
 
     var font:TextFormat = new TextFormat();
          font.align = TextFormatAlign.CENTER;
          font.bold = true;
          font.size = 24;
 
     text = new TextField();
     text.type = TextFieldType.INPUT;
     text.border = true;
     text.width = 250;
     text.height = 30;
     text.defaultTextFormat = font;
 
 
     var getDataBtn:LabelButton = new LabelButton();
          getDataBtn.label = "Get Tweets";
          getDataBtn.addEventListener(MouseEvent.CLICK,onGetDataClick);
 
     _verifyContainer.addChild(_spacer);
     _verifyContainer.addChild(label);
     _verifyContainer.addChild(text);
     _verifyContainer.addChild(getDataBtn);
     _verifyContainer.setSize(1024,600);
 
 
     removeChild(_authContainer);
     addChild(_verifyContainer);
 
     var authRequest:URLRequest = new URLRequest('http://api.twitter.com/oauth/authorize?oauth_token='+_requestToken.key);
     navigateToURL(authRequest);
}

Once the user comes back, puts in the PIN, and clicks the button, the application uses that information to build the request for the access token. By passing the PIN as the oauth_verifier property we get the access token we need to start requesting data from Twitter.

protected function onGetDataClick(event:MouseEvent):void
{
     var params:Object = new Object();
          params.oauth_verifier = text.text;
 
     _accessRequest = new OAuthRequest(OAuthRequest.HTTP_MEHTOD_GET,ACCESS_TOKEN_URL,params,_consumer,_requestToken);
 
     var accessUrlRequest:URLRequest = new URLRequest(_accessRequest.buildRequest(SIGNATURE));
     var accessLoader:URLLoader = new URLLoader(accessUrlRequest);
          accessLoader.addEventListener(Event.COMPLETE,onAccessRequestComplete);
}
 
protected function onAccessRequestComplete(event:Event):void
{
     _accessToken = getTokenFromResponse(event.currentTarget.data);
 
     var mainRequest:OAuthRequest = new OAuthRequest(OAuthRequest.HTTP_MEHTOD_GET,API_URL+'/1/statuses/friends_timeline.xml',null,_consumer,_accessToken);
 
     var getStatusURLRequest:URLRequest = new URLRequest(mainRequest.buildRequest(SIGNATURE));
     var getStatusLoader:URLLoader = new URLLoader(getStatusURLRequest);
          getStatusLoader.addEventListener(Event.COMPLETE,onStatusLoadComplete);
}

Requesting data is pretty straightforward. Using the consumer and access tokens we just got we can build a normal request, send it off, and then parse the data that comes back. In this case I’m going to go through and display usernames and status for the tweets.

protected function onStatusLoadComplete(event:Event):void
{
     _mainContainer = new Container();
     _mainContainer.flow = ContainerFlow.HORIZONTAL;
 
     var sendTweetContainer:Container = new Container(25);
          sendTweetContainer.containment = Containment.DOCK_TOP;
 
     var font:TextFormat = new TextFormat();
          font.align = TextFormatAlign.CENTER;
          font.bold = true;
          font.size = 24;
 
     twitterTextField = new TextField();
     twitterTextField.type = TextFieldType.INPUT;
     twitterTextField.border = true;
     twitterTextField.width = 500;
     twitterTextField.height = 30;
     twitterTextField.defaultTextFormat = font;
 
     var tweetLabel:LabelButton = new LabelButton();
          tweetLabel.label = "Tweet This";
          tweetLabel.addEventListener(MouseEvent.CLICK,onTweetClick);
 
          sendTweetContainer.addChild(twitterTextField);
          sendTweetContainer.addChild(tweetLabel);
 
     // Code for parsing the XML from the response
     var xml:XML = new XML(event.currentTarget.data);
     var statusList:XMLList = xml.children();
     var arr:Array = new Array();
 
     for(var i:int=0;i<statusList.length();i++)
     {
          var obj:Object = new Object();
               obj.label = statusList[i].user.name.toString() +': ' + statusList[i].text.toString();
          arr.push(obj);
     }
 
     // Create the DataProvider out of the parsed data
     var dataProvider:DataProvider = new DataProvider(arr);
     var list:List = new List();
          list.dataProvider = dataProvider;
          list.size = 100;
          list.sizeUnit = SizeUnit.PERCENT;
          list.setSkin(AlternatingCellRenderer);
 
 
     _mainContainer.addChild(list);
     _mainContainer.addChild(sendTweetContainer);
     _mainContainer.setSize(1024,600);
     removeChild(_verifyContainer);
     addChild(_mainContainer);
}

The next step is to enable the ability to send a tweet. This one is a bit different. For all of the previous calls we just created a params object, and sent that with the OAuthRequest. But when we’re using POST instead of GET, things have to be done differently. Soenke Rohde has a Flash Twitter library that I used for help, but essentially we have to strip the URL params from the original request and then reset them as URLVariables to match the POST request.

protected function onTweetClick(event:MouseEvent):void
{
     var params:Object = new Object();
          params.status = twitterTextField.text;
 
     // Use the same consumer and accessToken to update the Status
     var tweetRequest:OAuthRequest = new OAuthRequest(OAuthRequest.HTTP_MEHTOD_POST,API_URL+'/1/statuses/update.json',params,_consumer,_accessToken);
 
     var setStatusURLRequest:URLRequest = new URLRequest(tweetRequest.buildRequest(SIGNATURE));
          setStatusURLRequest.method = URLRequestMethod.POST;
 
          // use the replace function to strip out the status
          setStatusURLRequest.url = setStatusURLRequest.url.replace("&status=" + URLEncoding.encode(params.status),"");
 
     // Add the status as a URLVariable since it's a POST operation
     setStatusURLRequest.data = new URLVariables( "status=" + twitterTextField.text  );
 
     var setStatusLoader:URLLoader = new URLLoader(setStatusURLRequest);
          setStatusLoader.addEventListener(Event.COMPLETE,onSetStatusComplete);
}

And that’s pretty much all there is to it. You can grab the whole bit of code over on Snipplr. Just swap in your own information from Twitter and you should be set to go.

One thing to keep in mind is that this example makes you authorize each time you use the application. In reality that would be very annoying so if you were using this in production you’d want to save the consumer and accessToken somewhere so you didn’t have to create those each time.

Getting Started with the BlackBerry PlayBook and Adobe AIR

As I’ve mentioned, I’m excited about the fact that RIM has wholeheartedly embraced AIR for their PlayBook. That means if you’re a Flash or Flex developer you’re going to be able to easily target this device along with all of the other phones and tablets that support AIR.

And there is no reason you can’t get started right away. RIM just released a new version of the AIR SDK that you can use along with their simulator to get stared building apps. I did a quick tutorial embedded below that shows the steps needed to get going. It’s pretty easy to get a jump and the emulator gives you a feel for how your application will behave on the device.

I’ll be talking a lot more about development on the PlayBook over the next couple of months and I’ve got a few projects that will be specifically targeting the 7″ form factor so I’ll be talking about those and showing some best practices.

Adobe and RIM Collaborating on Tool Support for BlackBerry Devices

At the developer conference in San Francisco today, RIM and Adobe announced a collaboration around creating content for BlackBerry devices and Adobe’s Creative Suite tools. This builds off of the momentum we started with RIM when they announced they were joining the Open Screen Project and dedicated to bringing Flash Player to BlackBerry. There are some good links on Techmeme that cover the announcement pretty well.

rim_adobe_announcement

Creating Content with Adobe Tools

Adobe is known for first class design and development tools and today’s announcement means that you’ll be able to use those tools to target RIM’s devices. There are going to be multiple points of integration. One of the critical pieces of creating mobile content is to make sure it is optimized for the smaller screens and often less bandwidth. In Creative Suite 5 we’re going to support optimized graphic and video content from Adobe Photoshop, Adobe After Effects, and Adobe Illustrator. We’re also supporting a seamless workflow between those design tools and BlackBerry’s developer tools including the BlackBerry Web Plug-in for Eclipse and the BlackBerry Java Plug-in for Eclipse.

More interestingly for developers, we’re going to be working closely with RIM to enable full support for BlackBerry devices in Creative Suite Design Central, Dreamweaver, and Fireworks. You’ll be able to use those three tools to test and create content for BlackBerry’s mobile browser as well as to create widgets directly on the BlackBerry device. Device Central is a fantastic way to test both HTML and Flash content for specific mobile devices. It lets you tweak battery settings, screen sizes, and other phone-specific functionality. Now we’ll have support for most of the BlackBerry phones so you never have to leave Creative Suite to see exactly how something will look on the phone.

Lastly, on the application front, Adobe is to be working on applications for BlackBerry that will let users take rich media and image content from the phone and quickly and easily bring it into tools like Photoshop Elements and Photoshop.com so it can be edited and modified.

BlackBerry Momentum

My colleague Mark Doherty has some great stats on what the BlackBerry market looks like and what this collaboration will mean for people who want to use their existing skills with Adobe’s tools to create mobile content for BlackBerry. Seeing the level of cooperation between Adobe and RIM is an exciting thing for designers and developers. Unlike some companies, I think RIM sees the value in partnerships, and with the breadth of Adobe tools it means they’re able to leverage our community for all kinds of different content- not just Flash.

Next year is going to be incredibly exciting for Adobe developers and designers. We’ve already talked a lot about Flash Player being available for smart phones next year, you’ll undoubtedly be hearing more about AIR, and hopefully we’ll continue to see deeper mobile integration across all of our tools just like you’re seeing with RIM here today. For more information you can check out the BlackBerry portal on Adobe’s site to get the scoop on the details and see some of the workflows in action.