Introduction
If you have ever worked in Android development, one of the first things you might have encountered is the dependencies section in the app gradle file. This section is used to add new dependencies or third-party features to projects, ranging from support for a new type of widget to incorporating fundamental elements like RoomDB.
But have you ever paused to ponder how these dependencies function? Or, even more fundamentally, how are they created in the first place? In this series, we aim to unravel the answers to these questions.
Why to Create a Library?
Let's try to explore a use case to better understand why we need to create a library in the first place.
Problem Statement
Imagine undertaking a project where you are required to offer users multiple functionalities across different flavors. For instance, some users might necessitate a payment gateway, while others may prefer an authentication window or a chatbot. Moreover, users can also request combinations of these features.
Given that each feature can encompass a substantial amount of code and dependencies, it becomes prudent to supply each flavor with only the requisite code. This means a project devoid of authentication should not harbor any codebase from the authentication feature.
Surprisingly, even with just three features, we can forge seven distinct combinations of apps, leading to a complex scenario, especially when a bug is discovered in one of the features in one of the apps. Addressing this bug implies potentially patching it across seven different app combinations, a task that becomes exponentially cumbersome with an increase in the number of features.
ChatBot | Authentication | Payment Gateway | ||
Flavor A | ✅ | ❌ | ❌ | |
Flavor B | ❌ | ✅ | ❌ | |
Flavor C | ❌ | ❌ | ✅ | |
Flavor D | ✅ | ✅ | ❌ | |
Flavor E | ❌ | ✅ | ✅ | |
Flavor F | ✅ | ❌ | ✅ | |
Flavor G | ✅ | ✅ | ✅ |
This is where things get interesting!
Now imagine that we find a bug in one of these features in one of the apps.
Let's say that we find a solution for this bug, and we resolve it. Now we have seven different combinations of apps that might need the same patch as well!
And this is just the case when we have 3 features, imagine having 10 features, and you'll realize why this could create a lot of mess.
The bug fix can have a lot of changes into the code, and resolving the bug in each app would mean making the same changes across dozens of app codebases.
These apps might be maintained by different coders, across different teams which means, that now they need to understand where to patch this code, and how to test it.
Even if all of this works well, we still have the problem of version control, i.e. if we forget to update this code in just on the app combinations, it'd get progressively difficult to track this.
Solution
What if we could encapsulate each feature in our project into a bundle or a "zip" folder? This approach would mean that patching the code would simply involve replacing the existing "zip" folder of the feature with a new one containing the fixed code. This strategy effectively addresses our challenges by:
Facilitating easier updates through a single zip folder, obviating the need for hundreds of small changes in multiple files.
Transforming the feature into a black box for different teams, who can replace it without delving into its internal code mechanisms.
Enabling efficient tracking of releases through folder renaming or version naming.
In Android Terms
In Android, this "zip" file manifests as either a "JAR" or an "AAR" file. We will explore these file types and their creation in the subsequent post of this series. To streamline the creation and maintenance of these "zip" folders, we leverage hosted repositories such as Maven Central, JCenter, or Google's Maven repository.
When you sync your project with the Gradle files (an action you can perform in Android Studio), Gradle will:
Download Dependencies: Gradle connects to the specified repositories to download the necessary files (usually
.jar
or.aar
files).Cache Dependencies: To avoid downloading the dependencies every time you build your project, Gradle caches them locally.
Resolve Conflicts: If there are version conflicts between different dependencies, Gradle will try to resolve them automatically, usually by using the newest compatible version.
What Next?
While the actual process of crafting a new library in Android is relatively straightforward, understanding the necessity of creating these libraries and grasping the underlying design and architectural principles hold paramount importance.
In the forthcoming blog posts, we will guide you in creating a simple library, followed by a deep dive into the essential design principles to bear in mind during the creation process.
Conclusion
Embarking on the journey of creating your own library in Android not only elevates the efficiency of your project but also fosters a deeper understanding of the Android ecosystem. As we step into this exciting venture, we encourage you to keep a curious mind and a keen eye on the intricate details that go into building a robust and functional library. Stay tuned as we unravel the nuances of library creation, setting a strong foundation for you to build libraries that stand the test of time and technological advancements.