From 742ed31671852fd5c726cf2cbabe1fe04f3b7622 Mon Sep 17 00:00:00 2001 From: Josemy Duarte Date: Thu, 21 Mar 2024 21:32:20 +0100 Subject: [PATCH] Add flutter post --- _posts/2024-03-18-first-mobile-app.md | 37 ++++++++++++++++++++++++++ assets/img/flutter-logo.jpg | Bin 0 -> 17987 bytes 2 files changed, 37 insertions(+) create mode 100644 _posts/2024-03-18-first-mobile-app.md create mode 100644 assets/img/flutter-logo.jpg diff --git a/_posts/2024-03-18-first-mobile-app.md b/_posts/2024-03-18-first-mobile-app.md new file mode 100644 index 000000000000..5f956f639117 --- /dev/null +++ b/_posts/2024-03-18-first-mobile-app.md @@ -0,0 +1,37 @@ +--- +layout: post +title: Lessons from My Journey with Flutter Development +subtitle: Metrics, Errors, and State Management +date: 2024-03-18 +image: /assets/img/flutter-logo.jpg +share-img: /assets/img/flutter-logo.jpg +tags: + - flutter + - learning +published: true +--- + +I wanted to build something that I could proudly show to friends and say, "I built this 😎". So, I decided to try [Flutter](https://flutter.dev), a Dart framework that makes it easy to build apps for both iOS and Android. Instead of making a complicated app with lots of fancy features, I wanted to keep it simple. I made an app that uses your device's screen as a flashlight and allows you to change the colors and make it blink in patterns you record with simple taps on your screen. + +At first, I was super excited! Flutter made it easy to make pretty buttons and all kinds of common UI components following established design principles. But then, I had to figure out how to organize the app. I'm not a design expert, so it was tricky deciding where to put things. I just did my best to keep it simple and easy to use, but it made me realize that even though I use all kinds of apps every day, it wasn't straightforward deciding how to design my app. + +In a broad level, I know that intuitive UX is important, but what does that mean? It is a sum of different small decisions, like the type, color, and size of the different fonts used on your app together with the size, position, and color of your app's buttons, among other million things. Definitely, I learnt that UX isn't a trivial thing, but that wasn't the only problem I faced with this project... + +Then came another challenge — keeping track of the settings changed by the user across different screens and updating the UI components accordingly so that the user can see their changes reflected across the app. This is called "state management". Luckily, Flutter has multiple ways to handle it and after a quick modification, I was able to "move" the state across the screens and the UI got updated out of the box by using the [Provider approach](https://docs.flutter.dev/data-and-backend/state-mgmt/simple), which was a nice surprise. I was expecting more struggle to make this work 😅. + +Up to this point, I have learnt a couple of things: + +1. Crafting beautiful UIs is an art and an important aspect to keep your app intuitive. +2. Flutter provides tools that simplify state management and synchronization of your UI components. + +But then after multiple crashes while running the app on the simulator, I wondered how I would know if the app crashed on people's devices once I released it on the app store? I wouldn't be able to add breakpoints to debug or do any other type of deep investigation besides reading their review on the app store which wouldn't be a good one if the app just brings frustration to them. + +I figured it would be nice to have a way for my app to report crashes together with the context in which they happened so that I could reproduce the situation and fix it as soon as it started happening. + +A quick search on the topic and [Firebase Crashlytics](https://firebase.google.com/docs/crashlytics) popped up. It can be used for both iOS and Android and it has an SDK for Flutter so I didn't look further. It allows you to report all crashes and also add context to it, like custom fields from your app or information from the device itself, which proved to be very useful to understand the context in which your app crashed. + +That led me to think on how I could iterate and improve my app. The more you know your audience and their needs, the better you can customize your product to better serve them, right? People usually use [Google Analytics](https://analytics.google.com/) on their websites with this motive. So I was pleased to know that you can use [Google Analytics with Firebase](https://firebase.google.com/docs/analytics) with Flutter really easily. Allowing me to add custom events with all the context I wanted to record. In my case for example, I wanted to know how frequently people would actually use different colors than the default one for their flashlight. That was just adding a custom event for that particular screen and adding the color picked as a custom field. + +You might be wondering where the app is? Well, right in the middle of the development of this app, [Google changed the rules of their app store](https://techcrunch.com/2023/11/09/google-play-tightens-up-rules-for-android-app-developers-to-require-testing-increased-app-review/). Now, releasing your app on the store required not only paying [the developer's fee](https://support.google.com/googleplay/android-developer/answer/6112435?hl=en#zippy=%2Cstep-pay-registration-fee) but also getting 20 testers for your app before it can be officially released. + +I understand Google's intention is to increase the quality of the apps published on their store, which is great, but since I already had the app on my phone, I felt I had already gotten what I wanted from this journey — being able to show my friends "I built this 😎". Not only that, but I also learned a lot while doing it, so I didn't feel the need to go through that process. \ No newline at end of file diff --git a/assets/img/flutter-logo.jpg b/assets/img/flutter-logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7d9ff9535ec8d48f87459b50f2cd502d4ffb43ea GIT binary patch literal 17987 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