Tuesday, January 31, 2012

Updating Qt applications in Nokia Store

Every Symbian Qt application in Nokia Store consists of two parts: metadata and content files. Metadata is the information about the application visible in Nokia Store, and content files are applications binaries, i.e. sis file. Both parts are separate entities, can be updated independently and have separate Quality Assurance process. It stands to reason: why would anyone have to verify the application binary when you correct a typo in applications  description?

But sometimes you might want to change the description and the binary at the same time. For example I screwed up testing of the first version of my "Nu, Pogodi!" game and first few reviews were negative with "Doesn't work, shows only black screen" comment. I fixed the issue, published new binary and added "Version 1.0.1 fixes the black screen issue." text to description. The metadata QA finished earlier, but still the old, malfunctioning binaries were served. Guess what happened - the next review was also negative, this time with "Black screen, cannot download version 1.0.1" text. Joy.

So the point is, currently there is no way to update both parts of content at the same time. The solution recommended by Nokia Publish Support is to publish the binaries first, because the QA for that part is longer than for metadata and update the metadata when binaries pass QA.

Friday, January 27, 2012

x:name binding crash on Windows Phone 7.1

Recently I've started working on the new version of Windows Phone application originally written by interns in my company. One of the first tasks was to migrate from WP 7.0 to 7.1, a.k.a. "Windows Phone 7.5" (because 7.5 sounds sooooo much better than 7.1), a.k.a. "Windows Phone Mango". The transition was generally smooth and it seems we'll be able to clean up some 7.0 specific workarounds, but there was one crash that was quite tricky to track down:

Null Reference Exception:
    at MS.Internal.XcpImports.CheckHResult(UInt32 hr)
    at MS.Internal.XcpImports.UIElement_Measure_WithDesiredSize(UIElement element, Size availableSize)
    at System.Windows.UIElement.Measure_WithDesiredSize(Size availableSize)
    at System.Windows.Controls.VirtualizingStackPanel.MeasureChild(UIElement child, Size layoutSlotSize)
    at System.Windows.Controls.VirtualizingStackPanel.MeasureOverride(Size constraint)

Our code wasn't even in a call stack! It turns out that the following code worked on 7.0, but crashed on newer version:

    text="{Binding Custom}"
    x:name="{Binding Key}"/>

I'm not sure if using binding for a control name and relying on that information in code behind is a good idea, but I'm damn sure it shouldn't crash. And even if it crashes, it should provide some useful information instead of throwing NRE from seemingly random place.

What's the fix for it? Use x:Tag instead of x:Name.

Sunday, January 22, 2012

How (not to) test your QML application for Symbian

First of all by QML I do not mean this, I mean this: a UI module of Qt, the cross-platform framework. The gals and guys at Nokia figured out that modern user interface cannot be fully described by static layout in a XML file. Microsoft figured out that too, but they chickened out and only extended XML a bit and added an 'a' to file extension to make it look like something new. Nokians took a step further and created new language for declarative UI based on JavaScript called QML.

The QML UI components can be defined in two ways: it can be a QML file composed of other components (for instance that's the usual way to define the main UI file) or it can be a C++ extension. Both ways can be used together to create a plugin, which can be imported to your project.

And at last we reach the intended topic of this post: testing. What happens if some QML file defining a component is missing? What happens if the whole plugin is missing or the version of this plugin is lower than the one required by application? QML files are interpreted during runtime, so of course you get the runtime error. In the best scenario it limits the functionality of your app, in the worst case it renders it completely unusable.

But hey, you can catch most of those errors simply by clicking through your application, right? Not exactly, doing so only tells you that in works on one particular device. You might have some plugins already installed, but not included in application's package and your app will work only on the devices which happen to have those plugins, which is not very likely.

That's exactly the error I made when I published the first version of "Nu, Pogodi!". I submitted for Q&A process an application with dependencies to Qt Components 1.1, build with the latest Qt SDK. I've tested it thoroughly on some devices I had access to and via Remote Device Access service (which BTW rocks; I wish there was a similar service for Android) and everything worked fine. The application was rejected by Q&A, because at the end of 2011 there was some technical issues with Nokia Store and latest Qt and I was told to rebuild my application with old SDK, which included only Qt Components 1.0. I've tested my game again and everything worked so I published it to Nokia Store. Few days later I received first reviews - all negative, along the lines "doesn't work, beware".

Qt Smart Installer partially prevents those errors, but you still might shoot yourself in the foot in some cases. My game had dependencies to Qt Components 1.1, but the pkg file declared dependency to version 1.0, because it was created with old SDK. When my customers installed the game, the smart installer ensured only that version 1.0 is installed, but my game needed newer version and failed during runtime. I didn't caught this during testing, because all of my devices had latest Qt Components installed.

That was the "How not to test your QML application" part, now let's get to solution. It's really simple: downgrade all the stuff needed by your application to versions defined in pkg file. To check the current versions of Qt libraries and plugins I recommend using an excellent QtInfo tool. To downgrade Qt you need the sis files distributed with old Qt SDK versions.

This simple steps should ensure that your application will work properly on all supported devices. Nevertheless, you should prepare for failure and handle all runtime errors in a user friendly way. But that's the topic for another post...

Friday, January 20, 2012

Introducing: Nu, Pogodi!

"Nu, pogodi!" is the first application I've published in Nokia Store (or any other app store, in fact). It's a remake of a classic handheld console game I used to play in my childhood: you had to place a wolf with a basket under one of four roosts to catch the eggs rolling from them. Despite the extreme simplicity and the obvious flaw in the game plot (namely: what the hell does the wolf need the eggs for?) the game was quite addictive and I spent many hours listening to the hypnotizing ticking of the falling eggs (if you played this game you know what I'm talking about).

The handheld console I based my game on is actually a Russian clone of "Egg" game from Nintendo's "Game & Watch" game series. The main difference is the graphics - instead of fox and hen the Russian clone featured the Wolf and the Hare from a "Nu, pogodi!" cartoon - hence the name of the game.

At the beginning of 2011 I wanted to check out the Qt Quick, which was advertised by Nokia as the best thing since sliced bread. I never liked the go-through-a-boring-tutorials way of learning new things, so I started writing UI for a simple game instead. Few weeks later Nokia announced Qt Quick Competition - an event promoting Qt Quick introduced in Qt 4.7. I've entered the competition with the early version of my game under the name "Nu, Pagadi!" (which is, as I learned later, incorrect - apparently in Russian sometimes you write an 'o', but pronounce it as 'a'), which didn't won me anything, but at least I had a motivation to work on the game. In accordance with the competition rules I've published my code under OSS license and forgot about the whole deal.

In November 2011 I've stumbled upon a "Soviet Eggs" game in Nokia Store. It seems that some company forked my competition entry, added a splash screen and the menu and charged 2 euros for it. I've watched the gameplay videos on YouTube, and thought I can do much better version than them. I polished my game, added sound effects, better looking menu and new game mode which resembles the gameplay of original game much more than the one included in the competition entry. All those changes took me about one week worth of evenings and one weekend. Subsequentially I've screwed up testing, published to Nokia Store a game which silently crashed on 90% of the phones, fixed the problem, and then I screwed up again, this time when publishing the update.

Despite the initial issues the game reached top 10 bestseller list in two weeks and stayed there ever since. Try it yourself!

Tuesday, January 17, 2012

Hello, world

I've been planning to start a blog for quite some time, but I kept finding excuses to put off writing. Not enough content, poor writing skills, not enough time - take your pick. What's changed? Not much really, except I said myself 'screw it' and stopped procrastinating. I want to start a blog, so I have to sit down and write something, don't I? Call it my new year's resolution.

What will I write about? During my day job and in my free time I conduct a lot of research on programming for mobile devices and I want to document my work somewhere. I've prepared a list of topics I'd like to write about and I hope my research will provide enough content to keep this list full (and anyways, if I ever run out of interesting subjects I can always write "top 10 blah" or "introduction to monads" post). I've started my professional career two and a half year ago as a Symbian OS programmer and I've stayed in mobile world since then and wrote stuff for every significant mobile platform except iOS (but I do plan to change this soon). Currently I'm programming mostly Android and Symbian apps.

So I'm going to gloat about the stuff I wrote, rant about various gotchas in the world of programming for mobile devices and I hope that in the meantime I'll learn something and have some fun.