Building Trainly: Creating the Mobile App

From hacky web wrappers to cross-platform Flutter app - the evolution of Trainly's mobile experience

Welcome back to my multi-part series on how I built a fully capable and advanced train tracking app from scratch, what I learned along the way and the challenges I faced all while I was just 14 years old when I started. In this article, I will cover how I built the original Trainly app and the differences between then and now.

What was the first prototype version like?

After I'd spent a few weeks playing around with the Live Departure Board data and time interpolation, I figured it would be much more ideal to use this technology through an app rather than a primitive terminal app. I didn't know anything about mobile development at the time, however I stumbled across a library called AndroidJS.

The AndroidJS Discovery

It basically lets you build Android apps using HTML, CSS, and JavaScript I was already familiar with. Perfect!

The Reality Check

The first prototype was rough. Really rough. Think basic webpage squashed into a phone screen, wrapped up and launched like an app.

No animations
Questionable design
No loading spinner
~50MB APK size

But it worked! 🎉

  • âś“ See trains from chosen station
  • âś“ Live estimates
  • âś“ Track progress using interpolation

"That alone made it feel magical. I could open the app, click 'Track This Train', and see something I built tell me where a train was. For the first time, I knew that I was onto something. But this also made me question the lack of similar features in existing apps."

The Obvious Limitations

Clunky appearanceHacky web-to-native communicationDidn't behave like proper appMassive 50MB file size

But as a first attempt, it gave me the motivation to keep going.

How did I rewrite the app?

The AndroidJS Reality Check

I quickly realised that AndroidJS wasn't going to cut it long term:

  • Minimal support
  • Slow performance
  • Library not actively maintained
1

The Decision

After a few weeks of battling JavaScript workarounds, I decided to rewrite the entire thing using proper Android tools.

2

The New Approach

Mixing HTML with Kotlin using the built-in WebView. This gave me more control and performance while still letting me use my existing front-end code.

3

The Improvements

Better layouts
Smoother animations
Dynamic interactions
Real Android app feel

The Game Changer

What really stood out to me during this phase was how much more responsive the app felt. It still had the same backend logic—interpolating between station times—but now it actually felt usable.

This rewrite gave me the confidence to show it to friends and even use it daily on my commute, trusting it over well-established apps.

What about iOS?

Of course, I couldn't leave iPhone users behind—especially since most of the people I knew used iPhones. That made it the obvious next step.

The Success

Once the Android version was working smoothly enough and published on the Play Store, I started working on an iOS version.

The Roadblock

However I hit a bit of a road block: to compile for iOS and to publish on the App Store, you require an account to be enrolled in the Apple Developer Program.

The Cost Dilemma

$99 a year (~ÂŁ70) which isn't a small amount for something I didn't even know would be worth it.

After a while though, I decided to take the plunge and spent my Christmas money on a subscription to the program.

The Implementation

At this point, I didn't want to write a completely separate frontend, so I used the same idea: embed a web interface using Swift's WebView and link it up to native features where needed.

Challenge:Getting it to compile on Xcode was half the battle
Experience:Apple's ecosystem felt alien at first
Reality:Once running, surprisingly similar to Android WebView
Hardest Part:iOS-specific permissions and quirks

The iOS Milestones

TestFlight Deployment

I even managed to deploy a test version using TestFlight, which made sharing the app with friends on iPhones super easy.

Cross-Platform Achievement

More importantly, I'd officially crossed into the world of cross-platform development.

Why did I rewrite it again?

Everything changed when I discovered Flutter

Suddenly, I could build for Android and iOS at the same time—with proper native performance, beautiful UIs, and no hacky WebViews.

The Complete Transformation

I rewrote the entire app from scratch once more, making a few design tweaks, and this time it finally felt like the polished, proper experience I'd always wanted Trainly to be.

New Design Features (as it is today)

More visual feedback
Better train tracking
Live delay indicators
More accessible UI elements
Operator indications
Favourites
Proper share button

The Flutter Advantages

Single Codebase

Flutter allowed me to improve how the app handled updates. Since it's all one codebase, adding new features or fixing bugs didn't require twice the effort.

Better Focus

With more experience under my belt, I could focus on making the app faster, more stable, and more delightful to use.

It was miles ahead of the original prototype, and now something I was genuinely proud to share.

Ready to see the evolution continue? Stay tuned for Part 3 where I'll share the story of my first app release and the lessons learned!