Commiting google-services.json to GitHub - android

I am creating a public android project and I am using Google Sign-In service. I am doing it according to this tutorial. As it says, I have got the google-services.json file.
Do I need to commit the above file to Github?
Do other developers (If someone contributes) need this file?
Or, do they have to create there own?
By the way I am using Travis-CI. Will this file affect to CI build?

You can create a new build variant and store a template google-services.json to be used for your build on your CI platform in your app build.gradle.
Use a different google-services.json for the new dev build variant (see this post). Add the following google-services.json template to app/src/dev folder :
{
"project_info": {
"project_number": "",
"project_id": ""
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:123456789012:android:1234567890123456",
"android_client_info": {
"package_name": "com.your.package"
}
},
"oauth_client": [
{
"client_id": "",
"client_type": 3
},
{
"client_id": "",
"client_type": 1,
"android_info": {
"package_name": "com.your.package",
"certificate_hash": ""
}
}
],
"api_key": [
{
"current_key": ""
}
],
"services": {
"analytics_service": {
"status": 2,
"analytics_property": {
"tracking_id": ""
}
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"ads_service": {
"status": 1
}
}
}
],
"configuration_version": "1"
}
Note that I have extended this google-services in case you also use Google Analytics or GCM service.
You would have the following configuration :
app/
├── src/
│ ├── main/
│ └── dev/
│ └── google-services.json
├── google-services.json
└── build.gradle
You can use either :
a new build type
a new product flavor (if you already have existing ones)
Build Type
Add the following build type:
buildTypes {
dev {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
We don't need to build this "dev" build variant in regular build, so you can exclude this variant if a parameter is not specified. Add the following to your app build.gradle :
def build_param = "${build}";
if (build_param != "dev") {
//exclude production build
android.variantFilter { variant ->
if (variant.buildType.name.equals('dev')) {
variant.setIgnore(true);
}
}
} else {
//exclude all except production build
android.variantFilter { variant ->
if (!variant.buildType.name.equals('dev')) {
variant.setIgnore(true);
}
}
}
Product flavor
Add the dev product flavor to existing ones :
productFlavors {
full {
}
dev {
}
}
To remove this dev product flavor from the regular build :
def build_param = "${build}";
if (build_param != "dev") {
//exclude dev
android.variantFilter { variant ->
if (variant.getFlavors().get(0).name.equals('dev')) {
variant.setIgnore(true);
}
}
} else {
//exclude all but dev
android.variantFilter { variant ->
if (!variant.getFlavors().get(0).name.equals('dev')) {
variant.setIgnore(true);
}
}
}
Eventually, add your app module google-services.json to .gitignore :
app/google-services.json
We have previously ensured that this dev variant will only be used when parameter build=dev is specified
Edit .travis.yml to modify the build config :
script:
- ./gradlew clean build -Pbuild=dev
-Pbuild=dev will only build dev build variant using google-services.json located in app/src/dev/google-services.json
Take a look at this sample project which is using google-services Google project
In Travis log, you can see that the JSON file being parsed is the one for the dev build variant :
Parsing json file: /home/travis/build/bertrandmartel/android-googlesignin/app/src/dev/google-services.json
Extra Note
Note that this method is not limited to CI and can be extended for your production build when you require a production google-services.json or a different AndroidManifest.xml (with some specific properties like fabric.io key)
Check this method to prevent commitment of fabric keys embedded in AndroidManifest.xml (and can't be imported from gradle) that is using a different build variant and using a parameter to enable the production build.

You can use travis encrypt-file google-services.json
Documentation
You can do it by:
installed the Travis CI Command Line Client by running $ gem install travis.
logged in to Travis CI using $ travis login or $ travis login --pro
$ travis encrypt-file super_secret.txt
encrypting super_secret.txt for rkh/travis-encrypt-file-example
storing result as super_secret.txt.enc
storing secure env variables for decryption
Then it will print on the console this:
openssl aes-256-cbc -K $encrypted_0a6446eb3ae3_key -iv $encrypted_0a6446eb3ae3_iv -in super_secret.txt.enc -out super_secret.txt -d
You can copy it to your .travis.yml file as I did here
Do not forget to put your .enc file on your GitHub repository.
If you have multiple files, you could zip them and then you unzip the decrypted file on the Travis ci.
For instance, you can do like this:
$ tar cvf secrets.tar foo bar
$ travis encrypt-file secrets.tar
$ vi .travis.yml
$ git add secrets.tar.enc .travis.yml
$ git commit -m 'use secret archive'
$ git push
I did it.
In my case, I had two files to use on the build of my app. So, I used this due to travis does not support multiple encrypted files. Therefore, you zip then on one file and encrypt this file.
You can have a look at my travis script here

Firebase Documentation says:
"For open source projects, we generally do not recommend including the app's Firebase config file or object in source control because, in most cases, your users should create their own Firebase projects and point their apps to their own Firebase resources (via their own Firebase config file or object)."
https://firebase.google.com/docs/projects/learn-more?authuser=0#config-files-objects

Firebase documentation seems to imply that there is no problem in committing the file to GitHub.
Here is an extract from the docs
The Firebase config file contains unique, but non-secret identifiers for your project. To learn more about this config file, visit Understand Firebase Projects.

Related

How to configure Firebase App Distribution for a flavor dimension combination?

I am currently working on an Android application in which one there is several flavor dimensions and several product flavors:
flavorDimensions "environment", "deviceType"
productFlavors
{
playstore
{
dimension "deviceType"
}
touchpanel
{
dimension "deviceType"
versionNameSuffix "-TouchPanel"
}
prod
{
dimension "environment"
}
integration
{
dimension "environment"
versionNameSuffix "-Integration"
applicationIdSuffix ".integration"
}
dev
{
dimension "environment"
versionNameSuffix "-Dev"
applicationIdSuffix ".dev"
}
}
I would like to configure Firebase App Distribution for each flavor dimension combination.
I know how to configure Firebase App Distribution for a specific product flavor. For example:
dev
{
firebaseAppDistribution
{
serviceCredentialsFile = "${projectDir}/src/main/XXXXX.json"
artifactPath = "${buildDir}/outputs/universal_apk/devRelease/app-dev-release-universal.apk"
groups = "XXX"
}
}
But I do not how to configure firebase for the variants:
devPlaystore
integrationPlaystore
prodPlaystore
devTouchpanel
integrationTouchPanel
prodTouchPanel
In fact, I tried to write something like:
productFlavors
{
devPlaystore
{
firebaseAppDistribution
{
serviceCredentialsFile = "${projectDir}/src/main/XXXXX.json"
artifactPath = "${buildDir}/outputs/universal_apk/devRelease/app-dev-release-universal.apk"
groups = "XXX"
}
}
}
But gradle does no like my code and display the following error when I sync gradle:
A problem occurred configuring project ':app'.
kotlin.KotlinNullPointerException (no error message)
Thank you in advance for your help in order to help me to configure correctly Firebase App Distribution for my case :)
Conclusion: this use case cannot be resolved using the Firebase App Distribution gradle plugin. I now use the Firebase CLI :
build the first binary (for example an AAB using gradlew clean bundleProdRelease)
execute the first firebase command using for example firebase appdistribution:distribute "app/build/outputs/bundle/prodRelease/app-prod-release.aab" --app XXX --token XXX
build other binaries (for example gradlew clean packageReleaseUniversalApk)
execute other firebase commands (for example firebase appdistribution:distribute "app/build/outputs/universal_apk/preprodRelease/app-preprod-release-universal.apk" --app XXXX --token XXXX and firebase appdistribution:distribute "app/build/outputs/universal_apk/qaRelease/app-qa-release-universal.apk" --app XXX --token XXXX)

Setting process.env variable from Android Studio flavors

I want to be able to access a variable in my metro.config.js.
On iOS this can be achieved by adding a User Defined variable in the Build Settings tab. This is accessible with process.env.MY_VAR. The value of MY_VAR can be changed depending on which target is being built.
How can I achieve the same for Android using product flavours?
Here is my current setup
flavorDimensions "apps"
productFlavors {
free {
dimension "apps"
}
paid {
dimension "apps"
}
}
Execution Steps
When running iOS, I can see from the logs that the project gets built before the Packager starts
info Found Xcode workspace "foo.xcworkspace"
info Building (using "xcodebuild -workspace foo.xcworkspace -configuration Debug -scheme foo -destination id=CE408502-CD8C-4467-AE3D-295081CAF132 -derivedDataPath build/foo") <-- Build
▸ Running script '[CP-User] Config codegen'
▸ Compiling ReactNativeConfig.m
▸ Building library libreact-native-config.a
▸ Running script 'Upload Debug Symbols to Sentry'
▸ Running script 'Start Packager <-- Metro starts here
However, the packager starts before my gradle build task executes
info Starting JS server... <-- Metro starts here
info Installing the app...
> Configure project :app
Reading env from: .env
> Task :app:installFreeDebug <-- Build
Add the following codes to your build.gradle file.
buildTypes.each {
it.buildConfigField 'String', 'KEY_STRING', '"Default_Value"'
it.buildConfigField 'int', 'KEY_INT', '0'
}
applicationVariants.all { variant ->
if (variant.productFlavors[0].ext.has("key_1")) {
buildConfigField('String', 'KEY_STRING', variant.productFlavors.get(0).ext.key_1)
}
if (variant.productFlavors[0].ext.has("key_2")) {
buildConfigField('int', 'KEY_INT', variant.productFlavors.get(0).ext.key_2)
}
}
and then add ext.key_1 = '"desired string value"' and ext.key_2 = 'desired integer value' to flavors like this
flavorDimensions "apps"
productFlavors {
free {
dimension "apps"
ext.key_1 = '"free_value"'
ext.key_2 = '0'
}
paid {
dimension "apps"
ext.key_1 = '"paid_value"'
ext.ket_2 = '100'
}
}
Now you will access to the values in your app by calling BuildConfig.KEY_STRING and BuildConfig.KEY_INT.
If you don't set value for key_1 in a flavor, then the default value will be "Default_Value".
Update
I'm ashamed to say my above answer is wrong because in this way you can access the BuildConfig in JS scope but as you mentioned in your question you need to access the configuration in Metro Bundler and metor.config.js. I added the console.log(process.env); at the beginning of metro.config.js file and figured out process.env in Metro Bundler is my OS (in my case Windows 10) environment variables. So it means if you add desired variables as OS environment variable, then you will access them in metro.config.js through process.env. I tried to add environment variables through build.gradle but it wasn't a good way because:
1. I couldn't find a way to add the environment variable in Gradle
2. If I could do step 1, then as you mentioned the Metro starts before android Build, so the configuration will be ready late and Metro can't access them.
So, I decided to solve this issue in another way. First, I changed the build.gradle to log the required variables during Build process.
flavorDimensions "apps"
productFlavors {
free {
dimension "apps"
// Add any configuration you need for free flavor
buildConfigField('String', 'KEY_STRING', '"free_value"')
}
paid {
dimension "apps"
// Add any configuration you need for paid flavor
buildConfigField('String', 'KEY_STRING', '"paid_value1"')
buildConfigField('int', 'KEY_INT', '100')
}
}
applicationVariants.all { variant ->
// Read all flavors configuration
variant.productFlavors.each { flavor ->
flavor.buildConfigFields.each { key, value ->
// Set configuration to variant to be accessible through BuildConfig
variant.buildConfigField(value.type, value.name, value.value)
// Log all configurations in output
println "[" + variant.name + "]---" + value.name + "=" + value.value
}
}
variant.outputs.each { output ->
// For each separate APK per architecture, set a unique version code as described here:
// https://developer.android.com/studio/build/configure-apk-splits.html
def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
def abi = output.getFilter(OutputFile.ABI)
if (abi != null) { // null for the universal-debug, universal-release variants
output.versionCodeOverride =
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
}
}
}
Then I wrote a bat file to run {variant}PreBundle task (For example freeDebugPreBundle) in Gradle. Then it will read the output and extract required variables and then set them as environment variables and finally call react-native run-android --variant {variant} command.
run-android.bat
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
:: Reading input arguments to extract desired variant
FOR %%a IN (%*) do (
set "arg=%%a"
if "!found!"=="true" (
set "variant=%%a"
GOTO:EndOfLoop
)
if "!arg!"=="--variant" set found=true
)
:EndOfLoop
:: User must provide variant because when you have flavors, then `debug` varinat does not exist anymore
if "!variant!"=="" (
echo You must provide --variant
GOTO:EOF
)
:: Creating a pttern to extract required variables
set search=[!variant!]---
:: Creating gradle task name based on input variant
set firstCharUpper=%variant:~0,1%
CALL :UpCase firstCharUpper
set taskName=build!firstCharUpper!%variant:~1%PreBundle
echo Running !taskName!
:: Creating an empty bat file to store environment variables and call later
echo. > custome_env.bat
:: Running gradle task and extracting required variables from output log
cd android
FOR /F "tokens=* USEBACKQ" %%F IN (`gradlew app:!taskName!`) DO (
SET "line=%%F"
SET "newLine=!line:%search%=!"
if not "!line!"=="!newLine!" (
echo !line!
set "keyValue=!line:%search%=!"
:: Adding environment variabel to custome_env.bat file
echo set !keyValue!>>../custome_env.bat
)
)
ENDLOCAL
:: Running custome_env.bat file to set required variables as environment variable
call custome_env.bat
:: Calling react-native command with all input parameters (%*)
call react-native run-android %*
GOTO:EOF
#echo on
:UpCase
:: Subroutine to convert a variable VALUE to all UPPER CASE.
:: The argument for this subroutine is the variable NAME.
FOR %%i IN ("a=A" "b=B" "c=C" "d=D" "e=E" "f=F" "g=G" "h=H" "i=I" "j=J" "k=K" "l=L" "m=M" "n=N" "o=O" "p=P" "q=Q" "r=R" "s=S" "t=T" "u=U" "v=V" "w=W" "x=X" "y=Y" "z=Z") DO CALL SET "%1=%%%1:%%~i%%"
GOTO:EOF
For running the application you should run this command:
run-android.bat --variant freeDebug
You can use other react-native options as well but you must provide --variant because when you have flavors, default variant debug does not exist.
PS: I don't know how is your release proceseduar, so I'm not sure this answer is compatible with your release procedure or not. if I know it maybe I can find a solution for it.

Android. Firebase: Different applicationIdSuffix. Where save google-services.json?

I has project with 2 build types.
Every build type has specific applicationIdSuffix.
BuildType : dev , applicationIdSuffix = .dev
BuildType : prod , applicationIdSuffix = .prod
In Firebase console I create application for build type = dev.
As result I download file google-services.json. I put it in c:\myproject\android\app\
In this file "package_name": "com.myproject.dev"
OK. It's work.
Now I in Firebase for the same project, I need to create another application with another buildType = prod.
As result I download NEW file: google-services.json.
In this file "package_name": "com.myproject.prod"
Where I need to put this second file google-services.json?
Firebase already supports that, you should create a new project, then add 2 new apps for each build type (mypackage.prod and mypackage.dev) or flavor.
Once done, just export the google-services.json of the last created app (dev), the file should contain details of both apps, like the following
"client_info": {
"mobilesdk_app_id": "...",
"android_client_info": {
"package_name": "mypackage.dev"
}
},
"client_info": {
"mobilesdk_app_id": "...",
"android_client_info": {
"package_name": "mypackage.prod"
}
You just need to replace the google-services.json with existing one.Because Firebase automatically generates all the necessary attributes in google-services.json file having multiple build flavors in single project
Just remember every-time download new google-services.json and replace it after adding new flavor in your existing project

Android Data Binding in Make file (Android.mk)

As per a lot of examples, android data bindings are enabled by putting the following snippet in build.gradle file:
android {
....
dataBinding {
enabled = true
}
}
However, I'm working on an android project in AOSP which builds using the make file (Android.mk).
So my question is: How can we add support for data-binding dependencies in android make file?
I found a solution that works for me!
The first hurdle to climb will look something like this: error: package net.mulliken.pinenotenotebook.databinding does not exist
I found that Android Studio automatically generates these files. It was in app/build/generated/data_binding_base_class_source_out/debug/out/net/mulliken/pinenotenotebook/databinding. In order to incorporate this in my build I made a symbolic link from my Android studio workspace to databinding_src in my packages folder.
After that it still didn't work because it could not find the view binding package. You will probably get an error like this: error: package androidx.viewbinding does not exist
I found that google has a repo that includes this package and so I cloned it into my AOSP workspace under frameworks.
[me aosp/frameworks] $ git clone -b studio-main https://android.googlesource.com/platform/frameworks/data-binding data-binding
I then created a new symbolic link from that path into my package directory so that the compiler could find that class:
[me packages/apps/MyAPP] $ ln -s ../../../../frameworks/data-binding/extensions/viewbinding/src/main/java/ androidx_viewbinding_src
At the end of the day my Android.bp file looks like this:
android_app {
name: "PineNoteNotebook",
static_libs: [
"androidx.appcompat_appcompat",
"com.google.android.material_material",
"androidx-constraintlayout_constraintlayout",
"androidx.navigation_navigation-fragment",
"androidx.navigation_navigation-ui",
],
certificate: "platform",
srcs: [
"./**/*.java",
],
resource_dirs: ["res"],
product_specific: true,
sdk_version: "current",
optimize: {
enabled: false
},
required: ["libpinenote"],
}
And my package tree looks like this:
.
├── Android.bp
├── AndroidManifest.xml -> /home/mulliken/AndroidStudioProjects/PineNoteNotebook/app/src/main/AndroidManifest.xml
├── androidx_viewbinding_src -> ../../../../frameworks/data-binding/extensions/viewbinding/src/main/java/
├── databinding_src -> /home/mulliken/AndroidStudioProjects/PineNoteNotebook/app/build/generated/data_binding_base_class_source_out/debug/out
├── res -> /home/mulliken/AndroidStudioProjects/PineNoteNotebook/app/src/main/res/
└── src -> /home/mulliken/AndroidStudioProjects/PineNoteNotebook/app/src/main/java/
i think you must use the latest android studio 3.6 version , with the latest ndk +
add this to your android gradle
android {
...
viewBinding {
enabled = true
}
}
check this : https://developer.android.com/topic/libraries/view-binding

Switch GCM Client on Development and Production

Just implement the new GCM. For official document,
Copy the google-services.json file you just downloaded into the app/ or mobile/ directory of your Android Studio project.
Anyone know how to setup gradle to switch development and production to use different google-services.json?
I have just answered a similar question here for different productFlavors.
In your case it's debug/production. I don't know why you need to switch between production and debug but i think you can do the same as what I proposed for flavors.
Create two extra folders src/release and src/debug , in each of the folders you put the corresponding google-services.json , so you will have: src/release/google-services.json and src/debug/google-services.json
Now in gradle add this :
android {
// set build config here to get the right gcm configuration.
//def myBuildConfig = "release"
def myBuildConfig = "debug"
// this will copy the right google-services.json file to app/ directory.
if (myBuildConfig.equals("release")) {
println "--> release copy!"
copy {
from 'src/release/'
include '*.json'
into '.'
}
} else {
println "--> debug copy!"
copy {
from 'src/debug/'
include '*.json'
into '.'
}
}
// other stuff
}

Categories

Resources