<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rosário P. Fernandes</title>
    <description>The latest articles on DEV Community by Rosário P. Fernandes (@thatfiredev).</description>
    <link>https://dev.to/thatfiredev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F141179%2Fe66f8799-27ac-4fdb-871e-5f2f9354ec5a.jpg</url>
      <title>DEV Community: Rosário P. Fernandes</title>
      <link>https://dev.to/thatfiredev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thatfiredev"/>
    <language>en</language>
    <item>
      <title>A GitHub Action to Build Modular Android Projects</title>
      <dc:creator>Rosário P. Fernandes</dc:creator>
      <pubDate>Thu, 17 Sep 2020 20:01:36 +0000</pubDate>
      <link>https://dev.to/thatfiredev/a-github-action-to-build-modular-android-projects-5hd2</link>
      <guid>https://dev.to/thatfiredev/a-github-action-to-build-modular-android-projects-5hd2</guid>
      <description>&lt;h3&gt;
  
  
  My Workflow
&lt;/h3&gt;

&lt;p&gt;As most Android Developers know, an &lt;a href="https://developer.android.com/studio/projects" rel="noopener noreferrer"&gt;Android Project&lt;/a&gt; may have many&lt;br&gt;
 different modules.&lt;/p&gt;

&lt;p&gt;If you change one single module and submit a Pull Request, most CI workflows will try to build/test all the existing modules, which might take a lot of time, when in reality you only need to build the module you changed.&lt;/p&gt;

&lt;p&gt;This GitHub Action aims to solve that problem. When you submit a Pull Request, it will only build the module you changed,or no module at all if you left them untouched (in case of documentation or configuration changes).&lt;/p&gt;
&lt;h4&gt;
  
  
  Real Project Showcase
&lt;/h4&gt;

&lt;p&gt;Take a look at this project I forked: &lt;a href="https://github.com/rosariopfernandes/quickstart-android" rel="noopener noreferrer"&gt;quickstart-android&lt;/a&gt;. It contains many different modules (admob, analytics, database, etc).&lt;/p&gt;

&lt;p&gt;I made a change to the database module and sent a Pull Request:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/rosariopfernandes/quickstart-android/pull/11" rel="noopener noreferrer"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        refactor(database): make a demo change for the Github Actions Hackathon
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#11&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/rosariopfernandes" rel="noopener noreferrer"&gt;
        &lt;img class="github-liquid-tag-img" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Favatars1.githubusercontent.com%2Fu%2F16766726%3Fv%3D4" alt="rosariopfernandes avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/rosariopfernandes" rel="noopener noreferrer"&gt;rosariopfernandes&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/rosariopfernandes/quickstart-android/pull/11" rel="noopener noreferrer"&gt;&lt;time&gt;Sep 17, 2020&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;I'm hoping that this PR will only build the &lt;code&gt;database&lt;/code&gt; module, since that's the only change I made.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/rosariopfernandes/quickstart-android/pull/11" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;GitHub Actions built the &lt;code&gt;database&lt;/code&gt; module only and finished in 4m 40s, as seen in the &lt;a href="https://github.com/rosariopfernandes/quickstart-android/runs/1130510216?check_suite_focus=true" rel="noopener noreferrer"&gt;log&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Building the whole project generally takes around 17min, as seen in this &lt;a href="https://github.com/rosariopfernandes/quickstart-android/pull/11/checks?check_run_id=1130502965" rel="noopener noreferrer"&gt;log&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Submission Category:
&lt;/h3&gt;

&lt;p&gt;Phone Friendly&lt;/p&gt;

&lt;h3&gt;
  
  
  Yaml File or Link to Code
&lt;/h3&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/thatfiredev" rel="noopener noreferrer"&gt;
        thatfiredev
      &lt;/a&gt; / &lt;a href="https://github.com/thatfiredev/modular-android-action" rel="noopener noreferrer"&gt;
        modular-android-action
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      GitHub Actions to selectively build PRs on multi-module Android Projects
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Github Actions for Modular Android Projects&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;As most Android Developers know, an &lt;a href="https://developer.android.com/studio/projects" rel="nofollow noopener noreferrer"&gt;Android Project&lt;/a&gt; may have many
different modules.&lt;/p&gt;
&lt;p&gt;If you change one single module and submit a Pull Request, most CI workflows will try to build/test all the
existing modules, which might take a lot of time, when in reality you only need to build the module you changed.&lt;/p&gt;
&lt;p&gt;This GitHub Action aims to solve that problem. When you submit a Pull Request, it will only build the module you changed
or no module at all if you left them untouched (in case of documentation or configuration changes).&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Add it to your workflow YAML like this:&lt;/p&gt;
&lt;div class="highlight highlight-source-yaml notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;    - &lt;span class="pl-ent"&gt;name&lt;/span&gt;: &lt;span class="pl-s"&gt;Build with Modular Action&lt;/span&gt;
      &lt;span class="pl-ent"&gt;uses&lt;/span&gt;: &lt;span class="pl-s"&gt;rosariopfernandes/modular-android-action@v0.2.0&lt;/span&gt;
      &lt;span class="pl-ent"&gt;with&lt;/span&gt;:
        &lt;span class="pl-ent"&gt;for-each-module&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;assembleDebug&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt;
        &lt;span class="pl-ent"&gt;for-all-modules&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;check&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;As you can see, it takes 2 arguments:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;for-each-module&lt;/code&gt; - gradle task to run for each module.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;for-all-modules&lt;/code&gt; - gradle…&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/thatfiredev/modular-android-action" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Additional Resources / Info
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Inspired by the blog post &lt;a href="https://overflow.buffer.com/2019/12/20/selectively-running-android-modularized-unit-tests-on-your-ci-server/" rel="noopener noreferrer"&gt;"Selectively running Android modularized unit tests on your CI server"&lt;/a&gt; by &lt;a href="https://twitter.com/hitherejoe" rel="noopener noreferrer"&gt;Joe Birch&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;I've previously written a &lt;a href="https://dev.to/rosariopfernandes/run-android-modularized-builds-selectively-on-github-actions-4jp1/"&gt;blog post&lt;/a&gt; describing how I adapted Joe's code for GitHub Actions.&lt;/li&gt;
&lt;li&gt;The Projects bellow are already using this workflow:

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/firebase/quickstart-android/" rel="noopener noreferrer"&gt;firebase/quickstart-android&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/firebase/snippets-android/" rel="noopener noreferrer"&gt;firebase/snippets-android&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>actionshackathon</category>
      <category>github</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Run Android modularized builds selectively on GitHub Actions</title>
      <dc:creator>Rosário P. Fernandes</dc:creator>
      <pubDate>Thu, 09 Apr 2020 18:01:52 +0000</pubDate>
      <link>https://dev.to/rosariopfernandes/run-android-modularized-builds-selectively-on-github-actions-4jp1</link>
      <guid>https://dev.to/rosariopfernandes/run-android-modularized-builds-selectively-on-github-actions-4jp1</guid>
      <description>&lt;p&gt;&lt;em&gt;Header Photo by &lt;a href="https://unsplash.com/@bradneathery"&gt;Brad Neathery&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/nPy0X4xew60"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; I've improved Android build times on GitHub Actions for Pull Requests from ~17min down to ~5min using &lt;a href="https://gist.github.com/rosariopfernandes/e9529aa9b96aadc11adf43e08db82490"&gt;this&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A few months ago I read this great post &lt;a href="https://overflow.buffer.com/2019/12/20/selectively-running-android-modularized-unit-tests-on-your-ci-server/"&gt;"Selectively running Android modularized unit tests on your CI server"&lt;/a&gt;, where &lt;a href="https://twitter.com/hitherejoe"&gt;Joe Birch&lt;/a&gt; describes some of the tips and tricks he used to implement a CI Workflow that selectively runs unit tests on a modularized Android Project. This week I had some free time and decided to try implementing a similar workflow on a project that I've been contributing to (&lt;a href="https://github.com/firebase/quickstart-android"&gt;firebase/quickstart-android&lt;/a&gt;). So in this post I've decided to share the challenges I faced while doing it and some of the workarounds.&lt;/p&gt;

&lt;p&gt;Before we get started, let me walk you through some of the basics of it all to make sure you're familiarized with the concepts described here. If this post's title was 100% clear for you, you can go ahead and skip to Current Scenario section.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Basics
&lt;/h1&gt;

&lt;h3&gt;
  
  
  1. Modularized Android?
&lt;/h3&gt;

&lt;p&gt;If you're an Android Developer, you (probably) already know that an Android Studio Project can be divided into &lt;a href="https://developer.android.com/studio/projects#ApplicationModules"&gt;modules&lt;/a&gt;. This allows developers to create different apps for the same Project. For example, if I'm building a "Health Tracking" app, I could split it into different modules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;app&lt;/code&gt; - this is usually created by default when you select "new Android App" on Android Studio. This module is the Android app for phones/tablets;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;wear&lt;/code&gt; - let's suppose we also want our app to work on &lt;a href="https://developer.android.com/training/wearables/apps"&gt;Android Wear&lt;/a&gt; devices. We can build that app in this separate module;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;lite&lt;/code&gt; - let's say we have a different version of the app which uses less resources and is meant for Android devices with low-processing power.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're not yet familiar with Modules, I recommend checking the &lt;a href="https://developer.android.com/studio/projects#ApplicationModules"&gt;Android Documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. GitHub Actions?
&lt;/h3&gt;

&lt;p&gt;Now before we get into this, you should first understand the concept of Continuous Integration. I really like &lt;a href="https://www.atlassian.com/continuous-delivery/continuous-integration"&gt;this definition&lt;/a&gt; by Atlassian:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Continuous integration (CI) is the practice of automating the integration of code changes from multiple contributors into a single software project. The CI process is comprised of automatic tools that assert the new code’s correctness before integration.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Putting it in simple words: let's say we have a project stored on GitHub and many contributors. Before accepting any contribution, we want to make sure that this contribution will not break our code, and for that we can use Automatic CI Tools which will try to build the new code and then tell us if it breaks our current code or not.&lt;/p&gt;

&lt;p&gt;Particularly, I've been working with tools such as &lt;a href="https://travis-ci.org/"&gt;Travis CI&lt;/a&gt; and &lt;a href="https://circleci.com/"&gt;CircleCI&lt;/a&gt;. But recently, GitHub introduced &lt;a href="https://github.com/features/actions"&gt;GitHub Actions&lt;/a&gt; - another automated CI tool. This came as great news for some developers, since this means they can have their source code and their CI on one and only platform: GitHub. No need to share the code with any other 3rd party CI tools.&lt;/p&gt;

&lt;h1&gt;
  
  
  Current Scenario
&lt;/h1&gt;

&lt;p&gt;As I've mentioned in the beginning of the post, I've been contributing to &lt;a href="https://github.com/firebase/quickstart-android"&gt;firebase/quickstart-android&lt;/a&gt;. This Open Source project is basically a collection of Android sample apps that aim to demonstrate developers how to use the &lt;a href="https://firebase.google.com"&gt;Firebase&lt;/a&gt; APIs. Because Firebase provides many different services, the project has been divided into modules (one for each Firebase Service).&lt;br&gt;
At the time I wrote this post, it had 18 different modules and building the whole project on GitHub Actions would take around 17min (average).&lt;br&gt;
So whenever someone sent a contribution to the project, they'd have to wait for around 17 minutes before they could find out whether their contribution breaks the project or not.&lt;/p&gt;

&lt;p&gt;This may be "unfair" at times when someone has implemented changes in a single module and has to wait for GitHub Actions to build all the other unchanged modules. Or even worse: when someone doesn't change any code at all, because their changes were made on the project's documentation (E.g. README.md, LICENSE, etc), but will still have to wait for the project to build. And Joe's post tries to show how to reduce CI time in such cases.&lt;/p&gt;
&lt;h1&gt;
  
  
  NEED FOR SPEED!!!
&lt;/h1&gt;

&lt;p&gt;So what Joe proposes is: instead of testing the whole project (done with &lt;code&gt;gradlew testDebugUnitTest&lt;/code&gt;), we could simply test the changed modules only (with &lt;code&gt;gradlew :moduleA:testDebugUnitTest :moduleB:testDebugUnitTest&lt;/code&gt;) which might be a lot faster.&lt;/p&gt;

&lt;p&gt;Now in my scenario, the project doesn't really have any tests and what the CI does is basically check if the project builds successfully and if there are no lint issues(&lt;code&gt;gradlew clean ktlint build&lt;/code&gt;). &lt;br&gt;
For Pull Requests I've decided to only build the &lt;a href="https://developer.android.com/studio/build/build-variants"&gt;debug variant&lt;/a&gt; of the changed module (&lt;code&gt;gradlew clean ktlint :module:assembleDebug :module:check&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Doing this should be easy, right? I could simply copy Joe's code. But as it turned out, it was not that straight forward. Mainly because he uses a different CI Environment (&lt;a href="https://www.bitrise.io/"&gt;Bitrise&lt;/a&gt;) and some of his code was not running correctly on GitHub Actions.&lt;br&gt;
So let's have a look at what my code looks like and I'll explain the changes I made.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Find out which modules were changed
&lt;/h3&gt;

&lt;p&gt;In order to find the changed modules, he uses &lt;code&gt;git diff&lt;/code&gt; with a while loop in a &lt;a href="https://opensource.com/article/18/8/introduction-pipes-linux"&gt;pipe&lt;/a&gt; to read the command's output. I've tested this on my local terminal (zsh) and it works fine. But GitHub Actions uses the bash terminal, and bash was not so happy with that pipe. So I had to rewrite the while loop in the main shell, as suggested &lt;a href="https://stackoverflow.com/a/16854326/5861618"&gt;here&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# build_pull_request.sh&lt;/span&gt;
&lt;span class="c"&gt;# Get all the modules that were changed&lt;/span&gt;
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read &lt;/span&gt;line&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nv"&gt;module_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;line&lt;/span&gt;&lt;span class="p"&gt;%%/*&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="c"&gt;# This gets the first word before '/'&lt;/span&gt;
  &lt;span class="c"&gt;# Now we check if we haven't already added this module&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MODULES&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;module_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nv"&gt;MODULES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MODULES&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;module_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="c"&gt;# string concat&lt;/span&gt;
  &lt;span class="k"&gt;fi
done&lt;/span&gt; &amp;lt; &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;git diff &lt;span class="nt"&gt;--name-only&lt;/span&gt; origin/&lt;span class="nv"&gt;$GITHUB_BASE_REF&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Notice that we're using an &lt;a href="https://en.wikipedia.org/wiki/Environment_variable"&gt;env variable&lt;/a&gt; from GitHub Actions: &lt;code&gt;$GITHUB_BASE_REF&lt;/code&gt; - this contains the name of the branch where our Pull Request is supposed to be merged into (generally the &lt;code&gt;master&lt;/code&gt; branch).&lt;/p&gt;

&lt;p&gt;After pushing this, it still wouldn't work. It would show an error, saying it couldn't find the branch I had specified (&lt;code&gt;$GITHUB_BASE_REF&lt;/code&gt;) and that's because GitHub Actions pulls our code to their CI machine using a &lt;a href="https://linuxhint.com/git-shallow-clone-and-clone-depth/"&gt;shallow clone&lt;/a&gt;, therefore the branches were not being fetched. So in order to fix this, we have to unshallow and fetch the branches before running &lt;code&gt;git diff&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# build_pull_request.sh&lt;/span&gt;
git fetch &lt;span class="nt"&gt;--unshallow&lt;/span&gt;
git fetch origin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Check if the changed files belong to any module
&lt;/h3&gt;

&lt;p&gt;Now this is not very different from Joe's script, with a few exceptions, since I adapted it for my own scenario:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# build_pull_request.sh&lt;/span&gt;
&lt;span class="c"&gt;# Get a list of all available gradle tasks&lt;/span&gt;
&lt;span class="nv"&gt;AVAILABLE_TASKS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;./gradlew tasks &lt;span class="nt"&gt;--all&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Check if that list contains the modules that were changed&lt;/span&gt;
&lt;span class="nv"&gt;build_commands&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;module &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;$changed_modules&lt;/span&gt;
&lt;span class="k"&gt;do
  if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$AVAILABLE_TASKS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;~ &lt;span class="nv"&gt;$module&lt;/span&gt;&lt;span class="s2"&gt;":app:"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nv"&gt;build_commands&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;build_commands&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" :"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;module&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;":app:assembleDebug :"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;module&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;":app:check"&lt;/span&gt;
  &lt;span class="k"&gt;fi
done&lt;/span&gt;

&lt;span class="c"&gt;# Build the Pull Request&lt;/span&gt;
&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"./gradlew clean ktlint &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;build_commands&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Notice that if no module was changed, the &lt;code&gt;build_commands&lt;/code&gt; variable will be empty and CI will only run &lt;code&gt;gradlew clean ktlint&lt;/code&gt;.&lt;br&gt;
Now we can save our file as &lt;code&gt;build_pull_request.sh&lt;/code&gt; and change it's permission so that it can be executed: &lt;code&gt;chmod +x build_pull_request.sh&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  How will GitHub Actions know whether it's a Pull Request?
&lt;/h3&gt;

&lt;p&gt;That's the easiest part. We can add conditions to our workflow config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/android.yml&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Android CI&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pull_request&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;push&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;set up JDK &lt;/span&gt;&lt;span class="m"&gt;1.8&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-java@v1&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;java-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.8&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build with Gradle (Pull Request)&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./build_pull_request.sh&lt;/span&gt;
      &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.event_name == 'pull_request'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build with Gradle (Push)&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./gradlew clean ktlint build&lt;/span&gt;
      &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.event_name != 'pull_request'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And that's it! One &lt;code&gt;git commit&lt;/code&gt; and a &lt;code&gt;git push&lt;/code&gt; and you should see CI times faster than Lightning McQueen.&lt;/p&gt;

&lt;h1&gt;
  
  
  Final Considerations
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;After implementing this change, CI times in &lt;a href="https://github.com/firebase/quickstart-android"&gt;quickstart-android&lt;/a&gt; PRs dropped from ~17min to ~5min. While this may seem like it's only 12 minutes, it actually adds up to days, weeks or months on the long run. It also means that the CI Server will be freed quicker, allowing other contributions on different repositories of the same organization to use the CI.&lt;/li&gt;
&lt;li&gt;The full script and workflow config file is available on &lt;a href="https://gist.github.com/rosariopfernandes/e9529aa9b96aadc11adf43e08db82490"&gt;Gist&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Please note that this code only works if all modules are independent. So if you have moduleA dependending on moduleB and you make changes to moduleB, then moduleA might break and not be tested.&lt;/li&gt;
&lt;li&gt;If you're new to Continuous Integration, I'd also recommend reading about &lt;a href="https://www.atlassian.com/continuous-delivery/continuous-deployment"&gt;Continuous Delivery&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;I hope this helps you improve build times in your CI Environment. If you plan on trying out anything I've mentioned here, leave a comment bellow or reach out to me on Twitter(&lt;a href="//twitter.com/_rpfernandes"&gt;@_rpfernandes&lt;/a&gt;) and I'll be happy to have a chat about it.&lt;/p&gt;

</description>
      <category>android</category>
      <category>githubactions</category>
      <category>ci</category>
      <category>gradle</category>
    </item>
    <item>
      <title>Using Kotlin Extension Functions and Coroutines with Firebase</title>
      <dc:creator>Rosário P. Fernandes</dc:creator>
      <pubDate>Tue, 09 Apr 2019 08:58:53 +0000</pubDate>
      <link>https://dev.to/thatfiredev/using-kotlin-extension-functions-and-coroutines-with-firebase-j0k</link>
      <guid>https://dev.to/thatfiredev/using-kotlin-extension-functions-and-coroutines-with-firebase-j0k</guid>
      <description>&lt;p&gt;&lt;em&gt;Portuguese Version available on &lt;a href="https://developingwith.firebaseapp.com/Kotlin-Features-Firebase/" rel="noopener noreferrer"&gt;developingwith.firebaseapp.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The simpler the code, the faster you'll understand it." - &lt;br&gt;
&lt;a href="https://medium.com/@pauloenoque2014" rel="noopener noreferrer"&gt;Paulo Enoque&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Kotlin's simplicity and concision are the main reason why developers have been adopting this language for their work.&lt;br&gt;
I must also remind you that, in May 2017, Google announced that Kotlin became an official language for Android App Development. Ever since then, the number of Kotlin developers has been increasing.&lt;/p&gt;



&lt;p&gt;A year and a half after Kotlin became the official language for Android Development, Firebase added this language to their &lt;a href="https://firebase.google.com/docs" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt; :&lt;/p&gt;

&lt;blockquote data-lang="en"&gt;
&lt;p&gt;&lt;a href="https://twitter.com/Firebase?ref_src=twsrc%5Etfw" rel="noopener noreferrer"&gt;@Firebase&lt;/a&gt; code samples for Android are starting to get &lt;a href="https://twitter.com/kotlin?ref_src=twsrc%5Etfw" rel="noopener noreferrer"&gt;@kotlin&lt;/a&gt; samples to go with Java! Thanks to @daggerdwivedi and &lt;a href="https://twitter.com/_rpfernandes?ref_src=twsrc%5Etfw" rel="noopener noreferrer"&gt;@_rpfernandes&lt;/a&gt; for the assists here. It's a tremendous effort overall, and it's great to have help from the community.&lt;a href="https://t.co/PMlAViMf9F" rel="noopener noreferrer"&gt;https://t.co/PMlAViMf9F&lt;/a&gt;&lt;a href="https://twitter.com/hashtag/AndroidDev?src=hash&amp;amp;ref_src=twsrc%5Etfw" rel="noopener noreferrer"&gt;#AndroidDev&lt;/a&gt; &lt;a href="https://t.co/W386VlM3HC" rel="noopener noreferrer"&gt;pic.twitter.com/W386VlM3HC&lt;/a&gt;&lt;/p&gt;— Doug Stevenson 🔥 (@CodingDoug) &lt;a href="https://twitter.com/CodingDoug/status/1050473809994629120?ref_src=twsrc%5Etfw" rel="noopener noreferrer"&gt;October 11, 2018&lt;/a&gt;
&lt;/blockquote&gt;



&lt;p&gt;But I must agree with the popular saying "Better late than never". This change brought many improvements to the platform:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Java code on the &lt;a href="https://github.com/firebase/firebase-android-sdk" rel="noopener noreferrer"&gt;Firebase Android SDK&lt;/a&gt; was improved for better interoperability with Kotlin;&lt;/li&gt;
&lt;li&gt;"Extension Functions" were created to make the use of the Android SDK more concise;&lt;/li&gt;
&lt;li&gt;Some developers created libraries to improve the way Firebase is used with Kotlin, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I  decided to create a library to help people use Firebase in Kotlin, it was called &lt;a href="https://github.com/rosariopfernandes/fireXtensions" rel="noopener noreferrer"&gt;fireXtensions&lt;/a&gt; (now deprecated) and it used to provide some &lt;strong&gt;Extension Functions&lt;/strong&gt; for the Firebase Android SDK.&lt;/p&gt;
&lt;h1&gt;
  
  
  Kotlin Extension Functions
&lt;/h1&gt;

&lt;p&gt;Putting it short, Extension Functions are a Kotlin feature that allows you to add new methods/functions to a class, even if this class was not created by you. No need to implement the class nor extend it.&lt;/p&gt;

&lt;p&gt;After adding Kotlin to their Official Documentation, the Firebase Team has also added a few Extension Functions to their Android SDK (thus deprecating fireXtensions).&lt;/p&gt;

&lt;p&gt;The first extensions were the libraries &lt;strong&gt;Common KTX&lt;/strong&gt; and &lt;strong&gt;Firestore KTX&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Common KTX
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;firebase-common-ktx&lt;/code&gt; module contains extension functions used to obtain the Firebase Instance. If you've ever worked with Firebase (either in Java or Kotlin), you're probably familiarized with the method/function &lt;code&gt;FirebaseApp.getInstance()&lt;/code&gt;. If you use the &lt;code&gt;firebase-common-ktx&lt;/code&gt; module, calling this method gets easier: &lt;code&gt;Firebase.app&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In order to use this module, make sure you have the Kotlin Plugin 1.3.20 or higher on your &lt;code&gt;build.gradle(project)&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;classpath&lt;/span&gt; &lt;span class="s2"&gt;"org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.20"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then add the following dependency to your &lt;code&gt;build.gradle(app)&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... Other dependencies ...&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'com.google.firebase:firebase-common-ktx:16.1.0'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See the full list of &lt;a href="https://firebaseopensource.com/projects/firebase/firebase-android-sdk/docs/ktx/common.md/" rel="noopener noreferrer"&gt;available extension functions&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Firestore KTX
&lt;/h2&gt;

&lt;p&gt;As the name suggests, this module contains extensions that simplify the way you use the Firestore Android SDK. This module can be added to your project the same way we did with Common KTX, but using this dependency instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... Other dependencies ...&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'com.google.firebase:firebase-firestore-ktx:18.2.0'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See the full list of &lt;a href="https://firebaseopensource.com/projects/firebase/firebase-android-sdk/docs/ktx/firestore.md/" rel="noopener noreferrer"&gt;available extension functions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Note that when using the &lt;code&gt;firebase-firestore-ktx&lt;/code&gt; dependency, you no longer need to use &lt;code&gt;com.google.firebase:firebase-firestore&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Although these are currently the only available modules, I'm pretty sure more modules will be added to their SDK. I'll update this post every time a new module is added.&lt;/p&gt;

&lt;h1&gt;
  
  
  Kotlin Coroutines
&lt;/h1&gt;

&lt;p&gt;As you might already know, &lt;a href="https://medium.com/google-developers/why-are-firebase-apis-asynchronous-callbacks-promises-tasks-e037a6654a93" rel="noopener noreferrer"&gt;Firebase APIs are asynchronous&lt;/a&gt;, forcing us to use listeners in our code to read data from our database. And programmers often try to (wrongly) read data without listeners, or try to use the data outside those listeners, like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 1:&lt;/strong&gt; Read all users stored in Firestore.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// What we would like to do&lt;/span&gt;
&lt;span class="c1"&gt;// (PS: This code doesn't work)&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;db&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FirebaseFirestore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;users&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"users"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;updateUI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// (This code doesn't work either)&lt;/span&gt;
&lt;span class="c1"&gt;// What some people do (wrongly)&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
&lt;span class="n"&gt;usersRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;addOnSuccessListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;querySnapshot&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;querySnapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toObjects&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;displayError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;// displayError() will always be called because&lt;/span&gt;
    &lt;span class="c1"&gt;// the users list is loaded asynchronously.&lt;/span&gt;
    &lt;span class="c1"&gt;// The if is executed while the list hasn't been loaded yet.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;updateUI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;



&lt;span class="c1"&gt;// What they should do:&lt;/span&gt;
&lt;span class="n"&gt;usersRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addOnSuccessListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;querySnapshot&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;users&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;querySnapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toObjects&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Userr&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;updateUI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// The method is now being called after&lt;/span&gt;
        &lt;span class="c1"&gt;// loading the users list.&lt;/span&gt;
    &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;addOnFailureListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="nf"&gt;displayError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looking at the code above, you might think there's nothing wrong with listeners, because everything makes sense and even keeps the code organized. But what if you need to read data from different collections and merge the results before displaying on the app UI? This would force us to use nested listeners, which is not so easy to read, as we can see bellow:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 2:&lt;/strong&gt; Load John's profile and his list of friends (this list is stored under a different collection).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Allow me to send a shot out to all&lt;/span&gt;
&lt;span class="c1"&gt;// JavaScript Developers who have been to callback hell&lt;/span&gt;
&lt;span class="n"&gt;usersRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"john"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;addOnSuccessListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;querySnapshot&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;johnUser&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;querySnapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;friendsRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;addOnSuccessListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;friendSnapshot&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
                &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;friends&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;friendSnapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toObjects&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Friend&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;showProfileAndFriends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;johnUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;friends&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;addOnFailureListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;displayError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;addOnFailureListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="nf"&gt;displayError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://kotlinlang.org/docs/reference/coroutines/coroutines-guide.html" rel="noopener noreferrer"&gt;Coroutines&lt;/a&gt; have come to change that. They allow you to write asynchronous code as if it was synchronous, making it more concise and easier to read.&lt;br&gt;
In order to use Coroutines in your Android Project, make sure you're using version 1.3.x or higher of the Kotlin Plugin, and then add the following dependencies to your build.gradle(app) file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... Other Dependencies ...&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1'&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.1.1'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As of the time this was posted, 1.1.1 was the latest version. You can check the &lt;a href="https://mvnrepository.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-play-services" rel="noopener noreferrer"&gt;maven repository&lt;/a&gt; for the latest version of kotlinx-coroutines-play-services.&lt;/p&gt;

&lt;p&gt;Now, if we used Coroutines in our &lt;strong&gt;first example&lt;/strong&gt;, it would become:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;snapshot&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;usersRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;await&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;users&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toObjects&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;updateUI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FirebaseFirestoreException&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;displayError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It resembles our "What we would like to do" code from example 1, doesn't it?&lt;/p&gt;

&lt;p&gt;Now our &lt;strong&gt;second example&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;querySnapshot&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;usersRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"john"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;await&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;johnUser&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;querySnapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;friendSnapshot&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;friendsRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;await&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;friends&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;friendSnapshot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toObjects&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Friend&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;showProfileAndFriends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;johnUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;friends&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FirebaseFirestoreException&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;displayError&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code now looks synchronous and easier to read, right?&lt;/p&gt;




&lt;p&gt;And that's all. I hope you found these Kotlin features useful and I hope that they'll improve your productivity when developing firebase apps.&lt;/p&gt;

&lt;p&gt;If you have any doubts or suggestions, please leave it on the comments bellow.&lt;/p&gt;

&lt;p&gt;If you're trying to use the Kotlin Extensions or Coroutines and ran into a problem, you can post it on &lt;a href="https://pt.stackoverflow.com/questions/ask?tags=firebase" rel="noopener noreferrer"&gt;StackOverflow&lt;/a&gt; explaining what you did and what error you ran into. I'm sure you'll find help (either from me or someone from the Firebase Community).&lt;/p&gt;

</description>
      <category>firebase</category>
      <category>kotlin</category>
      <category>android</category>
      <category>ktx</category>
    </item>
    <item>
      <title>Exploring Firebase Bill of Materials (BoM)</title>
      <dc:creator>Rosário P. Fernandes</dc:creator>
      <pubDate>Tue, 19 Mar 2019 18:08:27 +0000</pubDate>
      <link>https://dev.to/rosariopfernandes/exploring-firebase-bill-of-materials-bom-1hij</link>
      <guid>https://dev.to/rosariopfernandes/exploring-firebase-bill-of-materials-bom-1hij</guid>
      <description>&lt;p&gt;&lt;em&gt;Portuguese version available in &lt;a href="https://developingwith.firebaseapp.com/Exploring-Firebase-Bill-Of-Materials/"&gt;developingwith.firebaseapp.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once upon a time, in a not so distant past, one could easily add the Firebase SDK to their Android Project not worrying about different versions for each module. Every module (core, auth, firestore, storage, etc) would use the same version, so our &lt;code&gt;build.gradle (app)&lt;/code&gt; file would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight groovy"&gt;&lt;code&gt;    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'com.google.firebase:firebase-core:12.0.0'&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'com.google.firebase:firebase-firestore:12.0.0'&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'com.google.firebase:firebase-auth:12.0.0'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Or even better, we could declare the firebase version in the &lt;code&gt;build.gradle (project)&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;buildscript&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;firebase_version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'12.0.0'&lt;/span&gt;
    &lt;span class="c1"&gt;// ... Other configurations&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;and then use it in the &lt;code&gt;build.gradle (app)&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight groovy"&gt;&lt;code&gt;    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'com.google.firebase:firebase-core:$firebase_version'&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'com.google.firebase:firebase-firestore:$firebase_version'&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'com.google.firebase:firebase-auth:$firebase_version'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But the happiness in this Kingdom didn't last long. After some time, some modules started getting updates more frequently than others, forcing the sdk developers to bump their versions and thus having different versions for each module.&lt;/p&gt;

&lt;p&gt;Well, if you wish you had lived in that fairy-tale, I have good news for you! Thanks to the feature &lt;strong&gt;Bills of Material (BoM)&lt;/strong&gt; introduced in &lt;a href="https://docs.gradle.org/current/userguide/upgrading_version_4.html#rel5.0:bom_import"&gt;Gradle 5.0&lt;/a&gt; you can now use a single version for all the Firebase Android SDK modules.&lt;/p&gt;

&lt;p&gt;Bills of Material (BoM) allows the SDK developers to specify (in a bill) which module versions are known to work with each other and then set a version to this bill.&lt;/p&gt;

&lt;p&gt;So every time the Firebase Team publishes a new bill, you can be sure that you'll be using the latest versions(at time the BoM was published) of every module.&lt;/p&gt;

&lt;p&gt;You can find the latest BoM version in the &lt;a href="https://firebase.google.com/support/release-notes/android"&gt;Firebase Android Release Notes&lt;/a&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  Getting Started
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Upgrading to Gradle 5.0
&lt;/h2&gt;

&lt;p&gt;Since the BoM feature was introduced in gradle 5.0, you'll probably want to upgrade your gradle version (if you haven't already).&lt;/p&gt;

&lt;p&gt;To upgrade to gradle 5.0 and add Firebase BoM to your Android Project, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Upgrade to version 4.10 first and check for any errors deprecation warnings. It's better to fix all errors and warnings before upgrading to a newer version.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Upgrade to version 5.0 using this command in your project root folder:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;./gradlew wrapper &lt;span class="nt"&gt;--gradle-version&lt;/span&gt; 5.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Sync your project and add the dependencies to your gradle file:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Import the BoM&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="nf"&gt;platform&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'com.google.firebase:firebase-bom:16.0.0'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// Import the modules not minding their versions. Hooray!&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'com.google.firebase:firebase-core'&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'com.google.firebase:firebase-firestore'&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'com.google.firebase:firebase-auth'&lt;/span&gt;

    &lt;span class="c1"&gt;// ... Other dependencies&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;One more project sync and that's it! You no longer need to worry about different versions for each module.&lt;/p&gt;

&lt;h2&gt;
  
  
  With Gradle 4.6.x or higher
&lt;/h2&gt;

&lt;p&gt;If you're not planning to upgrade to Gradle 5.0, you can still take advantage of this feature, because it has been in experimental mode since gradle 4.6.x, you just need to enable it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open your project's &lt;code&gt;settings.gradle&lt;/code&gt; file and add the line &lt;code&gt;enableFeaturePreview('IMPROVED_POM_SUPPORT')&lt;/code&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;include&lt;/span&gt; &lt;span class="s1"&gt;':app'&lt;/span&gt;
&lt;span class="n"&gt;enableFeaturePreview&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'IMPROVED_POM_SUPPORT'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Sync your project and add the dependencies to your gradle file:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Import the BoM&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'com.google.firebase:firebase-bom:16.0.0'&lt;/span&gt;

    &lt;span class="c1"&gt;// Import the modules not minding their versions. Hooray!&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'com.google.firebase:firebase-core'&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'com.google.firebase:firebase-firestore'&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'com.google.firebase:firebase-auth'&lt;/span&gt;

    &lt;span class="c1"&gt;// ... Other dependencies&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;One more project sync and that's it!&lt;/p&gt;




&lt;h1&gt;
  
  
  Notes
&lt;/h1&gt;

&lt;p&gt;Please note that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If you specify a module version and you use a Firebase BoM, then the specified module version overrides the version contained in the BoM.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Firebase BoM is still an experimental feature, which means there might be some issues. If you want to report an issue or provide feedback, consider doing so in the &lt;a href="https://github.com/firebase/firebase-android-sdk/issues"&gt;Firebase Android SDK Issue Tracker&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>firebase</category>
      <category>android</category>
      <category>gradle</category>
      <category>gradle5</category>
    </item>
  </channel>
</rss>
