In creating the mobile application for the Chicago DrupalCon, our team learned quite a few things about iOS/Android Drupal-based mobile app development. This article will distill a couple of hundred hours of our work into a few lessons you can use on your next Drupal-based mobile application.
Assemble a Good Team
One thing we realized early on was that if we wanted this project to be a success we were going to need to treat it like a proper project. Proper meant actually bringing on a UX person to make sure the app made sense. It also meant that it should have a backend engineer and a front end developer.
Our engineer for the backend was Larry Garfield (known as Crell in the Drupal world), our UX person was Jen Simmons, and I brought up the front-end development side of things.
Outline Your Requirements
After determining our resources, we outlined our requirements and their importance. We found it helpful to break this down into three categories; must do, important but not critical, and nice to have.
For our project, the list of application requirements went like this:
- It needed to be used by a large number of people at the same time and in a potentially unstable wi-fi environment.
- It needed to be accessible on both iPhones and Android phones, including Android 1.6.
- It needed to come pre-packaged with its own data so that it could be used offline, and it needed the offline storage to be robust enough to handle Drupal-ish data.
- It needed to be a native app to leverage the extensive resources Apple and Google had spent on improving the UI's for their own platforms.
- It needed to be quick, intuitive, and highly useful.
- It needed to communicate session info, presenter info, up-to-the-minute news, venue info, and allow feedback about sessions.
- It needed to be usable for future DrupalCons.
- It needed to be awesome.
It is a good idea at this point to also ball-park how many hours each requirement might take to develop. For us this was important in order to get some budget for the development process, as well as to determine what we would be able to accomplish in the limited development time we had. It may come as no surprise that this being our first mobile app, we were somewhat off in our time estimates.
Develop the UX First and Always
Start the development on the user experience side of things. In our project, Jen produced wireframes and mockups that were indispensable to us in making many down-the-road decisions during engineering and development.
Though the UX work is very important, keep in mind that it should remain elastic. The goal is an app that is similar to, but better than, the original wireframes. Also, the wireframes will often include the nice-to-have items from your requirements, and you will not always get those in, so the app may not end up exactly as expected. Be flexible!
Throughout the development, keep your UX person in the loop. In our project, Jen was there to help revise the graphical elements and advise us on how to revise the interface when certain things had to be left out, or when we discovered that we hadn't thought of everything in the beginning. (What happens when you realize you didn't include session tracks in the listings? Exactly!)
The Requirements Determine the Development Platform
Looking at your list of requirements should make it very clear what development platform you are going to use. If you are developing for iOS only—or if you need to include BlackBerry—you certainly might go native or use the excellent PhoneGap platform; if your development framework of choice is Ruby on Rails, you may choose Rhodes.
Get the Data
While the UX is being figured out, you should be able to extract from your list of requirements what data your app is going to need, and start providing the means to access it. In our app, we needed session data, presenter data, venue information, general information, and news.
Our session data needed to be complete with information on the track—such as Coder or Drupal Means Business—the room (or rooms) it was being held in, the presenter (or multiple presenters), the time and date, and the intended audience.
Our presenter data was somewhat less complicated. Each presenter had information from their user profile including their name, their Drupal.org username, twitter account, bio, and what sessions they were presenting. It also would have been nice to figure out a way to include their avatar.
There are probably many different ways to get data from a Drupal site, but the two we were most interested in for the DrupalCon app were the Services module and Views with Views DataSource module.
The Services module is a good choice if you need two-way authenticated communication between your Drupal site and your app; we discovered that if you don't need to talk back to the Drupal site from your app, Views DataSource is an easier solution.
Views DataSource may actually be a better solution for many Drupal/Mobile implementations because it allows you to pull out exactly the type of data structure you need, which could include referenced nodes, relationship-driven views, psuedo-nodes, etc. It allowed us to get only what we needed, and gave it to us in JSON, ready for input into our app.
If you do want to use Services in an Appcelerator application, Larry has actually written a good portion of the code needed to make Appcelerator work with Services, all of which is available in the public github repository referenced at the end of this article.
Keep the Data
To use the data accessible from Services or Views DataSource, you will probably want to store it. Appcelerator has a Database API which may suffice if your data needs are fairly simple. Our app required something a bit more robust to handle more-complicated data structures.
Later on, Larry created an update function to allow the app to determine if any data on the DrupalCon site had been updated from XYZ data. If so, it grabbed that data and inserted it into our local db.
With this method, we were able to create the initial database dump that shipped with the app to pre-populate the app with data so that no user would suffer through an interminable data-download experience.
Put it all Together
Once you have your data accessible, and you know what your app is supposed to look like and how it is supposed to flow, you can begin putting it all together.
That was my job; turning all the data Larry was providing into the UX that Jen was conjuring, and making it work on both Android and iPhone. Fun stuff!
In a simple app, you could probably just write your entire logic and presentation into the file called app.js (the JS file required by Titanium) and leave it at that. Hello World would be more than happy to run this way.
Anything more complicated then Hello World would probably require a model more like ours; create prototype driven page templates (which we keep all together in the Resources/windows directory), then populate them using the db helpers created earlier, then render them using Titanium.UI.API calls, producing lists, pages, and graphics for the final page.
This model of development uses quite a few files; basically, a page template for each different page type (session, presenter, news item, etc.). You will probably want to organize your app into an organized directory structure.
We broke ours out into a libraries directory, a directory each for Drupal-ish and DrupalCon-ish functionality, a directory for static pages that could be displayed using HTML/CSS, and a directory for all of the prototype page template files (which we call windows).
When creating a more complicated app, your app.js basically just becomes a bootloader, initializing all the window prototypes so they can be ready when it is time to display one, initializing the libraries, firing up the database connection and moving you on to main.js (which for us was windows/main.js).
In our app, this main.js file creates the tab layout, instantiates our tab touch event listeners, adds the update button, and then, finally, presents the schedule page on the first tab.
From there, almost anything you do follows this pattern: you press on something, it fires a touch event listener that calls up one of the windows that has already had a prototype built, inserts data here and there, and displays it to you.
This method can work for a majority of apps built in Appcelerator.
Understand You Can't Do It All
One thing to keep in mind when you are building out your requirements is to try to develop in a modular fashion. Have encapsulated bits of functionality that you can complete and move on from. This will allow you to be flexible with regards to your deadline. If you have already completed this piece or that, they get in; otherwise, they don't—but the entire project isn't scrapped as a result.
Toward the end of the development process we were freaking out a bit. We had desperately wanted to get two features into the app, namely BOF integration and synchronizing the "my schedule" feature from the site on the app. Unfortunately, there simply was not enough time to do these things well, so we decided to not do them at all.
The application may not be as fully-featured as it would have been with these things, but the app was still awesome because we were thinking modularly, working our way down our requirements list, and getting in the things that had to be in.
All told, we could easily have spent twice as much time developing this app, putting all the features we wanted in it, optimizing, and contributing fixes back to Appcelerator—but we had already spent far more time than we originally expected, so it is probably a good thing we had an immovable deadline.
QA and Distribute
QA of the DrupalCon app was pretty interesting. At the time we didn't know of any way to easily distribute the app for testing on iOS devices, so George DeMet kindly put his iPhone up as a guinea-pig for the iOS developer program.
Subsequently, we discovered that there is a web service called TestFlight that allows you to easily distribute your app for testing. We have not yet used this service, but I heard favorable reviews of it during the mobile BOF at DrupalCon Chicago.
In addition to the iPhone, we had been testing on the Android platform on a G1, a Motorola Cliq, and a Nexus S.
During our QA process, Larry began setting up distribution for the app in the Apple App Store, and the Android Market. You may want to read up on how to do this for the Apple App Store; it is a time-intensive task and one that we found to be very aggravating. The Android Market probably took a total of 30 minutes versus the many hours of correctly releasing the app on the Apple App Store.
We ended up doing 2 releases on the Apple App Store, primarily because we were a bit afraid if we didn't get an app in the store early, we wouldn't get one in on time at all. Luckily most people that I talked with at DrupalCon were using the newest version.
Conclusion: Tips for Drupal/Mobile App Development
Pay attention to the differences
Pay attention to the differences between Android and iOS native UX and plan for those differences. Understand that Android uses menus, iOS does not but it does have Settings; iOS uses buttons on the nav bar, Android doesn't really have a nav bar. The same UX may not work cross-platform, but your underlying logic may.
Emulators are not devices
After we released, one thing became clear from the feedback: Our opening graphic looked squished on many Android devices. This is something that was easily preventable had we tested more thoroughly on actual Android devices, rather than just on the emulator and one or two phones. Testing is cheap on Android as you can pass around an .apk file pretty easily.
In the same vein, something we did right was to cover the bases on iOS devices by including Retina scaled graphics, which ended up being a breeze to implement in Titanium (just include an firstname.lastname@example.org file scaled 2x for each filename.png image you have).
Titanium is still young
Remember that Titanium is still a fairly young project, and don't blow a gasket over every bug or inconsistency you run across. We found some humdingers and, honestly, the Appcelerator folks were pretty awesome about helping us on most of them. Be forewarned: You may have to pay for support to get the level of service you need.
Decide to do it well
I think the best thing we did in this app was to not try and implement every pie-in-the-sky requirement on our list. A couple of times we made the decision that if we couldn't do something really well, we wouldn't do it at all. That is a mindset that is uncomfortable when you are staring at the list of things you want to put in the app, but quality is better than quantity when it comes to development.
Last but not least: Steal this code
We built a lot of things here that are meant to be re-used: services integration, DBTNG-m, prototypes, PLEASE take it and run with it.