Engineering • 7 min read
By Bitpanda
07.08.2024
In today’s dynamic cryptocurrency environment, immediate access to key information is essential. We are thrilled to roll out three innovative widgets for our Android and iOS applications: the BTC Price Widget, the Top Movers Widget, and the Portfolio Widget. These tools not only furnish your home screen with up-to-date, pertinent data but also streamline your navigation within our app — enabling quick checks on BTC prices, portfolio performance, and insights into market movers. So let's dive deeper into the world of Bitpanda Widgets!
The launch of these widgets marks a significant collaborative effort across our engineering landscape. The development involved a harmonious blend of expertise from our iOS and Android developers, backend engineers, designers — who ensured adherence to our design system and guidelines — and product managers along with technical leaders who played a pivotal role in defining the strategic direction of these widgets.
As extensions of the Bitpanda application, these widgets not only enhance our mobile presence but also solidify our reputation as an indispensable tool for both casual investors and serious traders. By integrating these widgets, we aim to elevate user engagement and simplify access to vital information, ensuring a seamless and effective investment experience. Based on user feedback, these were among the most requested features, highlighting our commitment to responsive innovation and user-centric development.
Here we would introduce the widgets with the features provided by each of them, Each of the widgets would have different states based on the functionality.
Displays the current BTC price with interval updates, a line chart of the price, and 24-hour price performance
Provides a snapshot of the user's portfolio and 24-hour performance. This widget requires users to be logged in to the application.
For users who want more privacy, this widget hides the portfolio value, showing only the chart and performance.
Displays the most active stocks and assets in the past 24 hours, including price and chart.
Android: Separate widgets for Top Gainers and Top Losers to avoid a complex UX for configuration.
iOS: A single widget with the ability to configure showing Gainers or Losers.
* Data shown in the images are only for sample and is not real data
In developing our new widgets for iOS and Android, we encountered several technical challenges that required innovative solutions. Key challenges included adhering to platform-specific best practices, managing periodic updates efficiently, and ensuring seamless UI performance across devices.
For iOS, we adapted our UI components to work exclusively with SwiftUI, as UIKit components are not compatible with WidgetKit. This involved rewriting parts of our UI to align with the latest Swift Charts for data visualisation, and implementing a simple caching solution to maintain data freshness.
On the Android side, we transitioned from traditional XML to Jetpack Glance for modern widget development. We also tackled challenges in asynchronous image loading and data persistence, requiring custom solutions for integrating Glide within Glance and managing data updates through Android DataStore with minimal resource usage by using WorkManagers.
By overcoming these obstacles, we were able to deliver high-performance, user-friendly widgets that enhance our app’s functionality and user engagement.
Here's a breakdown of the key aspects:
Separate codebases will be maintained for iOS (using Swift and SwiftUI) and Android (using Kotlin). This ensures adherence to each platform's best practices and UI/UX guidelines provided by our great designers and design system.
iOS: Xcode will be the primary development environment for building the iOS widget, leveraging Swift for programming, and SwiftUI for implementing the UI/UX.
Android: Android Studio will be used for development, with Kotlin as the programming language.
iOS: We used Xcode, Swift, and SwiftUI as it is not possible to use UIKit for Widget, and the supported iOS system is 15 and higher.
Android: We used Jetpack Glance library for implementing the UI of the widgets, WorkManager for periodic updates, DataStore for caching and persisting data in the widgets. Also we have used BroadcastReceivers for propagating updates across the widgets.
Widgets will mainly try to fetch and update data whenever the system asks it to update, and it will use the UserDefaults(iOS) and DataSore(Android) to have simple caching and persisting data mechanisms that makes sure it’s always showing relevant data for users.
To create a seamless and modern user interface, we adopted the latest version of Jetpack Glance, moving away from XML in widget development. Glance, though limited, fits our use case perfectly, allowing us to implement all widgets efficiently. For chart displays, we developed a custom class using Android Canvas to draw charts, which are then converted to images and integrated into the Glance UI, Because Glance doesn’t support working with Canvas directly. This approach provides a smooth and visually appealing user experience.
In addition, we faced challenges with integrating Glide, our image loading library, to load images asynchronously in Glance Images. Since Glance does not support direct asynchronous operations, we implemented workarounds to enable Glide to fetch and display images efficiently. These workarounds ensure that images are loaded without blocking the UI thread, maintaining a responsive user interface.
Furthermore, components in Jetpack Glance differ from runtime Compose, requiring us to re-implement some of our design system components to be Glance-friendly. This involved creating custom modifiers and adapting existing components to fit within the Glance library.
Ensuring that our widgets stay up-to-date with minimal resource usage was a key challenge. We developed a logic that triggers the creation of two unique workers when a user adds a widget to their home screen:
One-time Worker: This initialises the first data update for the widget, fetching data from our APIs to display immediately.
Also, whenever users leave the Bitpanda app we would trigger all of the one-time workers to update the widgets.
Periodic Worker: To maintain efficiency, this worker updates data every hour. The operating system manages the timing based on several criteria to optimise performance and resource usage.
We also implemented a feature to display the latest update timestamp in a human-readable format within the widget, enhancing user awareness of data freshness.
Since widgets and the app run in different processes, we utilised Android DataStore to persist widget data. We developed a wrapper around DataStore, complete with abstractions and useful functions, to streamline serialisation and deserialization. This allows upper-level classes to easily write and retrieve data without dealing with the complexities of data handling, ensuring consistent and reliable data access for the widgets.
By addressing these challenges, we have created robust, efficient, and user-friendly widgets that enhance the functionality and engagement of our application.
Apple's WidgetKit imposes a quota budget on how frequently an iOS widget can refresh its content. This is to ensure smooth performance and minimise battery drain. Here's a breakdown of the key points:
Budget Period: The quota budget applies over a 24-hour window, although the exact reset time might not be precisely at midnight.
Budget Range: Widgets viewed frequently by the user typically receive a budget of 40 to 70 refreshes per day. This translates roughly to updates every 15 to 60 minutes, but the actual frequency can vary.
Dynamic Allocation: WidgetKit dynamically allocates the budget based on several factors:
User Viewing Frequency: Widgets accessed often get more refreshes.
Last Update Time: Widgets that haven't updated recently might be prioritised.
App Activity: If the containing app is open, the widget might refresh more frequently.
Learning Period: During the initial days of usage, the system gathers user behaviour data. This can lead to more frequent refreshes for your widget as it learns user habits.
We overcome that issue with a simple caching solution that uses user defaults, and this helped a lot to always make sure the widget is showing the latest fetched/updated data, and we decided with the UI/UX team to add a small timestamp label to show for the used the latest fetched date, so users can be aware how old the data they are seeing are.
Plus we used the Bitpanda app lifecycle, app started, app killed, and app sent to the background, to ask the WidgetCenter to reload our widgets, as these calls don't count from the limited available quota.
Widgets views can only be written by SwiftUI, and it is not possible at all to use any UIKit or wrapped UIKit in a representable view at all, which means:
We had to rewrite some part of our views so it can be used in widgets,
Our Chart library was not an option, it was a UIKit library, so we had also to implement a small chart view using the latest Swift Charts library, which is only available since iOS16+, so the iOS 15 devices will not show that chart, and we replaced it with a horizontal line instead to show empty state instead.
Our new widgets provide quick access to crucial information, enhancing user experience and engagement. We encourage users to try the widgets and share their feedback. Future enhancements and new features are planned to further improve functionality. Download the latest version of the app to get started, and join our community on social media for updates and support.
Authors: Hamidreza Sahraei (Senior Engineer) & Ammar Alaranji (Engineer)
Bitpanda GmbH ve grup şirketleri (Bitpanda) Türk Parasının Kıymetini’nin Korunması Hakkında 32 sayılı Karar’ın 2/b maddesine göre Türkiye’de yerleşik sayılan hiçbir kişiye yönelik olarak 6362 sayılı Sermaye Piyasası Kanunu başta olmak üzere Türkiye Cumhuriyeti Devleti mevzuatı hükümleri gereği Türkiye’de faaliyet izni gerektiren hiçbir sermaye piyasası faaliyetine dair hizmet sunmamaktadır. Şayet Bitpanda’nın yabancı sermaye piyasalarında vermiş olduğu hizmetlerden Türkiye’de yerleşik kişilerin faydalandığı tespit edilecek olursa tüm zararları kullanıcıya ait olmak üzere bu hizmetler ivedilikle sona erdirilecektir.
We use cookies to optimise our services. Learn more
The information we collect is used by us as part of our EU-wide activities. Cookie settings
As the name would suggest, some cookies on our website are essential. They are necessary to remember your settings when using Bitpanda, (such as privacy or language settings), to protect the platform from attacks, or simply to stay logged in after you originally log in. You have the option to refuse, block or delete them, but this will significantly affect your experience using the website and not all our services will be available to you.
We use such cookies and similar technologies to collect information as users browse our website to help us better understand how it is used and then improve our services accordingly. It also helps us measure the overall performance of our website. We receive the date that this generates on an aggregated and anonymous basis. Blocking these cookies and tools does not affect the way our services work, but it does make it much harder for us to improve your experience.
These cookies are used to provide you with adverts relevant to Bitpanda. The tools for this are usually provided by third parties. With the help of these cookies and such third parties, we can ensure for example, that you don’t see the same ad more than once and that the advertisements are tailored to your interests. We can also use these technologies to measure the success of our marketing campaigns. Blocking these cookies and similar technologies does not generally affect the way our services work. Please note, however, that while you’ll still see advertisements about Bitpanda on websites, the adverts will no longer be personalised for you.