coding

Musclog: Leveraging my React.js experience to build a React Native App

From Bodybuilding to Codebuilding: Crafting a comprehensive fitness App using React Native and Expo

Written in August 21, 2024 - 🕒 17 min. read

Musclog illustration
Musclog illustration

I constantly have that feeling of ”You become the very thing you swore to destroy” due to the amount of time I’ve been dedicating to bodybuilding in the past two years. I’ve been tracking my macros, my workouts, and even taking brogress pictures.

Not that I had anything against bodybuilding in the past, but I had tried working out before, and I never really got into it. I always felt like I was a skateboarder at heart and that I was betraying my true self by lifting weights. I know, silly.

Anyway, I’ve been using a combination of apps and integrations to achieve my performance tracking, including a custom Node.js script to calculate my TDEE and average calories using the Google Fit API, but since Google Fit is going to be deprecated soon in favor of the new Health Connect, I couldn’t postpone the development of my own app any longer.

But how? I honestly had no idea where to start, especially tapping into integrations with another app’s API. I didn’t even know in which format this data would be available. What’s the market standard? JSON? XML? Binary? I had no idea. Luckily, I found out that some really smart people created a library to integrate the Health Connect API with React Native, and knowing that was the tipping point for me to start developing my own app.

The perfect solution

I created all these scripts and integrations to monitor my workouts and nutrition because one thing I’ve discovered in these past few years of bodybuilding is that what really helps me stay consistent is tracking everything. I’m a data guy, and if I can see my progress in numbers, it motivates me to keep going. The truth is, if you’re not using any anabolic steroids, progress is slow, and at least for me, I don’t see any difference in the mirror, so the numbers are all I have.

I’ve been tracking everything I eat for two years now, and I also weigh myself with a scale that measures my body fat percentage, so I have a lot of data to analyze and identify my eating and workout patterns. What I want is something that’s really hard to find because most apps or websites out there don’t expect someone to be so meticulous as to track everything obsessively every day, but I love doing it.

So, the first idea was simply to get the data and continue my calculations with my scripts, and that’s how the idea for my first MVP was born.

The MVP

As I said, all I wanted was to access the Health Connect data and get my nutrition and weight data, so I could continue running my Node.js script, even if I had to have a simple app that fetched the data in the background and sent it to my server. Sounds like a plan, right?

Well… it seems like Health Connect only allows developers to access the data from the last 30 days due to privacy concerns. Okay… so this means I can’t get my historical data, and everything that is on Google Fit will be lost forever. Awesome!

The Real MVP

Perfection
Perfection

Cool, so our MVP died before reaching the shore; time to pivot: What if, instead of having a Node.js script that connects to different APIs, I could have a React Native app that will do most of the things, like workout tracking, nutrition insights, TDEE calculation, charts, tips, etc., and any other data that could be missing, I get from the Health Connect API? I could even add an option to import past data from a JSON file. This way, if Google Fit eventually allows me to export my data, I can import it to my app.

I have actually jumped from app to app in the past, trying to find the best way to track my workouts. I even tried Google Spreadsheet, but the UX was horrible on mobile, and I would like to focus on my workout and not stress myself out about touching the wrong cell on the spreadsheet.

Fine, I will do it myself
Fine, I will do it myself

So, React Native, huh?

Of course, I knew React Native was a thing, but as a React.js developer, I had never really considered diving into it, but surely it couldn’t be that hard, right? I mean, I already knew React, so how different could it be?

Well…

It turns out building a React Native app when your only experience is with React.js is like trying to switch from a skateboard to a surfboard. Sure, the principles are somewhat similar—balance, navigation, staying cool when things go wrong, but the medium is entirely different. In this case, the medium involved figuring out how to wrangle all sorts of device-specific quirks while keeping the app functional and responsive.

Surfing with a skateboard
Surfing with a skateboard

For example, as a web developer I focus on keeping a local state on the client and getting data from the server when needed, but on React Native, I want to have a local database, how should I go about that? Well, I found out about AsyncStorage, so why not go with it for now? (this will bite me in the ass later)

Still, I had no idea where to start from, though, but after chatting with my friends Juampi and Raf about my idea, they suggested I use Expo, a framework that allows you to build React Native apps without having to deal with the native side of things. That was honestly a game-changer for me because I could simply run my app in the browser most of the time and only use my phone to test the features that require native code.

Diving into Expo

I started by creating a new Expo project by following the ”Create your first app” tutorial, and then I created a new screen with a simple button that would connect to the Health Connect API and get my nutrition data and there I was, I already had my first MVP done, but because I don’t really like testing on my phone, I basically just copied the JSON response from the API and saved it into a file, so I could continue developing only on my computer and browser—this will bite me in the ass later².

After playing around with Expo for a weekend, I had a vague idea of what I needed for my app:

Time to get my calloused hands to work!

The joy (and pain) of learning on the fly

As I ventured deeper into the world of React Native, I quickly realized that my trusty toolbox from the React.js universe was, well, not entirely fit for the job. For starters, my database schema was way too complex for AsyncStorage, so, I figured, why not switch to IndexedDB? Spoiler alert: IndexedDB only works on the web, not on the mobile build of the Expo app. Oops.

Life of solo developer
Life of solo developer

After some wasted hours trying to polyfill IndexedDB for React Native, I simply gave up and I found myself in the middle of a major refactor. I decided to switch to expo-sqlite, a proper local database solution for mobile. But here’s the kicker—I still needed Dexie.js (a wrapper for IndexedDB) to keep the web build functional while I was developing the app since I mostly use the browser for it.

Thankfully the team behind Expo really did think of everything: Enter .web files in Expo—essentially, Expo allows you to create platform-specific files (like database.ts and database.web.ts) so you can have different implementations for web and mobile. This was a lifesaver, and after this discovery, I can confirm that refactoring code while muttering “better late than never” is totally a thing.

And let’s not forget the charts—because what’s a fitness app without fancy progress graphs, right? Well, react-native-charts-wrapper works great on mobile but not on web, so I had to bring in react-chartjs-2 for the web version. You can see where this is going: juggling two different chart libraries depending on the platform was just another part of the fun.

By now, I was deep into this rabbit hole, and to make life a bit easier, I added some developer tools to the app, like export and import database functions. This made it possible to move data between web and mobile during development. It was around this time that I realized why people are so in love with Firebase—maybe in a future version, I’ll make the switch, but for now, Musclog is 100% offline.

Building the features, one rep at a time

Software development is a lot like bodybuilding, you start with a plan, but then you find out that you have lagging biceps genetics, and you end up pivoting and doing 28 sets for biceps per week (right guys?). My original vision was pretty simple: just a place to track my workouts and nutrition. But to get there, I had to build a robust system for creating and editing exercises, constructing workout plans, viewing past workouts, calculating workout volume, and so much more.

Workouts tracking
Workouts tracking

And nutrition tracking? Well, it’s not just about logging meals. I needed to be able to add foods, different macros, track calories, and integrate all of this with the workout data. As I kept adding features, I noticed that I was using GPT for nutrition information. So, why not integrate it into the app? That’s how Musclog ended up with a chatbot feature. Now, I can ask it things like, “How many calories are in a banana?” and get a quick answer. But let’s not get ahead of ourselves.

Nutrition charts
Nutrition charts

From tracking to chatting

So, here I was, juggling workout logs, nutrition tracking, and managing multiple components for different platforms, and still I decided to add some ✨AI✨ into the mix? After all, everyone loves a good chatbot these days, and if you know me, oh boy, do I like a chatbot—so much that I’ve spent hundreds of hours coding a Magento chatbot extension that for many years was my most popular open-source project.

I started by adding a simple chat interface to the app, where users could ask questions like, “What’s a good post-workout meal?” or “How do I improve my bench press form?” The idea was to create an AI-powered personal trainer that’s always on hand, ready to provide insights and tips.

As usual, after many hours of coding, I decided to show my progress to my friends, and they were like, “Why not use Gifted Chat for this?“. Wait so you’re telling me after implementing a chat interface from scratch, sending and parsing messages, I could have just used a library? Well, I guess that’s the beauty of learning on the fly.

OpenAI integration

Integrating OpenAI into Musclog was a no-brainer for me. I had already dabbled with it in other projects, like when I used OpenAI to automatically create Instagram Reels coding tutorials. With that experience, I was already familiar with function calls, parsing responses, and handling prompts. So, I thought, why not add this powerful tool to my app?

Chatting on Musclog
Chatting on Musclog

The integration itself was pretty straightforward. I used OpenAI’s API to process user queries and provide insightful responses. Every time a user sends a message, the chat history is sent back to OpenAI to keep the conversation context intact. To give the AI a bit of personality, I used system messages like, “You’re a helpful personal trainer named Chad, and you’re here to help with fitness journeys. Ask me anything!”

But it didn’t stop there. I figured if I’m already integrating OpenAI, why not take it a step further? So, I added an option to ask OpenAI to create a workout plan directly. For instance, you can use the chatbot to ask, “Can you please create me a push-pull-legs workout?” and boom—Chad the trainer springs into action, generating a customized workout routine on the spot. This feature is particularly handy when you’re not sure how to structure your training or if you’re looking to mix things up.

The possibilities here are pretty exciting. With this integration, Musclog isn’t just a static workout tracker; it becomes a dynamic fitness coach that evolves with your needs. And let’s be honest, having an AI that can whip up a workout plan in seconds feels like a superpower, especially when you’re in the gym and need a quick routine on the fly.

Not only that, but I also gave access to all the health information to OpenAI, so my nutrition, workouts, weight, and fat percentage data is available for the AI to use, so it can give me better insights. Of course, due to privacy concerns, I made it optional, and I also added a feature to delete all the data whenever the user wants. But imagine, doing a really hard workout and then asking GPT what it thinks about it, pretty cool, right?

Making it to Google Play

After months of development, testing, and an unhealthy amount of Pepsi Max, Musclog was finally ready for the big stage: Google Play. But here’s where things got… interesting. I was under the impression that I could just submit my app and be done with it, like I did back in 2019 for my game Gotinha. Ha! Little did I know, Google Play forces you to get 20 people to test your app before it goes live, even if you’re just a solo developer. WTF, right?

Musclog on Google Play
Musclog on Google Play

Finding 20 people to test your app sounds easy until you’re actually doing it. I ended up recruiting anyone and everyone—friends, family, co-workers, acquaintances at parties, I might have even asked a few strangers on the street (kidding, maybe). But after gathering my testing “bros” and getting through the initial testing phase, guess what happened? My app got rejected. Yeah, it’s like life just wasn’t ready to let me win.

So there I was, waiting another 14 days, fixing the issues they pointed out, and resubmitting the app. It was a rollercoaster of emotions, to say the least. And as if that wasn’t enough, because I wanted Health Connect integration, but not only that, believe it or not I also needed to have a public website for my app, so I had to create a website for it, and write a privacy policy, and fill out a form explaining why I needed access to Health Connect data. So I quickly spun a website using Next.js and https://v0.dev/, and got GPT to write a privacy policy for me, you can see it here: https://blopa.github.io/musclog-website/.

You might be wondering if I made this app for myself, why do I care to have it on Google Play? Well for one, I think Google Play is quite convenient and I want convenience on installing the app on my phone, and second, I want to share it with my friends and family, and I think it’s easier to share a link to the app on Google Play than to send them an APK file.

But after all the hoops, I finally got the green light, and Musclog was officially on Google Play. So yeah, it wasn’t easy, but it was definitely worth it.

Musclog on Google Play
Musclog on Google Play

To open-source or not to open-source

I always open-source all my projects—it’s kind of my thing. But when it came to Musclog, I hesitated. This app took me over 300 hours to develop, and it has some really nice features that I haven’t seen in other fitness apps. I figured maybe I could recoup some of the time I spent on it by selling it on Google Play or maybe adding a “tip me” button.

To open-source or not
To open-source or not

But once my app was approved and, to be honest, after using it for the past few weeks, I realized that while the features and ideas are cool, the app isn’t as polished as I would like it to be. It dawned on me that maybe Musclog would be better off as an open-source project, where the community could help me improve it—which, to be honest, is also wishful thinking because most open-source projects don’t get much traction and are mainly maintained by the creator, so the best I can hope for is people creating issues and asking for features. Hooray!

Honestly, my dream would be to have an open-source app that somehow makes me money—something like Mindustry or Blender. So, after cleaning up the Git commit history, not because I’m ashamed of my code—okay, maybe a little—but mostly because I wasn’t sure if I had committed an OpenAI key by mistake, I decided to open-source Musclog.

You can check out the code here: https://github.com/blopa/musclog-app. If you’re into fitness and coding, feel free to contribute. Who knows? Maybe together we can turn this into something really special.

What’s Next for Musclog?

Now that Musclog is out in the wild, I’m already thinking about what’s next. There are a ton of features I’d love to add, like more detailed workout analytics, enhanced AI capabilities, and maybe even some social features to share workouts with friends or join challenges.

One “problem” with Musclog is that it’s really an app for advanced lifters, not that I am advanced myself (I am not), but I am crazy about data and tracking, and my app really shines if you’re the type of person who tracks every single rep, set, and calorie. So, I’m thinking about creating a simpler version of the app, with fewer features, or maybe with a better onboarding process, so beginners can use it too, after all, most lifters are beginners, right? I also would like to be able to convince my friends to start working out and using my app, so I need to make it more appealing to them.

Some of the features I’m thinking about adding are:

  • Integration with BLE devices
  • In-app food tracking capabilities
  • More detailed workout analytics
  • Option to use a custom OpenAI model
  • Maybe a local LLM one day
  • Online account to sync data between devices
  • Online profile to share workouts and challenges
  • Gamification features

Conclusion

Looking back, the journey of building Musclog has been as much about personal growth as it has been about coding. I’ve learned so much about mobile development, which is always a good thing. I might be a web developer nowadays, but that’s not how everything started; back in my college days, I was a C++ developer, and web development wasn’t even a track in my course, so kind of coming back to platform development is a nice change of pace.

Just do it!

So, if you’re thinking about starting your own project—whether it’s an app, a website, or something else entirely—my advice is simple: just do it. Embrace the challenges, learn from the setbacks, and enjoy the process. Because at the end of the day, the only thing standing between you and your goals is the decision to take that first step.

Thanks for joining me on this journey, and I can’t wait to see what we build next. Lift, Log, Repeat!

See you in the next one!

PS: If you want to try Musclog, you can download it from Google Play: [https://play.google.com/store/apps/details?id=com.werules.logger).

Side note

I actually wanted to include code snippets and explain how most of the features work, but I realized that it would make this post way too long, so I decided to write a series of posts explaining how I built Musclog, so stay tuned for that!

Tags:


Post a comment

Comments

No comments yet.