What is the iPad?

Posted in Eric Daugherty on January 29th, 2010 by admin
Inventing a new device category is hard. If it wasn't, the category would probably already exist. So there should be no surprise that Apple's iPad announcement has yielded wildly different responses. Here is my take.

First, as the happy owner of a Kindle 2, buying a $499 media pad is something I can contemplate. The Kindle DX at $489 with the same sized screen becomes a very tough sell versus the entry level $499 iPad. I love my 6" Kindle, and while it is in a different league at $259, I would have to stop and think about whether I'd buy it again today. Now, about that iPad...

The iPad is not a mobile device in the same sense as your phone. You will not carry the device around in your pocket. It is not a big phone. Instead, it is something new. I see three usage scenarios for it.

1. It is a device you use at home to access media, and play games. Videos, Pictures, Books, and the web. It is a couch device, a bed device, a kitchen table device. When you get home from work, you can leave your laptop in your bag, and just use the iPad.

2. It is a laptop replacement on trips. Headed on a short business trip, or on vacation? Don't want to take your laptop, but don't want to be stuck reading your iPhone for a few days? The iPad is a great alternative. You can take a keyboard with and catch up on emails from your hotel, but have a small device to carry in your bag during the day to spend 15-30 minutes checking in throughout the day.

3. Business/Education - Developing specialized applications and using the iPad as a computing platform. Whether it is kids in schools reading their textbooks and doing homework or sales associates at the local retail outlet showing you color alternatives, there are tons of special purpose applications that can leverage a device in this category. And the rate of development of iPhone applications to date certainly makes this seem reasonable.

Personally, I think the non-3G versions are great alternatives, as I don't envision myself using a device like this out of Wi-Fi range. So the base model is actually very appealing, and at $499 is still somewhat reasonable. That said, I'm not going to run out and buy one on day one. But I can see the second version as a great replacement for my Kindle.

No Flash on the iPad is the Right Choice for Apple

Posted in Eric Daugherty on January 29th, 2010 by admin
Apple finally announced the Jesus Tablet iPad, launching what they believe to be a new device category. It remains to be seen whether they are correct (although I have my guesses), but the launch of the iPad has rekindled an existing fight between Apple and Adobe.

Apple refused to implement (or allow others to implement) Flash on the iPhone. John Gruber has written about this topic extensively over the past two years. He correctly (though not surprisingly) predicted that the iPad would not support Flash. I say not surprisingly, because all the reasons they had for not supporting Flash on the iPhone still exist for the iPad. OK, one reason: CONTROL. I won't rehash John's arguments, but the summary is, Apple wants to control the experience (and commerce) on the iPhone (iTouch, iPad, etc.), and Flash bypasses that control.

As a newer Apple 'fanboy' (I apprecited Gruber's take: 'There’s a whole class of recent switchers who define “Apple fanboy” as “anyone who’s been an enthusiastic Mac user since before I switched to the Mac”.'), I long avoided Apple because of their demand for control. But after dipping my toe in with iTunes and an Airport Express, I finally gave in and switched to a MacBook Pro and iPhone 3GS (and love them).

I've seen two very different points of view in the past 24 hours regarding Flash on the iPad. When my wife and I were talking about the iPad, I suggested that it could be an alternative to her 13" MacBook, as it does nearly everything she needs. She quickly pointed out that without Flash, it was unappealing to her. (The keyboard is also an issue, but that's a topic for another post).

The second point of view was a post on the Adobe blog by Adrian Ludwig. He pointed out the iPad's lack of Flash, some of the sites that will be unavailable to the iPad users, and that "50 of our partners in the Open Screen Project are working to enable developers and content publishers to deliver to any device". I thought it was a pretty good post from Adobe, pointing out their frustration in a reasonably neutral tone (given their obvious interests). I was a bit surprised by the comments. I didn't do a full tally, but I'd say 90% of the comments were anti-Flash. They complained about the state of Flash on the Mac, and already run Flash blockers on their desktop.

So I see two camps, the general users, who just want the websites to work, and the super users (blog readers) who have a negative perception of Flash and just want it to die. As someone who has built Flash applications, and enjoyed the process and results, I have a biased viewpoint. However, I also have the debug version of the Flash Player installed, so I see first hand how many uncaught exceptions there are in nearly every Flash application I see. There are tons of poorly written Flash applications deployed on the web.

In the end, Apple made the right choice for Apple. I have yet to see a major group of users who are likely iPad buyers in the next 12 months that are upset by the exclusion of Flash. The broader population who may eventually adopt the devices are simply not likely buyers in the short term anyway.

Apple is in a race against Flash. They are gaining huge marketshare in the mobile space, and pushing HTML 5 and the iPhone SDK as the chosen mobile development platforms. As the marketshare continues to grow, the 'Flash Only' sites will be forced to provide mobile or iPhone optimized versions to gain access to growing mobile user base.

We've seen this before. There was a point when web developers optimized their sites for IE 6 exclusively. Now there are websites that actively reject IE6 users, and focus their primary support on Firefox, Safari, and Chrome. This shift occurred because the users demanded it. They were fed up with IE and switched to alternative browsers, and the websites had to adjust or lose the traffic. Apple is attempting to do the same thing with Flash. If they can successfully build a mobile audience without Flash support, websites must respond.

I think HTML 5 and rich applications via plugins (Java FX, Silverlight, Flex) both have their place. Consumer facing high traffic sites should be HTML. The accessibility and SEO trade-offs are simply to great to justify using a plug-in RIA. For applications, whether they are corporate applications, games, or utilities, Flex, Java FX and Silverlight are great alternatives. They provide the benefits of the web deployment model with the power and speed of development of traditional languages.

Looking forward, high level rich languages (Java FX, Silverlight, and Flex) will merge with the increasing functionality of the underlying platform (JavaScript and HTML 5) to create high level languages that 'compile to the browser'. Google's GWT is a first generation example of this, but I believe there is much more to come. Eventually the debate over plug-in architectures will become moot.

The only question is, will it happen fast enough for Apple to avoid a user backlash?

Update: Gruber and Scoble appear to be making the same analogy to the changes Firefox forced on web developers.

Android App Store: The Cure Is Worse Than The Disease

Posted in Dave Rodenbaugh on January 28th, 2010 by admin

So you’re a mobile developer and you want to start building apps for the glory, the fame, and the cold, hard cash.  You’re probably looking at the iPhone vs. Android war unless you were just recently thawed out from cryogenic storage, in which case I welcome you to the 21st century.

As a mobile development platform, the iPhone might as well rename itself to “Lightning Rod for Criticism.”  The critiques are not undeserved–largely due to its App Store, but the platform itself has a fair number of things to gripe about too.  Google “iPhone App Development Sucks” and you’ll find lots of complaints usually distilled down to:

  1. Getting approved requires intervention by the Pope or some higher deity.  Rejections are potentially random.
  2. Approval times are so long, users get mad because bug fixes take a long time to migrate into the ecosystem.
  3. The vast majority of apps in the store are ignored because they are swimming in a sea of competition.
  4. Apple is just plain mean and kicked my dog for amusement.

Maybe not the fourth one as much as the first three, but they’re all around in various proportions.  They usually result in the following solutions:

  • Apple should change the app approval process.
  • Apple should remove its stranglehold on the iPhone app store.
  • Developers should get the new <insert Android-based phone here> because Android’s platform has:
    1. No problematic approval process
    2. Greater opportunity
    3. Lower competition
    4. The hot new market
    5. Better development environment

My question to the mobile development community is the grass really greener on the Android side of the fence? Let’s take a hard look:

The Android Marketplace

I have a few friends with the Droid/Android phone sets and they love to brag about just how cool they are compared to the iPhone.  I’ve seen the handset and played with it for a bit.  It’s nice enough for sure.  But when I ask them about the Android App Store, instead of telling me about Android, they rail on how broken the Apple App store is.  That missed the point.  I wanted to know how theirs works.  So finally, I checked it out for myself…

There are no less than SEVEN different stores (that I can find to date, Jan ‘10), either already available or in the works, including:

This is progress?  Now instead of contending with ONE process, ONE registration fee, and potentially, ONE set of handset, I’m faced with a nightmare combinatorial problem of up to seven places to deal with as a developer (with seven fees, seven policies, seven places to potentially get rejected if they dislike something, etc), and SEVEN places to shop as a consumer.  As a developer (especially a micro ISV), my resources were already strapped but now they’re positively spread razor thin in this model.

Oh, but wait!  I want to stick with the MAIN store, because they clearly won’t all win, right?  You might guess that Google’s will win, but are you really 100% sure about that?  What if the Google Phone continues to have lackluster sales like it did in the first week?

Flurry Stats for First Week Sales

Not looking good there for Google, is it?  Yeah, so you’re going to hedge your bets, submit to multiple stores and reach for some aspirin.  So #1 on our list isn’t looking great.

Android Opportunity

The number one reason most (but not all) developers create mobile apps is to get some economic benefit.  How does Android stack up in terms of economic potential?

Apple and Android stores couldn’t be more different in size:   Apple’s app store is estimated to make $2.4  Billion dollars per year (source:  AdMob).  For some perspective, that’s about the 2008 GDP of Somalia and about 2x the 2008 GDP of the Maldives.  Official Android figures have yet to come out, but AdMob has estimated their size at about $60 Million dollars per year, as of about 6 months ago.  For the mathematically challenged, that makes Android’s Marketplace about 2% of the size of Apple’s iTunes economy, or Apple’s iTunes economy is about 40x larger than Android’s.

And as if that weren’t depressing enough, the Android Market’s purchase rate is less than half that of the iTunes App Store (19% of Android users bought apps vs. 50% of Apple users).  There’s some speculation that Android users have a higher ability to pirate purchased apps, and this is impacting the actual purchase rates.  Either way, the fact that the Android user base is less likely to buy apps coupled with the size difference makes the economic benefit of the platform shaky at best.

That makes #2 as a reason to switch somewhat naive.

App Store Competition

Is the market situation better with Android’s Marketplace because of lower competition?  Here’s one developer’s experience with Android vs. iPhone markets. My favorite is their quote:

A good example is the well known game Trism, which sold over $250,000 in it’s first two months on the iPhone. On Android it has sold, to date (August 2009), less than 500 copies. That’s $1,046 total earnings, max. How psyched are those guys that they ported a huge hit to Android and can’t even cover a party sub for the release dinner?

Ouch.  And if a well known title is struggling like that, what does that say about the lesser known apps?

Internal competition is a good thing–competition means that everyone thinks this platform is interesting.  Android doesn’t seem to have critical mass here.  Unfortunately, Android has external competition, but not in a good way.  If you want to get the best deal on apps, you actually need to shop and price-compare apps between stores–how’s that for a great experience?

We noticed that the MobiHand store features some apps that were also found on Handango’s site, like the GoogHelper app and the FotMob app, for example. However, on OnlyAndroid, GoogHelper was $3.95 whereas Handango sold it for $4.95. FotMob, on the other hand, was free on Handango but was $7.99 on OnlyAndroid.

I think we can scratch #3 as a good reason.

Android Market:  Hot or Not?

Android has the buzz, but Android’s market share just doesn’t touch Apple’s, either in terms of payout or number of handsets available.  Here are figures from Quantcast for Oct/Nov in 2009 comparison charts (This is the most recent data available for this post, I’d love to see how Dec changed this, if at all, with the release of the Motorola Droid).

October 2009, Ad Mob OS breakdown

October 2009, Ad Mob OS breakdown

Nov 2009, Ad Mob OS breakdown

Nov 2009, Ad Mob OS breakdown

Notice two things:

  1. Android’s jump in market share was at the expense of RIM, Windows Mobile and other non-Apple OSes.
  2. Apple’s market share remained untouched.

So why does Apple maintain such a captive audience?  They understand that a mobile device should be

  1. Beautiful.
  2. Useful.
  3. Usable.

The iPhone is the first mobile device to accurately capture that trifecta of characteristics.  A positive user experience will trump “open platforms” and all that other developer-centric nonsense that we like to spout.  Android merely copied most of what the iPhone had already innovated, but without adding much to its predecessor’s heritage.  As an iPhone user, my motive to switch platforms is low.  Android’s market share will stagnate soon for that reason alone.

What about the Android Marketplace vs. iTunes?  iTunes is a case study in user friendliness.  The Android Marketplace is functional but a real pain to navigate.  Try this fun experiment:  Browse the Top Paid Apps in the Android Marketplace.  You have to hover over each app to find out what it does and each page contains 8 apps.  You can’t see how much an app costs until you visit the developer’s own site.  Apple, by contrast, puts some minimal info on each app including publisher and price for each app and I can see up to 100 at a time.

Developers, Developers, Developers!

The Android’s development platform is a clear win for software nerds.  Developing an Android app means using Java, a well-known, well-documented language with loads of great tools and relative ease of uploading them to the device.  Apple’s XCode is a piece of crap, even on a good day.  Provisioning your iPhone app is a small nightmare that even the most seasoned of developers will struggle with.

Finally, a point for Android!  But unfortunately, developer friendliness is the least important aspect of the platform.  Not just Android, any platform.

Steve Jobs Is Still Pwning Android

Android vs iPhoneLet’s recap thus far:  With Apple, you have a painful setup process, a lousy development environment , a costly annual fee, and a single app store that if you’re part of the Blessed, you can make some fat cash, hand over fist.

With Android, you have seven potential stores to deal with, a reasonable development environment, a lot of uncertainty about the market, and no economic incentive to make apps because the payout isn’t working out like Apple’s app store.

I wouldn’t call that much of an incentive to go with anything but Apple, even with all the negatives in Apple’s basket.

The iPhone scratched an itch no one knew they had and the Apple App Store took off into the stratosphere, inspired by a paranoid and sometimes irrational father figure culture.  And it’s still kicking the crap out of everything else.  Android’s game of catch-up is turning into a potential nightmare for customers and developers alike.

My advice is to buy a black turtleneck, some khakis and buck up with your iPhone development.  Cocoa may be a pain and Objective-C far less fun than Java, but Android’s cure is worse than the disease.

UPDATE:  Six weeks later, the Nexus One launch is declared a flop.  Sales are 10% of either Droid or iPhone during the same 74 day period of their launch cycle.  Not exactly the iPhone killer Google was hoping for.

Related posts:

  1. Google’s Go Isn’t Getting Us Anywhere, Part 1
  2. Google’s Go Isn’t Getting Us Anywhere, Part 2

A Better HTML Template for Flex 4

Posted in Justin Shacklette on January 25th, 2010 by admin

Adobe took a big step forward using swfobject.js to handle swf embedding in Flex 4’s index.template.html, but in my opinion they didn’t go quite far enough.

Here are my changes:

  1. Short and sweet, so I can understand what the hell is going on.
  2. Use Google AJAX Libraries API to include swfobject.js.
  3. No IE6 crap.
  4. No Browser History crap.

Here’s my current version:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>${application}</title>
 
<style type="text/css" media="screen">
html, body, #flashcontent { height:${height}; }
body { margin:0; padding:0; overflow:hidden; }
</style>
 
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
<script type="text/javascript">
swfobject.embedSWF(
    '${swf}.swf',
    'flashcontent',
    '${width}', '${height}',
    '${version_major}.${version_minor}.${version_revision}',
    '${expressInstallSwf}',
    false,
    { 'bgColor':'${bgcolor}' });
</script>
</head>
 
<body>
<div id="flashcontent">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
</body>
</html>
Flashvars

Using flashvars is easy with SWFObject (see the embedSWF() method in the docs), just put them in as a Javascript hash like this:

<script type="text/javascript">
swfobject.embedSWF(
    '${swf}.swf',
    'flashcontent',
    '${width}', '${height}',
    '${version_major}.${version_minor}.${version_revision}',
    '${expressInstallSwf}',
    { key1:'val1', key2:'val2', key3:'val3' },
    { 'bgColor':'${bgcolor}' });
</script>
View Source

Lastly, here’s a little trick that I use to embed flash into a post on this blog (or anywhere else) that enables view source to work with a relative url, so I can leave the viewSourceURL attribute alone (defaults to viewSourceURL="srcview/index.html").

<script type="text/javascript">
swfobject.embedSWF(
    '${swf}.swf',
    'flashcontent',
    '${width}', '${height}',
    '${version_major}.${version_minor}.${version_revision}',
    '${expressInstallSwf}',
    false,
    { 'bgColor':'${bgcolor}', base:'.' });
</script>

Adding the base parameter, and setting it to '.', tells the embedded SWF to lookup urls relative to itself. The net effect is that view source just works.

Files

The Complete Software Developer

Posted in Eric Daugherty on January 25th, 2010 by admin
The Software Development profession is still a relatively immature profession. There are few real certifications and no real licensing processes that provide any realistic guide to an individual's competency. The landscape evolves quickly and covers a very broad spectrum of skills. These reasons make it difficult to map out a career path that will lead to the development of a complete Software Developer. In this article, I intend to lay out what I feel is a solid career outline for a Software Developer, and why each step is important.

It is important to note that this is not the path to be a competent developer, but to be an outstanding developer. The tools and resources available today make it possible for someone to achieve reasonable levels of successes with minimal levels of skill and education. Instead, this is a roadmap to become what I consider to be a complete developer. This includes more than just pure technical skills, but someone who can work with others to solve problems.

Education

A favorite movie quote of mine is from 'Die Hard':
"'And when Alexander saw the breadth of his domain, he wept, for there were no more worlds to conquer.' Benefits of a classical education." - Hans Gruber
While a Computer Science or Computer Engineering degree is not required to develop software, it can provide an understanding of the foundational elements on which everything else is built. Understanding both how a computer actually works, and the fundamentals of algorithms, data structures, and operating system design will provide a solid theoretical foundation for an entire career. I also believe it is important that the degree focuses on theory more than practice. A Computer Science degree that spends time teaching how to use Visual Studio or Eclipse may produce students who can be more effective in year 1, but does them a disservice in years 2-n.

The only other degree I've seen with some regularity provide individuals with a solid understanding is Physics. Even so, they have had to learn the fundamentals along the way. I guess with the Physics background, they probably understand everything at a much deeper level anyway.

Consulting

I believe that every new college graduate's first job should be with a consulting company. Not just any consulting company, but one large enough and experienced enough that it provides real training on how to be a Consultant, in addition to how to develop software. Consulting is a skill, and it is one that will pay dividends through an entire career.

Working at a consulting company will expose new Software Developers to a variety of technologies, business domains, and cultures. Ideally, the consulting company works in a variety of technologies and new consultants get an opportunity to work on projects across multiple languages/technologies/platforms.

Travel is not a requirement, but can provide some added benefits. From the simple worldly benefits of seeing different parts of the country, to business dinners with clients, where new developers can gain a real insight into how business gets done. You may also get to eat some great meals along the way as well.

Consulting also helps new developers learn to market themselves. Since consulting companies really sell the competency of their staff, and their 'unique process', developers will learn how to position their skills and experiences to demonstrate competence and credibility. After consulting for a while, every future job interviews will be much less stressful.

Ideally, spend 2-3 years broken up into six month projects across at least two different platforms (Java, .Net, etc.), and with at least one project in a different city.

This experience will do several things. First, it will teach new developers how to be a consultant. This includes everything from dressing professionally, to presenting ideas and concepts to non-technical customers, to understanding the business of selling services. Second, it provides a broad experience base while new developers are still young and impressionable. There are many different technologies and platforms out there, all taking different paths to solve problems. Seeing this diversity early insures that new developers do not become assimilated into the group think of a single platform or pattern. It is hard to work in different platforms like .Net and Ruby on Rails without developing a knowledge about how the underlying technologies work. Finally, new developers will also see the rich diversity of business and cultures across companies. It is an opportunity to learn the trade-offs of different business models and cultures, and how they impact the ability for software development teams to be effective.

Support

After spending some time in Consulting, it is time to move into a role where you can own and support a product. This can either be within an internal IT department, or for a Software as a Service company. A packaged software vendor provides many of these benefits but I believe that a critical part of this experience is 'carrying the pager', which packaged software usually avoids.

The key learning here is to own and support a system across several major releases. Building version 1.0 of an application as a consultant is very different from enhancing and maintaining an application across several minor and major releases. Being responsible (indirectly, if not directly) for the support and success of a production application is a critical learning experience.

Ownership is an important concept. This experience provides the ability for a new developer to really work on something over a long period and 'own' it. A developer can see the payoff of a bit of foresight or extra effort they put in 12 months ago. They can also feel the pain of taking shortcuts that were ill-advised. They can learn how those trade-offs work and begin to get a sense of when they are worthwhile.

In the end, working in IT or Engineering provides a different set of goals and drivers for Software Developers than Consulting can provide. These different goals force new developers to see software development through a different lens.

Performance and Scaling

The opportunities within most consulting and traditional IT/Engineering roles to really focus on high performance code and application scaling are limited. Within consulting, it is often a non-factor, as performance and scaling issues often do not appear until long after the initial deployment. Within IT/Engineering roles, there is often an opportunity to address issues, but only within the context of a single application and infrastructure.

Therefore, the next stop on the career path is Professional Services or other specialized consulting. Professional Service organizations often focus on providing extremely skilled resources for short periods to address critical issues. These can often focus on performance or scaling issues, and provide a great opportunity to gain exposure to a broad set of problems, architectures, technologies, and infrastructures. To be successful in this role, an individual needs both a deep understanding of the product they are supporting but also an understanding of how it fits into the greater ecosystem.

In a Professional Service or specialized consulting role, individuals often interact with very senior members of the customer's staff, allowing developers to gain experience and exposure to a individuals they may not traditionally interact with.

This type of experience provides an opportunity to solve a large number of very intense problems over a relatively short period of time. This provides a breadth of knowledge about how the different types of major systems in production, and the problems that they face. It also allows developers to build an impressive network of contacts across a broad range of companies.

What's Missing?

As a career outline, I believe this is a great start, but it is probably incomplete. There are many other valuable experiences that an aspiring Software Developer should experience. Some of these can be done in parallel with the above outline, others may be additional steps.
  • Build a product - Whether it is an Open Source application, shareware, or a commercial application, build something from scratch that other people will use. Interact with your user base and understand the challenges that product managers face.
  • Manage a team - Lead a team. Learn the interpersonal skills necessary to manage a team, and learn the leadership skills and qualities necessary to rally a disparate group of individuals into a team.
  • Work for a startup - As a side project or part of your career path, understand how a small company can often achieve more than a much larger firm.
  • Work for a Fortune 500 Company - In a consulting role or as an employee, understand how the right decision for an organization isn't always the right decision for an individual team or group, and the political and interpersonal issues that this can create.
  • Learn - Learn a new language every year, at least. Learn a new framework, pattern or approach ever quarter, at least. Understand how things work on the other side of the fence, you'll be amazed at how it can change your perspective.
  • Mentor - Learn to help others grow. If you can't teach someone else how to do it, you probably don't understand it well yourself.
  • Build your Network - It is a small world. You will run into folks again and again. The impression you make on them as a junior developer may be important a decade later.
  • Maintain your Network - Keep in touch with as many people as you can. Reach out to them and help them as much as possible. It will pay off.
Go Forth and Create

Now, focus on your passion. You have the background necessary to learn any new technology, solve any problem, and effectively communicate with others. It is time to focus on what you are passionate about, and become a leader in your chosen field.

Using the FoneMonkey Console

Posted in Stu Stern on January 24th, 2010 by admin
Creating and Editing Scripts with the FoneMonkey Console

When you launch an application that has been linked with FoneMonkey (see Setup Guide), the FoneMonkey Console is displayed on top of the application’s window.



To begin recording, touch the Record button. The FoneMonkey console will hide and you can manually test your application. As you interact with it, FoneMonkey records FoneMonkey commands corresponding to each user interface gesture.

If you stop interacting with the application for longer than the timeout interval (by default, 2.5 seconds), the FoneMonkey console will reappear on top of your application window.
If you are not yet done recording, click any where over the application to hide the FoneMonkey console and resume recording.

Touching the Pause button hides the FoneMonkey window and lets you interact with your application without recording. The console will reappear after the timeout interval. Touch anywhere on your application to re-hide the console and continue without recording.
Touch the More button to view the list of recorded commands.



Commands are displayed in the Command List table. The Timeout slider can be used to set the timeout interval anywhere from 2 to 10 seconds. If the console is reappearing more quickly than you want it to while the console is recording or paused, make the timeout longer.

Touch the Play button to begin playback. The console hides and FoneMonkey executes each command in sequence, generating user interface actions corresponding to each command.
By default, FoneMonkey pauses .5 seconds between commands. Sometimes you may need FoneMonkey to wait additional time at certain points in a script. For example, a command might need to wait until an animation finishes running. Use Pause commands (see command reference) to insert pauses between commands during playback.

Editing Recorded Commands

To edit a recorded command, touch the Edit button on the row in the command list to be edited. The Command Editor will be displayed.



Using the command editor, you can change the Command, Component Class, Monkey ID, or any of the associated parameters. When you’re finished editing, touch the Done button.

Inserting and Deleting Commands

Commands can be inserted and deleted using the Insert and Delete toolbar buttons, which display the Insert or Delete buttons in each row of the displayed script.
Saving a Script

To save a script, touch the Save Script button. The Save Script dialog will be displayed.

Enter a name for the script and hit the Save button. Scripts are saved in the application's Documents directory.

Running a Saved Script

To run a saved script, touch the Open Script button. The Saved Script List will open displaying all saved scripts.


To open a script, touch its name in the list. The script will open in the console and can be played and edited.

Recording a New Script

To clear the currently opened script and begin creating a new one, click the Open Script button and then touch the New button displayed above the Saved Script List.

Deleting a Saved Script

To delete a saved script, touch the Open Script button and then click the Edit button displayed above the Saved Script List. You may then delete a saved script by touching the associated Delete Icon.

Working with FoneMonkey Command Scripts

Posted in Stu Stern on January 22nd, 2010 by admin
FoneMonkey plays FoneMonkey commands. For each kind of user interface action there is a corresponding command. Some examples of commands are Touch, Scroll, and Shake. (See the FoneMonkey Command Reference for a complete list).

User interface actions are directed to components. For example, you Touch a UIButton, or Scroll a UITableView to Row 5. FlexMonkey commands identify the action to be performed, and the component to receive the action. Components are identified by a combination of their Object-C class name (or superclass name) and a string identifier called a monkeyID.

All commands are written as:

CommandName ComponentType "MonkeyID" Parameters, ...

where

CommandName identifies the command to be executed.
ComponentType is the Objective-C class name of the component to receive the command. If componentType is omitted, it defaults to UIView (ie, any component).
"MonkeyID" is a quoted string that uniquely identifies which instance of the component's class should receive the command. If there is only one instance of a particular type, monkeyID may be omitted.
Parameters, .... are zero or more command-specific parameter values in CSV format.

By overriding recording and playback methods, it's easy to add your own commands to FoneMonkey or customize existing commands. See the FoneMonkey Extension Guide for more information.

Some Command Examples

Touch the "Done" button:

Touch UIButton "Done"

Touch the PaintingView at coordinate (25, 75):

Touch PaintingView 25, 75

Enter text into the "FirstName" field:

InputText UITextField "FirstName" fred

Identifying Components by ClassName and MonkeyID

As mentioned above, commands correspond to user interface actions, and actions are directed to components. For example, a command might specify to Touch a UIButton. If there is only one UIButton on the screen, FoneMonkey knows which button the command is referring to. If there are multiple buttons, however, we must tell FoneMonkey which one to use. In addition to the component's Objective-C classname, and a unique identifier called a monkeyID that's generated by FoneMonkey extensions for various UIKit classes. For any command, you can specify just a className or a monkeyID, or you can specify both.

Component Identification Examples

If there are multiple buttons on the screen:

Touch UIButton "Done"

If there is just one button on the screen:

Touch UIButton

If threre is just one button on the screen with a monkeyID of "Done":

Understanding MonkeyID's

FoneMonkey's UIView extensions provide the default monkeyID for all components. By default, the monkeyID of a component is the value of its accessbilityLabel property, if one exists, its tag property if it's non-zero, and otherwise FoneMonkey generates a unique identifier as explained below. Many component types provide specialized monkeyID's. For example, UIButton returns its titleLabel.text as its monkeyID, UITextField returns its placeholder value.

See the FoneMonkey Command Reference for a description of the monkeyID's returned by each component type.

If a component provides no monkeyID, FoneMoney generates an identifier by assigning an ordinal to each instance of each class on the screen FoneMonkey generated monkeyID's are prefix with a #-sign.

Examples of Generated MonkeyID's

Touch the first button:

Touch UIButton #0


Touch the second button:

Touch UIButton #1

Validating Tests with the Verify Command

You insert Verify
commands into your script to validate during playback that actual results match expected ones. The Verify command has the following syntax:

Verify ClassName "monkeyID" propertyPath, expectedValue

As with all FoneMonkey commands, you can specify either ClassName or monkeyID or both to identify the component.

propertyPath is any valid key path to a property.
expectedValue is the expected value of the property identified by the propertyPath.

Verify Command Examples

Check that the last name label is "Smith"

Verify UILable "Last Name" text, Smith

Check that the button says "Hello"

Verify UIButton titleLabel.text, Hello

If a verify command fails, a message is displayed in the FoneMonkey Command List.

Inserting Pauses into a Script

By default, FoneMonkey pauses .5 seconds between commands during playback. Sometimes you may need a longer delay between commands, for example if an animation needs to finish running before a component is displayed.

You can insert pause commands to allow additional time between the execution of commands. It has the following syntax:

Pause milliseconds

where milliseconds is the number of milliseconds to pause before executing the next command.

The Pause command ignores class name and monkey ID, if any are supplied.

Pause Example

Pause for 1 second:

Pause 1000











Working with FoneMonkey Command Scripts

Posted in Stu Stern on January 22nd, 2010 by admin
FoneMonkey plays FoneMonkey commands. For each kind of user interface action there is a corresponding command. Some examples of commands are Touch, Scroll, and Shake. (See the FoneMonkey Command Reference for a complete list).

User interface actions are directed to components. For example, you Touch a UIButton, or Scroll a UITableView to Row 5. FlexMonkey commands identify the action to be performed, and the component to receive the action. Components are identified by a combination of their Object-C class name (or superclass name) and a string identifier called a monkeyID.

All commands are written as:

CommandName ComponentType "MonkeyID" Parameters, ...

where

CommandName identifies the command to be executed.
ComponentType is the Objective-C class name of the component to receive the command. If componentType is omitted, it defaults to UIView (ie, any component).
"MonkeyID" is a quoted string that uniquely identifies which instance of the component's class should receive the command. If there is only one instance of a particular type, monkeyID may be omitted.
Parameters, .... are zero or more command-specific parameter values in CSV format.

By overriding recording and playback methods, it's easy to add your own commands to FoneMonkey or customize existing commands. See the FoneMonkey Extension Guide for more information.

Some Command Examples

Touch the "Done" button:

Touch UIButton "Done"

Touch the PaintingView at coordinate (25, 75):

Touch PaintingView 25, 75

Enter text into the "FirstName" field:

InputText UITextField "FirstName" fred

Identifying Components by ClassName and MonkeyID

As mentioned above, commands correspond to user interface actions, and actions are directed to components. For example, a command might specify to Touch a UIButton. If there is only one UIButton on the screen, FoneMonkey knows which button the command is referring to. If there are multiple buttons, however, we must tell FoneMonkey which one to use. In addition to the component's Objective-C classname, and a unique identifier called a monkeyID that's generated by FoneMonkey extensions for various UIKit classes. For any command, you can specify just a className or a monkeyID, or you can specify both.

Component Identification Examples

If there are multiple buttons on the screen:

Touch UIButton "Done"

If there is just one button on the screen:

Touch UIButton

If threre is just one button on the screen with a monkeyID of "Done":

Understanding MonkeyID's

FoneMonkey's UIView extensions provide the default monkeyID for all components. By default, the monkeyID of a component is the value of its accessbilityLabel property, if one exists, its tag property if it's non-zero, and otherwise FoneMonkey generates a unique identifier as explained below. Many component types provide specialized monkeyID's. For example, UIButton returns its titleLabel.text as its monkeyID, UITextField returns its placeholder value.

See the FoneMonkey Command Reference for a description of the monkeyID's returned by each component type.

If a component provides no monkeyID, FoneMoney generates an identifier by assigning an ordinal to each instance of each class on the screen FoneMonkey generated monkeyID's are prefix with a #-sign.

Examples of Generated MonkeyID's

Touch the first button:

Touch UIButton #0


Touch the second button:

Touch UIButton #1

Validating Tests with the Verify Command

You insert Verify
commands into your script to validate during playback that actual results match expected ones. The Verify command has the following syntax:

Verify ClassName "monkeyID" propertyPath, expectedValue

As with all FoneMonkey commands, you can specify either ClassName or monkeyID or both to identify the component.

propertyPath is any valid key path to a property.
expectedValue is the expected value of the property identified by the propertyPath.

Verify Command Examples

Check that the last name label is "Smith"

Verify UILable "Last Name" text, Smith

Check that the button says "Hello"

Verify UIButton titleLabel.text, Hello

If a verify command fails, a message is displayed in the FoneMonkey Command List.

Inserting Pauses into a Script

By default, FoneMonkey pauses .5 seconds between commands during playback. Sometimes you may need a longer delay between commands, for example if an animation needs to finish running before a component is displayed.

You can insert pause commands to allow additional time between the execution of commands. It has the following syntax:

Pause milliseconds

where milliseconds is the number of milliseconds to pause before executing the next command.

The Pause command ignores class name and monkey ID, if any are supplied.

Pause Example

Pause for 1 second:

Pause 1000











Getting Started with GraniteDS, Spring, and Maven

Posted in Eric Daugherty on January 22nd, 2010 by admin
This is a quick tutorial to get you up and running using GraniteDS, Spring, and Maven. My initial assumptions are that you already have a Spring project up and running using Spring WebMVC, and you want to add GraniteDS to the project to enable a Flex client. This just covers using GraniteDS for a basic RPC call using AMF. GraniteDS does much more, but this should at least get you started.

First, you need to add the GraniteDS dependencies to your pom. GraniteDS does not appear to be in the default Maven repository, so first you need to add a references to the Java.net Maven Repository:
<repositories>
<repository>
<id>Java.net</id>
<name>Java.net Repository</name>
<url>http://download.java.net/maven/2/</url>
</repository>
</repositories>

Next, you'll need to add the dependencies:
<dependency>
<groupId>org.graniteds</groupId>
<artifactId>granite-core</artifactId>
<version>2.0.0.GA</version>
</dependency>
<dependency>
<groupId>org.graniteds</groupId>
<artifactId>granite-spring</artifactId>
<version>2.0.0.GA</version>
</dependency>

You may also want to add additional GraniteDS artifacts, such as granite-hibernate, etc. You can see the entire list here.

You will need two additional configuration files, services-config.xml and granite-config.xml. The services-config.xml should be familiar to anyone who has used BlazeDS before.

WEB-INF/flex/services-config.xml - This file contains the core of the mapping config. The first block specifies the destination, including the beanName of the backing Spring Bean. You will need to replace [beanName] with the name of the Spring Bean you are exposing. You can tweak the URL and destination names, but otherwise this should be good for your simple RPC call as is.
<?xml version="1.0" encoding="UTF-8"?>

<services-config>

<services>
<service
id="granite-service"
class="flex.messaging.services.RemotingService"
messageTypes="flex.messaging.messages.RemotingMessage">
<destination id="test">
<channels>
<channel ref="my-graniteamf"/>
</channels>
<properties>
<factory>springFactory</factory>
<source>[beanName]</source>
</properties>
</destination>
</service>
</services>

<factories>
<factory id="springFactory"
class="org.granite.spring.SpringServiceFactory"/>
</factories>

<channels>
<channel-definition id="my-graniteamf" class="mx.messaging.channels.AMFChannel">
<endpoint
uri="http://{server.name}:{server.port}/{context.root}/graniteamf/amf"
class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>
</channels>

</services-config>

Note: If you are using AutoWiring in Spring, the beanName will just be the unqualified class name. So the class com.ericdaugherty.TestService would have a beanName: testService.

WEB-INF/granite/granite-config.xml - In this simple example, there is no configuration of real value in this file yet. As you delve deeper into GraniteDS's features, you can add configuration here.
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE granite-config PUBLIC
"-//Granite Data Services//DTD granite-config internal//EN"
"http://www.graniteds.org/public/dtd/1.2.0/granite-config.dtd">

<granite-config scan="true">
</granite-config>

You will need to add some additional configuration to your web.xml. In addition to your SpringMVCServlet configuration, you will need the GraniteDS Filter and Servlet:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/config/web-application-config.xml
</param-value>
</context-param>

<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>

<filter>
<filter-name>AMFMessageFilter</filter-name>
<filter-class>
org.granite.messaging.webapp.AMFMessageFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>AMFMessageFilter</filter-name>
<url-pattern>/graniteamf/*</url-pattern>
</filter-mapping>

<servlet>
<servlet-name>AMFMessageServlet</servlet-name>
<servlet-class>
org.granite.messaging.webapp.AMFMessageServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>AMFMessageServlet</servlet-name>
<url-pattern>/graniteamf/*</url-pattern>
</servlet-mapping>

I had to add the ContextLoadListener and specify the location of my web-application-config.xml file for GraniteDS to work, even though I didn't need it for Spring.

Note: if your SpringMVCServlet is mapped to your root (/), make sure the AMFMessageServlet mapping is first in your XML file.

Now, you simply need to create a Flex project and use RemoteObject to call your service. In Flash Builder 4, I was able to set it up as a BlazeDS project, point it at the src/main/webapp directory in my Maven tree, and it was able to auto-configure RemoteObject.

That's it. This is a very simple version of what you can do with GraniteDS, but it should be enough to get you started.

FoneMonkey: New Fat Library

Posted in Stu Stern on January 21st, 2010 by admin
Thanks to some helpful advice from Victor Costan about building fat libraries, the latest FoneMonkey library can be used to build applications for both the iPhone device and simulator. The fat library contains code for both arm7 (iPhone) and i386 (simulator) architectures, so you can reference the same library binary from either your simulator of device builds. Note that the linker will strip out unreferenced code so the convenience of the single library does not come at the expensive of a bloated application binary.

The download is available here.