(Portfolio Update) Ascension - Reaching the number 1 Bible app spot in the US App Store
When I was asked to lead Ascension mobile development, leaving The Pump, Arnold Schwarzenegger's official fitness app, felt bit sad, because it seemed like nothing bigger can come after that. Well, I couldn't be more wrong. Releasing Ascension was my biggest success story as a developer, with the application gaining the number 1 spot in the US App Store reference category, reaching the 36th place in the broad US App Store free apps category, gaining over 50,000 registered users within a first 24 hours, and finally keeping rating 4.9+ ⭐️ on both iOS and Android platforms.
The client, Ascension Press (opens in a new tab), is a publisher of Catholic books and digital media, and they have huge amount of digital content, with podcasts The Bible in a Year and The Catechism in a Year, probably being the most popular, especially among the US audience. So popular that The Catechism in a Year was just behind the Joe Rogan Experience in the USA top podcasts. Therefore, the client tasked STRV in building a mobile application to unite all their digital content with the Bible and the Catechism (2 books + 2 podcasts) being the centerpiece of everything.
As you can imagine, this was quite a technical challenge, yet we kept the team reasonably sized with 2 core frontend engineers and 1 core backend engineer to keep the efficiency high. To hit our milestones safely, we would eventually bring +1 for both FE and BE. And as usual, we were accompanied by 1 PM, 1 QA (+1 before the launch), and 1 designer. The application didn't require any strong native integration, therefore React Native was picked to provide the client with fast and efficient development.
Before we could even start developing, we had to figure out the biggest technical challenge - how to display the Bible and the Catechism. We knew we needed interactions such as highlights, taking notes, text resizing, saving last position, cross referencing to certain book sections, which is something eBooks have figured out before us, therefore a Webview implementation with epub.js (opens in a new tab) was considered. But we also needed custom design and ability to dynamically insert certain additional content before or after specific verses/paragraphs to provide even more depth to the original books.
We understood we need an absolute control for the best user experience, so we undertook an epic quest of creating our custom data structure and parsing ePub version of the books with its enormous content into it. And given the "static" nature of the books (in other words, the Bible won't change), it was actually a safe decision allowing storing indexed interactions on the backend, but keeping the content on the frontend and making the books and search for the users offline as default.
Nevertheless, it turned out that there were many more technical challenges we had to face after that and push React Native to its limits.
One of them were long lists of content, React Native's main nemesis. While the Bible chapters are relatively well sized, the Catechism chapters can have over 200 paragraphs. Moreover, we could not display simple text, because the parsed content actually had to include html tags to apply to certain words italics or bold styles, and also to keep
<a> tags to custom render footnotes and references to other book sections. The amazing library react-native-render-html (opens in a new tab) helped us tremendously with rendering, but the performance suffered quite a bit. It could have been easily solved by using recycling from Flashlist (opens in a new tab), but Flashlist is unable to scroll precisely to a specific index when content is not consistently sized, which was a crucial user experience interaction to access the exact last location or navigate to a specific highlight or reference. So we got stuck with
Flatlist, which by the way is not great in it either, but is able to make it work when you set
initialNumToRender to your desired index, but you can imagine what happens to the JS thread when you set it to 200. Eventually, we made Catechism content more granular, splitting chapters into articles and smartly optimizing our components with
memo, which mostly resolved our performance issue. Finally, on top of it we added a skeleton loader to make the user experience even better.
I actually found a way how to make the scroll with Flashlist work, but it requires to scroll to the given index at least 3 times within 1000ms using timeouts, so that Flashlist has time to correct its calculation of the location. From user experience point of view, this can work only if you cover the reader screen with a loader/skeleton, do your index scrolling, and then show the user the reader and hope it worked 😅. Currently, there was not enough time and faith for the refactor, but it is on my mind.
Basically, the application already replicates a fully fledged eBook reader functionality, with some cool features such as scroll up/down to go to previous/next chapters/locations, but again there was much more to build. For example, a fully fledged podcast player with transcripts and a global miniplayer allowing you to navigate the rest of the app while listening.
As big believers in Expo, we started with Expo AV (opens in a new tab), but we quickly realized we would be missing out on iOS lock screen audio controls and promptly switched to more feature rich react-native-track-player (opens in a new tab). The library is currently in v4 release candidate status, but it is already stable. The library helps nicely with queueing of audio tracks, progress tracking and each track can carry extra metadata to access anywhere in the app. At the time of writing, the Ascension app has 4 various audio types (the two podcasts, individual Bible Answers tracks, the Bible as an audio book, Bible Studies playlists), so metadata helped tremendously to separate progress tracking/queuing logic for each one of them. Finally the library's documentation is clear and helped us to easily implement an offline listening feature, which all users wanted the most.
As a part of the Bible Answers (1000 pieces of inserted content to certain parts of the Bible - text, images, audio, video), we also implemented a video player using both react-native-video (opens in a new tab) and Expo av. We found that on iOS we couldn't use Expo AV for video, because it was overriding native settings of the audio player and lock screen audio controls would be lost again. Therefore, we switched to react-native-video, but found issues on Android with full screen controls and orientation. That is why we ended up with react-native-video on iOS and Expo AV for videos on Android. React Native at its best 😅. But lets be honest, it is so great to have the option to split the logic based on a platform.
This is already my longest portfolio article, but there is still so many more things to talk about. For example, after two previous GraphQL projects, our backend engineers chose a REST api, therefore React Query (opens in a new tab) was chosen to help with the API management. Given, that with GraphQL you can easily generate types and React Query hooks from a schema, I was searching for a way how to do it with REST. I remembered when I was playing with Supabase 2 years back (public talk (opens in a new tab)), the had types generation thanks to OpenAPI (opens in a new tab), therefore I persuaded our amazing backend engineer to maintain an OpenAPI schema and used this OpenAPI codegen (opens in a new tab) to generate types and React Query hooks to make the project more maintainable. Eventually, I also migrated the project to a monorepo, so that we could reuse the api and other things on the admin.
Finally, I am just at the bring of launching subscriptions to give users access to even more premium digital content. Revenue Cat (opens in a new tab) has proven to be a great choice for The Pump, therefore I picked it for Ascension as well.
At the time of writing, the Ascension project is still ongoing and there is still so much more content to incorporate into the app. Besides new features, Ascension constantly monitors feedback (among other smart things their amazing team does) from the users, who are generally bit older, so they bring valuable insights, how to make the app easy to use for everyone.
Over 6 weeks since the launch (28 June, 2023), we have already gathered over 10,000 ratings on iOS and 2,600 on Android, still keeping the rating 4.9+ ⭐️ on both platforms.© Aron BerezkinRSS