Cross-platform mobile app development for iOS, SailfishOS and Android with Qt/QML
A few weeks ago, our cross-platform Qt-based version of the Berlin-Vegan guide for SailfishOS and iOS made its debut on the Apple App Store. In this blog post, I would like to share our experience with developing a cross-platform mobile application for iOS and SailfishOS with Qt.
1 How we got there
During the development of the new Android version of the Berlin-Vegan guide, being a Jolla phone owner myself, I started writing a native version for SailfishOS. The first version of Berlin-Vegan for SailfishOS was released in November 2016 on the OpenRepos store.
For iOS still only the nice but aged original PhoneGap based version was available. With the native SailfishOS SDK being based on Qt and QML and Qt being a cross-platform toolkit, the idea of porting the SailfishOS app to iOS and finally filling that gap this way suggested itself immediately. Learning from Julian, who also developed a lion share of the new Android version, that he decided to join that foray, made me really happy, as it gave this project a real chance.
2 Porting approach: Silica-to-V-Play wrapper (and generic components)
Although Qt is a cross-platform framework, for mobile targets, Qt is unfortunately not there yet. At the moment, you cannot simply take a SailfishOS app, recompile it for iOS and voilà, the port is done. Some porting effort is required. After a little research, we chose to harness the Qt-based V-Play Engine, as it promised us achieving better native look and feel easier and making the initial bring-up way more convenient.
And in fact, our Silica-to-V-Play wrapper (in many cases it actually is a wrapper to plain Qt) approach was really helpful for getting a rough version of the app running on iOS pretty fast. But when the development moved on, it turned out that in some cases we needed more flexibility how the app looks like and behaves on the two platforms. For those cases, we started introducing abstractions for both SailfishOS and iOS — very similar to the Universal Components approach taken by Martin Kolman for ModRana. The first instance where we needed abstractions for both platforms was the Theme component.
At the moment, we run with a hybrid solution: Some components can still be perfectly handled with the Silica-wrapper approach, some need abstractions for both platforms. And in some cases we explicitly want to solve things differently for the two platforms (as apposed to bridging platform gaps). In those cases, we make the distinction right at that place in the code:
If (BVApp.Platform.isSailfish)... .
Example: On SailfishOS, we want to apply a nice opacity transition to the venue picture, on iOS we want to show the picture without it:
3 Pain points
3.1 Push attached
SailfishOS has the special feature of attaching a page on the right hand side of the navigation stack (
pushAttached()). We made use of this feature to implement a swipe gesture for getting from the venue description to its map page. But this
pushAttached() mechanism is not available on V-Play and those swipe gestures are not a common navigation scheme on iOS. Therfore, as solution for the port, we extended the navigation stack of V-Play in a way that it supports the
pushAttached() API by pushing a page together with an icon. This attached page can then be launched via a button (showing that icon) from the right side of the navigation bar (on the upper right corner).
Although V-Play already comes with an advanced abstraction for the navigation control, creating a menu solution that works on both V-Play and SailfishOS was an ongoing challenge, which required a second iteration after the first shot turned out not being flexible enough during development.
While SailfishOS has this pretty nice concept of a pulley menu, which lives on an initial page, it is the exact other way round on V-Play and iOS: The menu owns and manages page
Components for every menu item, and creates new pages from it once a menu item gets clicked the first time.
MenuItem[SailfishOS, V-Play] with a page property that gets simply pushed to the top of the navigation stack on SailfishOS. And an
ActionMenuItem[SailfishOS, V-Play], which replaces the whole navigation stack on SailfishOS (including the root page) and which allows you to perform an action on that new page once it was replaced (
The menu abstraction of SailfishOS makes sure that the pulley menu is always attached to the root page on the navigation stack.
In this way we are able to support those two completely different navigation metaphors on the two platforms with one single menu definition:
The app is now available for iOS and for SailfishOS. Thanks to V-Play a version for Android came as a byproduct almost automatically with the port (which could possibly even replace the current native Android version, once the Qt app is on par with it).
Our hybrid porting approach in conjunction with Qt and V-Play facilitated us to come up with a port of the app to iOS very quickly. At the same time, it gave us a large range of flexibility: We could reuse existing code without almost no effort, but also shape things differently wherever we wanted to.
The V-Play engine helped us with bring-up and iOS integration. Its desktop target is a neat tool to speed up the development turnaround cycle. A nice plus that is that it allowed me developing for iOS without even having an iPhone or a Mac. The downside of V-Play (as opposed to plain Qt) is that its no free and open source software. Beyond all ideological considerations, the lack of source code actually put bumps in our road during development from time to time.
Using Qt for mobile app development was a very interesting and pleasant experience, and we do not regret our decision for Qt. The Qt community (the Qt company in particular) has interesting plans for exposing actual native controls directly within Qt: Either abstracted away as a generic component, or as components for specific platforms if an abstraction is not possible in a meaningful way — with the possibility of mixing both. It will be interesting to see where this road leads us. Exciting times are lying ahead of us in the mobile Qt universe.