A repository that shows how to use Firebase App Distribution to distribute android app to testers by fastlane.
:boom: This project will help you distribute your app with the power of Firebase App Distribution and fastlane. As you may know, Firebase App Distribution is a replacement of Beta. This sample also guides you how to organize a multi-build types and a multi-flavor Android application.
:fire: Firebase App Distribution makes distributing your apps to trusted testers painless. By getting your apps onto testers' devices quickly, you can get feedback early and often. And, if you use Crashlytics in your apps, you’ll automatically get stability metrics for all your builds, so you know when you’re ready to ship. Please visit Firebase App Distribution page fore more detail.
:rocket: fastlane is the easiest way to automate beta deployments and releases for your iOS and Android apps. 🚀 It handles all tedious tasks, like generating screenshots, dealing with code signing, and releasing your application. Please visit fastlane page fore more detail.
This to-do list is consist of 5 sections. We will see how both Firebase and Android side work respectively.
In this part, we will learn how to register our app via Firebase Console.
Before you can add Firebase to your Android app, you need to create a Firebase project to connect to your Android app. Visit Understand Firebase Projects to learn more about Firebase projects.
keytool -list -v -alias androiddebugkey -keystore ~/.android/debug.keystore
Certificate fingerprint: SHA1: DA:39:A3:EE:5E:6B:4B:0D:32:55:BF:EF:95:60:18:90:AF:D8:07:09
Click Download google-services.json to obtain your Firebase Android config file (google-services.json).
Move your config file into the module (app-level) directory of your app. This is not required anymore, hereafter you can move all required info into strings resources. This is explained in the Android side
dependencies {
// Add the following line:
classpath 'com.google.gms:google-services:4.3.2' // Google Services plugin
}
In your module (app-level) Gradle file (usually app/build.gradle), add a line to the bottom of the file.
android {
}
// Add the following line to the bottom of the file:
apply plugin: 'com.google.gms.google-services' // Google Play services Gradle plugin
dependencies {
// ...
// Add the Firebase SDK for Google Analytics
implementation 'com.google.firebase:firebase-analytics:17.2.1'
// Add the SDKs for any other Firebase products you want to use in your app
// For example, to use Firebase Authentication and Cloud Firestore
implementation 'com.google.firebase:firebase-auth:19.1.0'
implementation 'com.google.firebase:firebase-firestore:21.2.1'
// Getting a "Could not find" error? Make sure that you've added
// Google's Maven repository to your root-level build.gradle file
}
In this part, we will configure our Android application to allow it to be in touch with Firebase App Distribution.
When you work on a project that has multiple build types or flavors, you will most likely face weird issues. For example:
Could not find google-services.json while looking in [src/flavor1/debug, src/debug, src/flavor1]
To suppress such error, you have to create both src and all flavor folders and move google-services.json file into each one. This could be costly especially you have several build types and flavors. Now we will see how to use only resources instead of google-services.json file and obtain the same result for our app.
./gradlew :app:assembleDebug
to force the plugin to do its job.app/build/generated/res/google-services/debug/values/values.xml
and inspect the contents, it should look something like this:<?xml version="1.0" encoding="utf-8"?>
<resources>
<! -- Present in all applications -->
<string name="google_app_id" translatable="false">1:1035469437089:android:73a4fb8297b2cd4f</string>
<! -- Present in applications with the appropriate services configured -->
<string name="gcm_defaultSenderId" translatable="false">1035469437089</string>
<string name="default_web_client_id" translatable="false">337894902146-e4uksm38sne0bqrj6uvkbo4oiu4hvigl.apps.googleusercontent.com</string>
<string name="ga_trackingId" translatable="false">UA-65557217-3</string>
<string name="firebase_database_url" translatable="false">https://example-url.firebaseio.com</string>
<string name="google_api_key" translatable="false">AIzbSyCILMsOuUKwN3qhtxrPq7FFemDJUAXTyZ8</string>
<string name="google_crash_reporting_api_key" translatable="false">AIzbSyCILMsOuUKwN3qhtxrPq7FFemDJUAXTyZ8</string>
<string name="project_id" translatable="false">mydemoapp</string>
</resources>
The reason that is underneath this way according to the Firebase docs
Because this provider is just reading resources with known names, another option is to add the string resources directly to your app instead of using the Google Services gradle plugin. You can do this by:
- Removing the google-services plugin from your root build.gradle
- Deleting the google-services.json from your project
- Adding the string resources directly
- Deleting apply plugin: 'com.google.gms.google-services' from your app build.gradle
Navigate to your app folder or on Terminal inside Android Studio, type the command below:
sudo gem install fastlane -NV
Verify that the installation was successful by typing this command in the CLI:
fastlane -version
Run fastlane init
Provide the package name for your application when asked (e.g. com.thedancercodes.fastlanedroid)
Press enter when asked for the path to your json secret file
Answer ’n’ when asked if you plan on uploading info to Google Play via Fastlane (we can set this up later)
That’s it! Fastlane will automatically generate a configuration for you based on the information provided. This process generates our App file and Fastfile. Below is a screenshot of the Fastlane directory in your project containing these files.
Appfile: Defines configuration information that is global to your app.
Fastfile: Defines different lanes that drive the behavior of fastlane to do different tasks.
The Fastfile defines what steps run & in what order Fastlane runs them. A group of steps is called a lane
Below are code snippets show the contents of the Fastfile & Appfile:
App file | Fast File |
---|---|
There are something we need to add into our Fastfile in order to have lane working correctly.
app: This key indicates our APP_ID. This is found on Firebase console. Respectively;
release_notes_file: A file that includes changelog.
testers_file: A file that includes testers. If we specify it we can skip Distribute app to testers since fastlane will handle distribution automatically.
firebase_cli_path: A path to Firebase CLI - Please see Setup Firebase CLI
apk_path: Refers to our apk path that we want to distribute.
:clipboard: The Firebase CLI (GitHub) provides a variety of tools for managing, viewing, and deploying to Firebase projects.
Install plugin firebase_app_distribution
for fastlane by run this in your terminal
fastlane add_plugin firebase_app_distribution
Check that if in your Pluginfile like this
Next, install Firebase CLI by running this in your terminal
curl -sL firebase.tools | bash
Sign in your account to authorize Firebase by running
firebase login
and you can log out anytime by running with the following command line
firebase logout
In order to distribute your application, you need to build it first. You can check out fastlane build actions for more options. Below code block is enough to build our application.
gradle(
task: "assemble",
flavor: "MyFlavor",
build_type: "Release" -> This could be Debug or any kind of custom build type.
)
Now we need to add a fastlane lane to distribute our application. A common lane can look like;
We also need to have some settings on Firebase console in order to able to distribute our application such as defining testers, groups, invite links and so on.
When you expand any distribution you will see email addresses which were invited and release notes.
After you add testers, click Next.
The last part is to download our app after getting an aler email that indicates the application has a new release.
:boom: Just type below command and our app will be distributed in a while :confetti_ball:
fastlane distribute
For a faster execution, you could type:
bundle exec fastlane distribute
...And the result!
increment_version_code is a fastlane plugin that helps to increment version code in each release. This usually is used in Deploy to Play Store part. In this example, I used it in Firebase distribution part to imitate the scenario.
increment_version_code(
gradle_file_path: "./app/build.gradle"
)
Sometimes you might need to checkout a new branch after you distributed your application. In case of that, branch names usually have version name as a suffix to make it clear. get_version_name helps you do so...
An example:
new_version = get_version_name(
gradle_file_path:"./app/build.gradle",
ext_constant_name:"versionName"
)
dotenv basically shims to load environment variables from .env into ENV in development. To install it, just type below command on terminal;
sudo gem install -n /usr/local/bin dotenv
If it asks you some permissions, grant it otherwise it won't continue.
Since we have a sensitive data called Firebase App Id we need to store it in a .env file. Therefore, fastlane will access and read content directly. We need to follow steps below in order;
.env.secret
to your .gitignore
file (if you are using git)before_all block
in your Fastfile
# fastlane/Fastfile
fastlane_require 'dotenv'
before_all do
Dotenv.overload '.env.secret'
end
lane :distribute do
firebase_app_distribution(
app: ENV['FIREBASE_APP_ID'],
...
)
end
That's it! Fastlane will automatically read our value from the file and distribute a release without any error.
Resources that I benefit from to create this comprehensive documentation.
Find this docs useful? :heart:
Support it by joining stargazers for this repository. :star:
And follow me for my next creations! 🤩
Apache License
/*
* Designed and developed by 2019 nuhkoca (Nuh Koca)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/