Authored by:
Over the years, developers have struggled with cross-platform development. With the evolution of the mobile industry, it became imperative that any popular application in the market needs to be available on the most popular platforms (i.e. Android and iOS). But due to significant differences in the overall design and architecture of these platforms, it was really difficult to use a common technology that can create applications for both.
In most cases, developers reject cross-platform development and propose native development instead, as Xamarin, React Native, Ionic and other cross-platform frameworks have more drawbacks than benefits - be it animation customization or support of all android devices and operational systems. On top of that, if developers are able to make two versions of the same application, their look and feel is not consistent. This happens due to the differences in the internal libraries for these platforms.
Then came Flutter and it changed the game.
Native apps are software applications that are used in a platform. The programming language of native apps are based on the platform. It is designed specifically for operating systems. So whatever the hardware and software that the O/S uses, will be used by native apps too.
The overall cost involved in the development and maintenance of a native app is considerably higher. This is due to the fact that there should be separate versions of the same application. A substantial amount is needed to maintain the app. But still, native apps are cost effective in the long run.
Developing a native app is a complex process since separate developers are needed for each platform. For example, different developers must be hired to develop Android and IOS versions of the same application. Moreover, it is not an easy task to develop native apps. It is incorporated with tough challenges, as the app needs to be up-to-date and compliant with the latest changes in both platforms.
Since native apps are developed for multiple platforms, it requires more time. Native apps may require a significant amount of creation time compared to their counterparts. Developers of native apps have to take time to write codes for specific O/S, and a significant portion of time is often dedicated to make the look and feel consistent for applications designed for both platforms.
Developers often come up with new updates in native apps for various reasons - most often for fixing bugs and glitches. Hence, necessary updates need to be implemented in the app store so that users will be able to download them. Now the problem comes if the user isn't aware of such updates or skips them to save storage space.
Flutter is an open-source project hosted on GitHub with contributions from Google and the community. Flutter uses Dart, a modern object-oriented language that compiles to native ARM code and production-ready JavaScript code.
Flutter - a simple and high performance framework based on Dart language, provides high performance by rendering the UI directly in the operating system’s canvas rather than through native framework. This ensures that the application’s look and feel remains consistent irrespective of the platform, as the application is directly being plotted and created at the pixel level.
We know that essentially any cross-platform framework provides a way to share codebase between the target platforms. But there are no such application frameworks that allow sharing both the UI code and the UI itself, besides Flutter.
Flutter’s “hot reload” feature, in turn, allows seeing the applied changes almost instantly, without even losing the current application state. And this is exactly what makes Flutter app development several times faster due to the increased development speed. The way this feature works is that in case of hot reload, it preserves the parent widget tree to ensure that only the code that has been modified is getting changed.
This one is pretty straightforward. Flutter development framework functions quicker than its alternatives. In most cases, you can expect a Flutter app to require at least two times fewer man-hours compared to the same app developed separately for Android and iOS. The main reason is simple: you don’t have to write any platform-specific code to achieve the desired visuals in your application. Any 2D-based UI can be implemented in Flutter without interacting with a native application counterpart.
One of the biggest advantages of Flutter is the ability to customize anything you see on the screen, regardless of how complex it may be. While it’s usually possible to do a very custom UI on native platforms as well, the amount of effort required differs by the order of magnitude. Here’s an example of such a simple, yet custom UI.
Firebase is an app development platform that helps you build and grow apps and games users love, backed by Google and trusted by millions of businesses around the world.
Let’s add Firebase to your Flutter application…
1. Create a Firebase project
Assuming you’ve already created your account for Firebase and are logged in, click on the get started icon -> Add Firebase to your project. Go with the flow and provide the necessary information to create your first project with Firebase.
2. Register your app with Firebase
3. Add Firebase configuration file
4. Add Firebase plugins
Flutter uses plugins to provide access to a wide range of platform-specific services, such as Firebase APIs. Plugins include platform-specific code to access services and APIs on each platform.
Firebase is accessed through a number of different libraries, one for each Firebase product (for example: Realtime Database, Authentication, Analytics, or Storage). Flutter provides a set of Firebase plugins, which are collectively called FlutterFire.
Since Flutter is a multi-platform SDK, each FlutterFire plugin is applicable for both iOS and Android. So if you add any FlutterFire plugin to your Flutter app, it will be used by both the iOS and Android versions of your Firebase app.
Adding the FlutterFire plugin, step-by-step
For our use case here, we are building an app with Flutter and integrating it with Firebase in the backend for Authentication and Firebase Realtime Database.
Add Firebase Authentication to your app
To use an authentication provider, you need to enable it in the Firebase console. Go to the Sign-in Method page in the Firebase Authentication section to enable Email/Password sign-in and any other identity providers you want for your app.
Before talking about how your app authenticates users, let's introduce a set of tools you can use to prototype and test Authentication functionality: Firebase Local Emulator Suite. If you're deciding among authentication techniques and providers, trying out different data models with public and private data using Authentication and Firebase Security Rules, or prototyping sign-in UI designs, being able to work locally without deploying live services can be a great idea.
The second part is trickier. Firebase provides two database options: Cloud Firestore and Realtime Database. For our use case, both are legitimate options. It depends on the need to handle big amounts of data or even perform queries on it, so here we are going with Realtime Database. But Cloud Firestore would also work just fine, and you might as well use it for other upcoming features. To decide for yourself what will suit you better, Google provides a test, so you can test it for your application yourself.
The Realtime Database - yes, it’s a NoSQL database (as well as Cloud Firestore) - has its implications. So if you’re looking into the direction of any Firebase data store, you need to keep that in mind. Even though some of our models are quite complex, they don’t have many relations between them. They can also be flattened into simple JSON types like the one below, for example.
We will follow the Clean Architecture principles in our module structure (presentation / data / domain). So if we ever want to move on from Firebase, we can plug in a new data module and be done with it.
In the presentation layer, we use the BloC pattern via this library, usually a bloc-per-page structure.
BLoC stands for Business Logic Components. The gist of BLoC is that everything in the app should be represented as a stream of events: widgets submit events, and other widgets will respond. BLoC sits in the middle, managing the conversation. Dart even comes with syntax for working with streams baked into the language.The bloc shouldn’t know anything about the UI and the widget should be as business logic agnostic as possible. If you don’t know what BloC is yet, we highly recommend reading about it here.
Our users can start their projects from the app and track their progress. To do that, we save the pattern details and the user's progress into a local database. One of the future features can be to also synchronize this data with the backend so that users can continue their progress on another device, but that’s not yet implemented.
This was also a no-brainer because the Bitrise + Firebase App Distribution works for all apps, and it works like a charm. The Firebase App Distribution part has no problems. Gitlab is an absolutely amazing and highly customizable CI tool.
GitLab CI/CD pipelines are configured using a YAML file .gitlab-ci.yml in the root of the project folder. There are different stages in the pipeline but the two most important stages are the Build and Test & Deploy stages, which can be seen above.
Because testing new patterns straight on production isn’t a very clever or user-friendly idea, we should make different flavors of our app before releasing it to the users.
Even though flavors on Android and iOS are pretty standard, the same thing can’t be said about Flutter.
Flavors are so amazing. Just like how ice cream has different flavors and everyone loves them, your application may have different flavors too! By using flavors, you can create different versions of your app, meaning you can generate different versions or variants of your app using a single code-base.
They are just comfortable. They let you define some build configuration and switch them as you want. For example, you could have one flavor for development, and one for production. You can set different URLs for API calls or different icons and app names. With a click you’re ready to develop or to release your great application.
Overall, these limitations are not too major to prevent the developers from using flavoring with Flutter.