In this guest post Dipl.Inf. Oliver Kuss shares insights about several problems he faced when developing cross-platform apps. He now uses Felgo to speed up the process, saving months of development time compared to the first cross-platform app he worked on. Read along to learn about the biggest issues, and what solutions Felgo provides to solve them.
Cross-platform App Development? No Problem!
That’s what I thought when we started our first app for both Android and iOS. We were just a small team and had never done cross-platform mobile apps before. The app included live audio and video, as well as push notifications and network service discovery. Having gained some experience using QML, we decided to use QML and Qt QuickControls 2 for this new project.
Thanks to QML, the first prototype worked within weeks but the details kept us busy for months. Not being covered by QML or the QuickControls, features like push notifications or platform dialogs required completely different native code for both platforms. We had to bridge language borders between C++ and Swift (or Objective-C) for iOS, as well as Java for Android.
Different screen sizes and densities produced errors and an unaesthetic look on several of the many targeted mobile devices. GUI elements and fonts that looked fine on one device came up too large or too small on another. We learned about dots per inch (DPI), point and pixel sizes, and that we need to calculate and apply scaling factors to all size values in our user interface.
Due to this experience and the vast amount of time that was lost, we now rely on Felgo to handle all those details for us:
- Reason 1: Multiple Device and Screens Support
- Reason 2: App Navigation and Pages
- Reason 3: Controls and Theming
- Reason 4: Access to Native Platform Features
- Reason 5: Local Storage and App Settings
- Reason 6: Push Notifications, Firebase and Other Plugins
Reason 1: Multiple Device and Screen Support
Almost every cross-platform mobile app has to deal with multiple screen sizes and densities. I strongly recommend you read the article, in case you haven’t already. Without Felgo, we had to find and work on a solution ourselves. In short, the App component adds methods like sp() and dp() to help you maintain a consistent physical size of your UI across the different platforms. You may simply write:
import Felgo 3.0
import QtQuick 2.12
App {
Page {
Rectangle {
color: "lightyellow"
anchors.centerIn: parent
// density-independent item size
width: dp(144)
height: dp(144)
}
AppText {
text: "Hello World"
anchors.centerIn: parent
// density-independent font-size
font.pixelSize: sp(14)
}
}
}
A static pixel value without dp() or sp() will produce smaller elements on screens with a higher pixel density. By using these functions instead, you can ensure the same physical size on all screens.
Reason 2: App Navigation and Pages
In almost any app, you will need a mixture of direct and hierarchical page navigation. This is handled by the Felgo Navigation components. Use NavigationItems inside a Navigation to support direct page access via a tab bar on iOS or menu drawer on Android:
import Felgo 3.0
App {
Navigation {
NavigationItem {
title: "Home"
icon: IconType.home
NavigationStack {
Page {
title: "Main Page"
}
}
}
NavigationItem {
title: "Lists"
icon: IconType.list
NavigationStack {
Page {
title: "Lists"
}
}
}
}
}
Also have a look at the Felgo Page component and how it interacts with NavigationStack. We spent two months of work creating something similar for our project. You can use the NavigationStack to push() and pop() Pages to implement a page hierarchy:
import Felgo 3.0
import QtQuick 2.12
App {
NavigationStack {
initialPage: pageComponent
}
Component {
id: pageComponent
Page {
id: pageItem
property int count: 0
title: "Page #"+count
Row {
AppButton {
text: "Pop"
onClicked: navigationStack.pop()
}
AppButton {
text: "Push"
onClicked: navigationStack.push(pageComp, { count: (pageItem.count+1) })
}
}
}
}
}
Of course you may place a NavigationStack inside a NavigationItem to implement a mixture of direct and hierarchical navigation.
The Felgo approach is much cleaner than the solution we made ourselves. We tried to handle this all within one multi-purpose component, which led to some rather messy QML code.
Reason 3: Controls and Theming
When populating your pages with GUI controls, make sure you use the enhanced Felgo ones instead of Qt Quick Controls. They automatically respect platform colors and screen-independent sizes defined in the app-wide styling Theme! We had to do this ourselves, because the default QML controls are quite low level.
The Felgo items also add even more useful features. For example the AppTextField, which is an input control for one line of text. It offers a clear button (a little ‘x’ to clear all input) or the clearsOnBeginEditing property. This customization and flexibility is great in case you need such features. We did.
Apart from such simple controls, there are many advanced features as well, like a SearchBar or a PullToRefreshHandler. Implementing all of those without Felgo cost us quite some precious time.
Reason 4: Access to Native Platform Features
We did want dialogs to look and behave like they do on the respective platforms, so we had to do two different implementations and pass data and signals between the native code, the C++ layer and the QML UI. With the NativeDialog component we could have saved quite a substantial amount of platform specific code.
When talking about native features, you should check out the Felgo NativeUtils as well. You can use it to handle the safe area on iPhone X or to get access to device contacts, pictures or the camera. For even easier access to native dialogs, there are a couple of ready-to-use display-functions as well:
import Felgo 3.0
App {
AppButton {
text: "Open Dialog"
anchors.centerIn: parent
onClicked: {
nativeUtils.displayAlertDialog(qsTr("Title"), qsTr("Description"), qsTr("OK"), qsTr("Cancel"))
}
}
}
Reason 5: Local Storage and App Settings
Rather sooner than later your app will need some kind of data storage, like for some application settings. Since QML is based on JavaScript, JSON is a good choice for the main data format. QtQuick allows you to use a MySQL database, which is a fast option even for large data. But it is rather inconvenient to use for some simple JSON-based settings. Felgo takes it one step further. The Storage component encapsulates such a database and is made to be used with JSON data. You can access this database as a simple key-value store. So there is no need for SQL queries! Simply use
myStorage.setValue (key, value)
and
value = myStorage.getValue (key)
to write and read values. Felgo even automatically calls JSON.stringify() when writing composed values. If desired, you can still work with the database directly and use SQL queries instead.
Among other useful features, like the functions for screen-independent sizes, the Felgo App component also contains a settings property. It is a default Storage that you can directly use to read and store data:
import Felgo 3.0
import QtQuick 2.5
App {
id: app
// this property holds how often the app was started
property int numberAppStarts
Component.onCompleted: {
// read setting, or start with '0' if 'undefined' is returned
numberAppStarts = app.settings.getValue("numberAppStarts") || 0
// increase value and store setting
numberAppStarts++
app.settings.setValue("numberAppStarts", numberAppStarts)
}
NavigationStack {
Page {
title: "Settings"
AppText {
anchors.centerIn: parent
text: "App starts: " + numberAppStarts
}
}
}
}
You can thus skip adding your own Storage item for simple app settings and directly use Felgo’s default local storage instead.
Reason 6: Push Notifications, Firebase and Other Plugins
With Felgo Plugins, there is even cross-platform support for integration of push notifications or third-party frameworks like Google Firebase. Otherwise, you need your own platform specific code for integration of such features on Android and iOS. Receiving a push notification in Felgo is then a simple matter of setting up the plugin. To handle a new notification in code, just connect the notificationReceived signal in QML and you are done!
What If We Knew About Felgo Earlier?
Well, the app was late but we managed to solve all the problems and release it. I learned about Felgo just before the release. If I had known earlier, we could have saved about 50% of the development time. Instead of recreating solutions that Felgo already provides and that are not unique or specific to our app, we would have been able to focus more on the app itself.
So, please: Don’t make the same mistake as we did.
Rely on Felgo to make your life easier and your development faster!
Oliver Kuss worked for three decades as a professional software developer for different companies, mostly using C++. He finished his diploma (aka master) in computer science at the University of Erlangen, Germany in 1993. Oliver used Qt for the last 10 years and especially QML for 4 years. He is now self-employed to do what he likes best: Creating applications with Felgo!
Related Articles
How To Add Augmented Reality to your App
How To Add Machine Learning to your App
3 Practical App Development Video Tutorials
Most Popular Programming Languages