Stay.com wins Best Utility App at AppWorks

We’re proud to report that the Stay.com app has won the “Best Utility App” award at AppWorks 2012. AppWorks is the biggest conference for mobile apps and services in Norway.

Photo: Eirik Helland Urke.


Working together with Stay.com and Unfold on the app has been lots of fun, and we’re already working hard on making it even better! High five! ;)

Fly is now Open Source

It’s a known fact that ninjas like open source.

There are many good reasons for releasing your source code into the open, but in the end we do it because it feels right.

The Fly app was originally hacked up over a weekend in late 2010, but has been polished a bit since then (although there are still some rough edges here and there). The Qt version has been published in Ovi Store (both for Symbian and MeeGo) and Google Play (experimental) and we’ve had some pretty good download numbers, for a local app.

Fly on the Nokia E7

That’s not to say that it’s anywhere near perfect. There are lots of improvements that can be made. If you feel like improving it, the sky is the limit! (pun intended ;) ).

It has been a long time coming, but we have finally released the Fly source code as open source. You can clone the github repository here or browse the source code here. Happy hacking!

Developing Stay.com 2.0 – an app post-mortem

You’re only as good as your last app. And the last one we’ve developed here at Cutehacks is Stay.com for Android and iOS. We developed the Android version and helped finalize the  iOS version. Here is a small write-up of some of our experiences developing and launching Stay.com 2.0. Overall it was a great success, but as you’ll see – we learned a few things along the way.

A short intro to Stay.com

If you don’t already know Stay.com here is a small introduction: Stay.com lets you create your own personal travel guides which you can download to your phone and use while offline. This saves a lot of money as roaming fees are still ridiculously high around the globe. Here are some screenshots:

The app is available for  Android and iOS, and if you want to know more check out this short video explaining the service.

What went wrong

We spent about five and a half months developing Stay.com for Android. We were two full time developers. We learned a lot along the way and I’ve selected three areas where we met problems.

Wrong#1 – Ignoring the Android look

Stay.com was developed for Android and iOS in parallel. At the start of the project we were asked by the designers what kind of modifications were needed to adapt the design, which was iOS focused, to Android. We estimated that no big changes were needed and promised we could make the iOS inspired design work on Android as well. We delivered on the promise, and launched a great looking app that handled the different resolutions of Android and followed the design close to pixel-perfection.

What we, or I guess I should say I, didn’t expect, was the negative reviews this provoked from some of the users downloading and rating the app on Google Play. I honestly didn’t know there were Android fanboys out there that cared. Some excerpts:

  • “…a converted iOS app on Android is an insult…”
  • “…it’s just an iOS app…”
  • “…iOS look on Android is not cool…”

Clear and honest feedback right there. And looking at things as they are now with Ice Cream Sandwich in use, updated fonts and proper design guidelines, I’d say they have a point. In my defense, the guidelines were not published when we started the project.

However, we’ve seen the errors of our ways and have have released several updates of the Android app that fixes most of these issues. Here are a few screenshots that shows some of the design changes:

Wrong#2 – Memory and performance

Another area that took us by surprise was the memory handling on Android. In short: the maximum heap size allowed for each app is limited and device dependent. If you try to allocate memory above this limit, your app is killed – just like that.  This is clearly not the way to do it, and I was surprised to find this behavior on a modern mobile OS like Android. We ended up having to rewrite some of our caching algorithms for  images, databases, and offline maps in order to run Stay.com on inferior Android devices. If you’re wondering how to do memory profiling on Android I recommend you watch this video - several times.

We also experienced performance issues with the default Android database. Every app can easily create a database where it adds, edits and retrieves data in a sensible manner. It turns out that inserts are really slow. If you want any sort of adequate performance you need to pay special attention to how you manipulate the database. For example, when inserting multiple rows in the same table make sure you do bulk inserts and not one row at a time.

Wrong#3 – Facebook SDKs

I’m not a big Facebook fan. In truth, up till we developed Stay.com I didn’t even have an account. Yeah, I know. One of the things we discovered during the implementations of some of the more advanced features of Stay.com and its Facebook integration was: the Facebook APIs suck. For the Android app we use both the official Facebook SDK for Android, as well as some of the REST APIs. We found them poorly documented, unstable, broken, non-compliant and confusing. Especially the REST APIs. Odd! The only tip I can give you are to keep an eye out for changes mentioned on the developer pages and search for tips and tricks on Stack Overflow.

What went right

Right#1 – Crash logger ACRA

A few days before we were ready to launch in Google Play, after we were done with most of the testing and debugging, I came across a post where someone mentioned this crash logger tool called ACRA. And just as an afterthought, we added it to the build. This turned out to be a great idea.

ACRA works in a very simple way. When the application crashes the user is given the chance to report back what just happened. If the user sends a report, a lot of debug data ends up in a Google spreadsheet of our choosing. ACRA is easy to integrate and has helped us expose a lot of bugs in our code. I highly recommend ACRA.

Right#2 – Trello, Git and GitHub

We use a lot of tools, but I’d like to focus on three of the ones we used when developing Stay.com.

Trello is a low-impact collaboration tool. It’s free, simple and online. You create a board for your project, you add some lists to the board, and in each list you add some cards. We used two boards when developing Stay.com – one for the Android client and one for iOS. We’re using Trello for all our projects now. We love it.

Git is a version control system. If you’re still using something like Perforce, Subversion or CVS, you need to get out more. Here are two reasons for using Git:

  • branches cost nothing
  • it works offline

Now, if you like being sysadmin it’s fairly easy to setup and maintain your own server where you can host your repositories. But if you just want something that works, go with GitHub. We’ve now upgraded to their business plan and I have to say that makes administrating different repositories, teams and access control very easy. Thumbs up!

Right#3 – Small teams, small companies

Developing Stay.com 2.0 for iOS and Android involved teams in different companies:

Somehow, this all went great. I think the combination of small teams in small companies really melded well together. Weekly meetings, IRC and Skype, shared source code, Basecamp, Trello and a mishmash of other tools helped collaboration.

Conclusion

Overall the development and launch of Stay.com 2.0 was a great success. The user feedback has been great and we’re proud of what we developed. The app has a 4 star rating on Google Play and 4+ on iTunes. Although the initial launch was in mid-June 2012 – we’re still working full-time on the Android and iOS versions, continuously fixing bugs and adding new features.

Why You Should Always Use SSL for API Calls

We recently had an interesting bug report for a project we’re working on;

“I was going through attractions in Venice and was adding them to ‘my guide’, however when I reopened the App the very next day it shows my guide, but it is empty.”

This was a bit disconcerting to say the least! When your App suddenly start losing data, alarm bells and blinking lights go off and you scramble to fix it. However, the world of hotspots and ‘free’ wireless networks is a menagerie that’s difficult to reproduce in a lab environment.

In this case, the App resumed normal operation once brought back online – which gives a hint to the cause. The fix was somewhat surprising and discovered by coincidence; You should always use SSL for all API calls! You’ll incur increased CPU use for decrypting data, and potentially have to get approval to use it – but it’s worth it! Let me explain;

The real culprit in the scenario above is a neat thing called “Captive Portal”. You’ve probably used when you have been out travelling, and purchased internet hours from an overpriced provider – or received a cupon from your friendly hotel clerk. Typically you open a browser to pass the Captive part of the portal. If your device is unfortunate enough to connect through a non-authenticated portal, your App could be in trouble.

In most cases, the portal will immediately present a login dialog when you try to go online – asking you to accept TOC or give them some money. In this case, the platform will recognize that you are not actually online and prevent your App from making API calls (assuming you’re guarding for this in your implementation).

- (void)reachabilityChanged:(NSNotification *)notification
{
  // using Reachability from Apple: http://tinyurl.com/42mxger
  NSUInteger status = [reachability currentReachabilityStatus];

  BOOL isOnline = (NotReachable != status);
  BOOL isUsingWiFi = (ReachableViaWiFi == status);

  // handle appropriately..
}

Trouble begins when less friendly implementations hijack your DNS queries and present their own content in place of what you’re asking for.

In the case of your App, regular HTTP API calls will appear to succeed, and return… garbage. Actually, they will return HTML content from the captive portal – but to your App it’s highly toxic garbage. In the scenario above, the App happily eats whatever content is served – promptly concludes there is nothing salient returned from the API call, and fails to display anything.

If you use HTTPS however, you will immediately get a certificate failure and you can handle the situation gracefully;

NSError *error; // out parameter from NSUrlConnection::syndSynchronousRequest

switch (error.code)
{
  case NSURLErrorServerCertificateHasBadDate:
  case NSURLErrorServerCertificateUntrusted:
  case NSURLErrorServerCertificateHasUnknownRoot:
  case NSURLErrorServerCertificateNotYetValid:
    // Handle the certificate error
    break;
}

.. and present the user with a clarifying dialog;

While I would have loved to go to Venice to dissect and purge the issue – there’s an easy way to reproduce this environment using only your local network;

1. Set up a Web server and DNS on your localhost.

Personally I used Mac OS X’s Server App to quickly get it up and running, but there are multiple guides out there to do it using a mix of dhcp, dns and apache.

2. After you’ve set up the DNS, add the hostname for the API calls you wish to block.

Set them to point to your own host’s network IP address – and make sure the web server has a 404 page configured.

3. Switch the DNS entry of the wireless network on your device to your host IP address.

4. All calls to the URL will now return your /index.html or alternatively the 404 page you configured.

In the case of using SSL it will provide an untrusted certificate that incorrectly claims to be your API endpoint.

For us, the lesson is that SSL is invaluable in mobile Apps and should be the default when polling data – because it accurately lets you identify that you’re receiving data from the correct source, and that it has not been tampered with on the way.

Designing assets for app developers

The development of apps is becoming more professional. As a result of this specialists like graphic designers are more often the creators of the look of an app these days. However, it’s still very much the realm of the programmer to deconstruct the design – and breath life into it. As a graphic designer, you can either help or hinder the developer in this job. It all depends on the assets you provide. Here is a list of best practices for graphic designers delivering assets to mobile developers. I assume the original designs are made with Photoshop/ Illustrator/ GiMP and that the programmer prefers them as 24bit .PNGs with an alpha channel.

1. Break up your screens into UI elements

It’s a good idea to provide mock-up screens  as a reference –  but these are not the files a developer wants to work with. You need to break the design apart into its different UI elements. Any button, frame, indicator, switch, arrow, toggle that you designed needs to be provided  in a separate file. If you leave this task to the developer your design might suffer inferior Photoshop skills and you’re wasting his time.

2. USE LAYERS, align them, provide all states

In each element file you need to provide all the states and color variations as separate layers. Take a custom button as an example. It comes in three colors and has two states (normal and pressed). That means you have to provide a button.psd with  six  layers: “black_normal”, “black_pressed”, “blue_normal” … you get the idea. Make sure to provide complete sets here. If you leave out layers, you’ve left the completion of your design to the programmer.  When you have complex set of layers where it is not obvious how they interact, make it simple for people by creating Layer comps in Photoshop. Also, make sure you’ve aligned the content of the different layers to their correct positions. The programmer should be able to simply save each layer in a separate .PNG without any extra work.

3. Use a sensible naming convention

If you pick a sensible naming convention for your files the programmer can adopt them and carry them on into the code with their original names. This makes it easier for both parties when designs needs to be updated, changed or expanded. Sensible file names from a programmers perspective means:

  • follow a consistent naming pattern. Example: header_button.psd, header_gradient.psd, header_logo.psd or similar.
  • use safe characters: lowercase a-z, 0-9 and _

4. Align to pixels

This really shouldn’t need telling, but apparently still does: Align your shapes to pixels. This means, almost without exception, any shape you add to your design must have a top-left and width-height that is in full-pixel values. This can be done easily in Illustrator, and moderately easily in Photoshop (“Snap to pixels” in the Shapes dialog). Coming back to the programmer with miss-aligned half pixels  is literally like flipping him the bird.

5. Summarize your color, font and margin choices

A lot of what the programmer ends up doing is condensing your design into reusable components and variables, hopefully without compromising its look. You can help in this by providing a list of your design guidelines. Ideally this list would contain your choices of:

  • Colors: text colors, button colors, list colors, effect colors
  • Gradients: backgrounds, effects etc.
  • Fonts: list of faces used, list of sizes used, shadow effect settings
  • Margins/Paddings: numbers for guides or grids used

6. Make your graphics scalable

It is no longer realistic to believe you are designing for one resolution or platform. More likely your design will be used for developing apps on both tablets and mobile phones across multiple platforms. Your design needs to be scaleable. You should always use vector shapes, your gradients and effects should be scaleable, you should never use pixmaps, your fonts should be readily available or embedded in the file. Basically, your image should look good rasterized to any size.

7. Tips for the elite designer

If you’re already following the above guidelines you’re making most  app developer happy. But if you want to go the extra mile, here are some tips to make your programmer even happier:

  • create scripts the programmer can run to render all assets to an arbitrary resolution
  • put your designs into any sort of version control system (git / svn / rcs / perforce)  - we honestly don’t care. Anything is better than zip files over mail, dropbox or whatever.
  • pre-render the assets to our current target resolutions – we’d love you for it.

Icons by http://dryicons.com

Tabs on Android

Using a tabbar, either at the top or bottom of an interface, is a typical design pattern used in apps to navigate between segments. This is used by the Android Twitter client for example. The typical way to implement this is by using TabWidget, TabActivity, TabHost and friends. Each tab is populated with whatever activity you want and all is well.

There is a problem with this approach however. If you start a new activity the tabs (area A, B, C) all disappear and this is not always what you want. Sometimes what you want is to keep the tabbar around and have an individual backstack for each of the tabs.

Typical tab layout

Typical tab layout

I’ve published an example on github that shows how you can get the best of both worlds. It explains how to keep an individual backstack for each tab, but also how to start activities that break out of the tabs as is the traditional way on Android. The Back button still works and you can also programmatically navigate back. The behavior of back is changed to respect the backstack of each individual tab.

If you want to try it out yourself I’ve compiled an Android package for you. Navigate to http://bit.ly/stacksintabs with your Android device and install the .apk to check it out.

Navigation in the example

Navigation in the example

The design is very simple. I still use TabWidget, TabHost and TabActivity (layout here) – but instead using normal activities for each tab, I subclass FragmentActivity – and build a stack of Fragments inside each tab. The gist of the code is in the addFragment(…) function

To launch a new fragment inside a tab (area D), see the launchNewFragment() function, and to see how you break out of the tabs and launch a new activity (area E) see the function launchNewActivity(…)

The fragments and activity I use are just examples, the point is that you replace ExampleActivity and ExampleFragment with you own classes.

My initial approach at solving this problem was using Fragments exclusively, but since nested Fragments are not supported on Android I gave up.

I hope this helps some of you – it’s all available under a BSD license. The example requires API level 7 and uses the Android Support library v4. Comments and contributions are welcome. Btw: I’m also working on a comparison between QML and Android XML where I compare pros and cons, so stay tuned for more :)

New office and new employee!

Nothing is like starting the new year with blank sheets of paper and color crayons! OK, Norwegian proverbs might not translate that well, but here we are: A new year, a new office, and a new employee (me)!

New Employee Cava

I can totally get used to lunches like this!

My name is Henrik Hartz, and I joined Espen and Marius January 2nd this year after working 7 years at Trolltech and Nokia. For the first week and a half I have been getting busy with existing projects while Espen and Marius are pushing new frontiers – for the time being focusing on an Android project.

Aside from 50% growth, we also moved to a new office – literally across the road from the old one. The new place is a lot larger – the three of us share an office – while we have a lunch-room (with a red couch and gaming system) and extra offices to spare. We want to grow even more this year.

After moving in – the place was in a bit of a shoddy state..

before we got our shit together

discombobulated...

After a quick stop at IKEA, we got some new office furniture to get us ready for a busy New Year!

espen building a bookcase marius building a coat stand david and alexandra helping out marius doing assembly

After organizing and cleaning up, we’re ready to take on the new year

marius can't stop hacking troll bowl lunch room coffee

 

Share