Why I stopped using SwiftUI and AWS in my personal project

Forehand app’s logo

At the end of March this year, when the coronavirus lockdown began, I started missing table tennis. I decided to create a mobile app for table tennis players and enthusiasts. I already have a few personal apps and games in the iOS App Store but I wanted Forehand to be a bigger, multiplatform (iOS and Android) and long term one. Something like a personal business card for a mobile apps developer.

As I’m an iOS developer, I started from an iOS app. It’s 2020, I’m starting a new iOS app, sounds like a great opportunity to learn more about SwiftUI I thought. So I started building the iOS version of Forehand using SwiftUI. It was going quite well let’s say, I added a few initial screens.

SwiftUI project structure

First problems that I faced were around a performance of VStack. I had a VStack containing 5 WebView views, each of them loading a different HTML, embedded YouTube video.

WebView which I embedded 5 times (each with a different HTML) in VStack

Putting 5 instances of such a view was killing the performance, VStack was just almost non-scrollable.

Main issue number 2 was customising a navigation bar. Navigation bar on some of the screens was supposed to look like this:

Navigation bar with a custom background colour

or like this:

Another example of a navigation bar with a custom background colour

Unfortunately customising navigation bar’s background colour or its title’s background colour is not natively supported in SwiftUI and I needed to try some UIKit-ish solutions. None of them was perfect and at some point I even ended up replacing a navigation bar with a normal View. It worked, I could fully customise it but I didn’t feel it’s a long term solution. At the end I left default colours.

The last thing that I’m gonna mention in this article about problems with SwiftUI is Onboarding screen. In UIKit we do it with UIPageViewController. Unfortunately there is no built in SwiftUI component for that yet. I researched Stackoverflow what workarounds other developers do, I found a few solutions. They were based on manually calculating frames of swiped views. It didn’t work well for all screen sizes unfortunately so I decided to use a UIKit bridge called UIViewControllerRepresentable. UIViewControllerRepresentable and UIViewRepresentable are protocols which let you embed old good UIViewController or UIView in a SwiftUI app. So I had Onboarding screen working but there was a navigation to the Home screen after tapping a Next button on the last page of onboarding missing. In a UIKit-only app it would be an easy push(viewController) or performSegue(with identifier) but SwiftUI screens are driven by state changes so it’s a bit different.

I ended up doing something like this:

I was sending a “NextButtonTappedNotification” from Onboarding SwiftUI view conforming to UIViewControllerRepresentable and it was being received by ContentView which is SwiftUI app’s entry point. Not entirely clean solution but changing screens worked. There was a problem with a navigation bar though. I couldn’t get rid of an additional top header added by NavigationView / NavigationLink. I spent 2/3 evenings on that and taking into account previous problems as well I came to a conclusion that maybe it will be better to wait for SwiftUI 2.0 and not to spend my evenings on being frustrated and trying to fix things that are super easily achievable in UIKit. That’s why I decided to stop using SwiftUI for the first version of Forehand. I rewrote everything what I had to UIKit views in 2 days and I started progressing with the project much faster.

Most of the mobile applications need some sort of backend, some remote data provider. Forehand is not different. As I am a one-man-band (in terms of devs, because I have an awesome designer working with me on Forehand too), I wanted to go for something easy to set up, integrate and multiplatform (iOS, Android). I considered 2 options: Firebase and AWS. From my previous experience I knew that Firebase is easier to set up, you don’t need to deal with a maze of permissions setup but on the other hand AWS seems to be more scalable. As I think about Forehand as the app that I’m gonna support and maintain for a longer time, I decided to use AWS driven backend for my app. Unfortunately I faced a blocking issue just at the beginning of the integration, at authentication stage. I want the users of my app to be able to authenticate using the following methods: Log in with Facebook, Sign in with Apple and Email + password sign in. Sign in with Apple is not only a nice to have sign in method, but it’s also required by the App Store review guidelines if you have any social sign in method (including Log in with Facebook) in your app: https://developer.apple.com/news/?id=09122019b. Even though AWS Cognito officially supports that sign in method as per this article: https://aws.amazon.com/about-aws/whats-new/2019/11/amazon-cognito-now-supports-sign-in-with-apple/, there is still an open issue https://github.com/aws-amplify/aws-sdk-ios/issues/1809 and people try to find hacks to make it work. I didn’t want to go that way, I didn’t want to spend my evenings on finding hacks to fix AWS Cognito bugs and that’s why I decided to switch to Firebase where all sign in methods which I needed worked perfectly and the whole configuration process is really well documented.

Conclusions

  • Some of you may say that I’ve given up too early and that’s a fair point. I just want my free time that I spend on coding a personal app to be as enjoyable as possible. I also want to see the results as soon as possible, to touch what I build and to let other people touch it, test it, give some feedback.
  • Most of the SwiftUI issues that I’ve faced are fixed in SwiftUI 2.0 which will be publicly live this autumn. There are lazy stacks, native support for onboarding-like screens and much more: https://developer.apple.com/videos/play/wwdc2020/10041/. I just didn’t want to wait a few months for SwiftUI 2.0 to be publicly live and then maybe 2/3 months to build my app from scratch using a technology that I’m not fully confident with yet.
  • In terms of a backend solution - I’m not forgetting about AWS. Maybe one day I will go for some kind of a hybrid solution: Firebase managed authentication and AWS for storing and providing data - I don’t know if it’s possible though. I would need to do more research.

I hope this article will be at least a bit helpful for some of you. Please feel free to share your thoughts and experience with the technologies mentioned here.