I have a multi-module multi-flavor android project, the modules are as follows:
core module, which is an android library that holds common stuff, including library dependencies.
authentication module, which is as the name suggests, a module that contains a bunch of UI activities and is responsible for authenticating users. It's also the module that has the launcher activity.
user module, which is another android library module. It is responsible for handling user profile UI, user data, along with Firebase database. But it also has to deal with Firebase authentication to get the Uid as it's used as key in the database.
Other modules that are irrelevant right now
The module core does nothing with respect to Firebase, except just include it as a dependency for other modules. So I have this in my project build.gradle:
dependencies {
classpath 'com.android.tools.build:gradle:3.2.0'
classpath 'com.google.gms:google-services:4.1.0'
}
and I also have this in my core build.gradle:
apply plugin: 'com.android.library'
apply plugin: 'com.google.gms.google-services'
android {
compileSdkVersion 28
defaultConfig {
minSdkVersion 19
targetSdkVersion 28
versionCode 1
versionName "1.0"
otherstuff
}
otherStuff
}
dependencies {
otherStuff
api 'com.google.android.gms:play-services-base:16.1.0'
api 'com.google.firebase:firebase-core:16.0.6'
api 'com.google.firebase:firebase-auth:16.1.0'
api 'com.google.firebase:firebase-database:16.0.6'
api 'com.google.firebase:firebase-storage:16.0.5'
api 'com.hbb20:ccp:2.2.3'
api 'com.google.android.libraries.places:places:1.0.0'
}
The user module does nothing except import the core library, and use authentication right away. So I have the following in my user build.gradle:
dependencies {
otherStuff
implementation project(':core')
}
and then I proceed to use it in my classes like so:
FirebaseAuth auth = FirebaseAuth.getInstance();
boolean isLoggedIn()
{
assert(auth != null);
return (auth.getCurrentUser() != null);
}
void uploadUserImpl()
{
assert(isLoggedIn());
db.getReference("users").child(auth.getCurrentUser().getUid()).setValue(this);
}
etc
The authentication module is the one that defines the app name, the launcher activity, etc. So, in my mind at least, it's also the one that should have the google-services.json file. So it has it under the authentication folder.
It includes both core and user libraries, so in my authentication build.gradle I have the following:
dependencies {
otherStuff
implementation project(':core')
implementation project(':user')
}
It also proceeds to use Firebase authentication for logging in and signing up users.
Now with the problem:
trying to build the project, I get the following error:
File google-services.json is missing. The Google Services Plugin cannot function without it.
Searched Location:
/work/mewais/CompanyName/ProjectName/core/src/FlavorName/debug/google-services.json
/work/mewais/CompanyName/ProjectName/core/google-services.json
and if I try to copy the google-services.json under core too, I get the following error:
No matching client found for package name 'com.companyname.projectname.core'
the google-services.json file has the app name defined inside it as:
"package_name": "com.companyname.projectname.appname"
which obviously expects the app name and not core.
So how to include Firebase in this setting? I want to keep the firebase dependencies defined inside core because multiple modules will use it. At the same time, authentication is the one that actually defines the appname and is also the one that has the launcher activity in which I start to use Firebase. I also expect user and any other modules to be able to use Firebase after that. It doesn't make sense to me to register all modules with Firebase (not even sure if it's possible since Firebase expects an app not a library?!). So is there anyway to fix this issue?
I managed to wrap firebase dependencies into a library module without polluting the main module. Here is what I did:
google-play-services plugin requires the module that includes it to have applicationId and its JSON file(or it won't compile).
If you're sure you don't use special functions that google-play-services plugin provides, you can delete them.
https://developers.google.com/android/guides/google-services-plugin
Then you can follow this article's instructions:
https://medium.com/#samstern_58566/how-to-use-firebase-on-android-without-the-google-services-plugin-93ecc7dc6c4
Update: Another Link
https://firebase.google.com/docs/projects/multiprojects#support_multiple_environments_in_your_android_application
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 may put a google-services.json file in flavor accoding to use:-
check this link
android {
// set build flavor here to get the right gcm configuration.
//def myFlavor = "flavor1"
def myFlavor = "flavor2"
if (myFlavor.equals("flavor1")) {
println "--> flavor1 copy!"
copy {
from 'src/flavor1/'
include '*.json'
into '.'
}
} else {
println "--> flavor2 copy!"
copy {
from 'src/flavor2/'
include '*.json'
into '.'
}
}
// other stuff
}
Related
I have a library (which we will name "test.aar" here), and i need to implement it inside an Android Project.
However, hosting it on Maven, as far as i know, is Open Source, and anyone can access it.
I am looking for a way to host the "test.aar" library somewhere with a "private mode".
What i mean by "private mode" is actually some credentials or tokens/keys to allow the access to "test.aar".
i would like to maybe use it like that inside build.gradle with credentials:
dependencies {
implementation "io.test-lib:test-lib:1.0.0"
}
PS : I have to do it remotely and ideally free (can pay if needed but not too expensive).
I once used some "secret SDK" and the provider of this SDK hoste it in jfrog.
https://jfrog.com/
The usage looks like this, in user's top level build.gradle:
allprojects {
repositories {
maven {
url "https://some_sdk_maker.jfrog.io/artifactory/secret-android-sdk"
credentials {
username = "username"
password = "password"
}
}
apply plugin: "com.jfrog.artifactory"
}
Then user must add the "implementation" string in the module's buid.gradle file. So only those who have the username and pass will be able to use your library.
In your build.gradle file you can use
implementation project(':mylibrary')
if you have the library set up as a subproject in your workspace. If you just have a binary, you can use
implementation fileTree(dir: 'path_to_file', include: ['*.aar'])
Either of these just require it to exist locally on the filesystem.
There are two modules in the Android project
app
database
database build.gradle:
dependencies {
implementation 'com.sample.lib:lib-v7:27.1.1'
}
app build.gradle:
dependencies {
implementation project(':database')
}
Now in the app I am able to get references to the files in sample lib.
But when the apk is to be built i get the following error:
error: cannot find symbol class SampleLibClassA
Why am I getting this error even when database module is added to app module as a dependency?
It works if I add the SampleLib dependency separately again the app module. But doesn't that defeat the whole purpose and wouldn't that just mean duplicate dependencies. Why is there a need to add them separately?
Am I missing something here?
Thanks.
Now in the app I am able to get references to the files in sample lib.
This is not exactly true. You need to use api instead of implementation in the database build.gradle to make it working as you expect.
dependencies {
api 'com.sample.lib:lib-v7:27.1.1'
}
This can actually happen if you are using minifyEnabled true in the module build.gradle file in the buildType.
In case you have this, just set it to false and build again.
I am currently working on an exiting Android application in order to create an Instant apps version.
My Android Studio is now split into several modules :
the business object module (which is a library)
the base -feature- module
the moduleA -feature- module
the app module (which is a phone/tablet module)
the instant module (which is an instant apps module)
My instant app module can be compiled and launched on a phone/tablet but each time it crashes due to Firebase issues. I have the following message into the logcat :
I/FirebaseInitProvider: FirebaseApp initialization unsuccessful
According to the documentation the Firebase library is compatible with Instant Apps, but I am pretty sure that I do not move the google-services.json file into the right place in my project...
Here what I have done :
I defined the following classpath dependencies into the build.gradle file of the Android Studio project : classpath 'com.google.gms:google-services:3.1.1'
I put the google-services.json file into my module base (because the documentation asks for it)
Now, if I try to apply the plugin (apply plugin: 'com.google.gms.google-services') into the build.gradle file of the base module, I cannot compile. I have the following message :
Error:Execution failed for task ':base:processGooglePlayProductionDebugFeatureGoogleServices'.
> No matching client found for package name 'com.mycompany.myapp.base'
In fact, the package name defined into the google-services.json file is the one use by the app (because according to the documentation the base library cannot have the same package name as the installed android app.
I also tried to apply the plugin into the build.gradle files of the installed app and into the instant apps module leaving the google-services.json file into the base module. The app compile but I have the log : "FirebaseApp initialization unsuccessful".
So I tried moving the google-services.json file into my instant app module but I still have the log : "FirebaseApp initialization unsuccessful"
I also tried to force the initialization calling the static method initializeApp from the FirebaseApp class but the log persists.
I cannot find an example of implementation on the web. In fact, the Google Sample repository does not use a google-services.json file.
Thank you in advance for your help !
Edit : Here the dependencies of my modules :
The dependencies of my base -feature- module :
implementation project(':businessobject')
feature project(':moduleA')
application project(':app')
The dependencies of my moduleA -feature- module :
api project(':base')
api project(':businessobject')
The dependencies of my app module (which is a phone/tablet module) :
implementation (project(':base'))
implementation (project(':businessobject'))
implementation (project(':moduleA'))
The dependencies of my instant module (which is an instant apps module) :
implementation project(':base')
implementation project(':businessobject')
implementation project(':moduleA')
because according to the documentation the base library cannot have
the same package name as the installed android app.
I think the documentation is a bit out of date. Each "feature" module needs to use a different package name, because that's what's used to generate the name of the R class. AFAIK there's no reason why you can't have the "base" feature use the same package name as the app itself.
It seems like the "google-services" plugin needs to be updated for the "feature" plugin to use the application ID rather than the name specified in AndroidManifest.xml (which will be overwritten later to be the same as the application ID).
tl;dr---changing the package name of "base" to "com.mycompany.myapp" should get things working.
I am following one of the Google Codelabs for making an Instant App.
And I was trying to create topeka-ui (A UI feature module for Instant Apps).
When I try to run one of the instant app module it says :
A dependent feature was defined but no package ID was set.
You are probably missing a feature dependency in the base feature.
I had an issue in that I had an Android app and an Android Library, but I had used the wrong plugin by mistake.
For an app:
plugins {
id "com.android.application"
id "kotlin-android"
}
For a library:
plugins {
id "com.android.library"
id "kotlin-android"
}
Since this is the only stackoverflow question for "A dependent feature was defined but no package ID was set. You are probably missing a feature dependency in the base feature." I will answer what my issue was here rather than create a new question. I had a module that was giving me this error and couldn't figure out the problem. In the dependent module's build.gradle file, I had:
apply plugin: 'com.android.feature'
It should have been:
apply plugin: 'com.android.library'
I just ran through the codelab on AS 3.0 beta 2 without issues (*note). After what point in the codelab did your issue appear?
You might’ve missed a step. Double check that your base module’s build.gradle has:
dependencies {
...
application project(":topekaapk")
feature project(":topekaui")
}
Leaving out feature project(":topekaui") can cause this error:
Error:com.android.builder.internal.aapt.AaptException: A dependent
feature was defined but no package ID was set. You are probably
missing a feature dependency in the base feature.
Note: because data-binding has been disabled for non-base modules (https://issuetracker.google.com/63814741), there requires some additional steps in the multi-feature step-7 to get around it (ie. getting rid of the DataBindingUtil).
I did it in build.gradle(...mylibrary), fixed it and it worked:
plugins {
- id 'com.android.application'
+ id 'com.android.library'}
defaultConfig {
- applicationId "com.example.mylibrary"
minSdk 21
targetSdk 32}
I had this issue in my Dynamic Feature Module when I forgot to add a reference to it in the base module's android.dynamicFeatures = [":module_name"] array
Base from basic instant app project structure,
When you build your instant app, this module takes all of the features and creates Instant App APKs. It does not hold any code or resources; it contains only a build.gradle file and has the com.android.instantapp plugin applied to it. Here's an example:
apply plugin: 'com.android.instantapp'
...
dependencies {
implementation project(':base')
// if there additional features, they go here
implementation project(':feature1')
}
Furthermore, note that
The base feature module's build configuration file needs to apply the com.android.feature gradle plugin. The build.gradle file does not contain any instant app specific modifications.
With this and in line with your encountered error, you may want to check your base feature module's build configuration file. Lastly, make sure that you also sync your project with gradle files.
See Android Instant Apps documentation for more information.
With the following gradle pugin
classpath 'com.android.tools.build:gradle:3.5.1'
In my case, after adding to app's build.gradle
android{
dataBinding {
enabled = true
}
}
I got the posted error, then doing the following
Android studio -> invalidate cache and restart
Issue got fixed!
Not Fixed Yet?
Probably there is a conflicting dependency residing in build.gradle,
like the older and current version of the same library
This solution will work 100%
Step 1) Open gradle.properties
Step 2) Add android.enableJetifier=true to the file
Done!
See The Screen Shot:
You might have added dependent module as a application, it should be added as a library.
Check build.gradle file of module and
Replace
plugins {
id 'com.android.application'
to
plugins {
id 'com.android.library'
also remove applicationId from build.gradle's of inner module if its added in defaultConfig block
I want to implement Firebase notifications system inside a library that I want to use as SDK in many apps.
Firebase is asking now for an App ID, but I'm implementing it inside a library, thus no App Id.
How could I achieve my goal to be able to send notifications to my apps that use my library ?
Thanks in advance.
These are all kinda hacky or too much work, here’s a nice n simple example (ironic though, cause it’s a long post -- but worth it).
It is possible to use FireBase code in your library project, of course the consuming application will need to register the app and get the app ID / google-services.json file.
But your library doesn’t, and shouldn’t care about about that, it’s the consuming applications job to do that, not your library.
Here’s a brief example using the firebase-messaging module inside of a library project.
YourLibrary module’s build.gradle:
// Other typical library set up
apply plugin: 'com.android.library'
android {
compileSdkVersion 27
defaultConfig {
minSdkVersion 16
targetSdkVersion 27
versionCode 1
versionName '1.0'
// Don’t for get your library’s proguard file!
consumerProguardFiles 'proguard-rules.pro'
}
}
ext {
currentFirebaseVersion = "11.8.0"
}
dependencies {
/*
Here we depend on the firebase messaging dependency (via compileOnly),
allowing us to use the FireBase API within our library module.
I exclude that org.json module because it may cause build warnings, this
step isn’t totally necessary.
NOTE: You should use `compileOnly` here so the dependency is
not added to the build output You will be allowed to use the
dependency in your library. If the consuming app wants to use firebase
they’ll need to depend on it (using `implementation`).
*/
compileOnly("com.google.firebase:firebase-messaging:$currentFirebaseVersion") {
exclude group: 'org.json', module: 'json'
}
}
// Other typical library set up. But nothing else relating Firebase.
This is all you need to do in your library project. DON’T apply the gms plug in here, and don’t add the google-services classpath to the libraries build.gradle.
Now here’s how you set up your consuming app:
MyClientApp’s top-level build.gradle:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google() // You know the drill...
}
// Any other set up you might have...
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
/*
Here in your client app’s top-level build.gradle you add the
google-services to the app’s classpath.
*/
classpath 'com.google.gms:google-services:3.2.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
// Other basic stuff...
allprojects {
apply plugin: 'maven'
apply plugin: 'maven-publish'
repositories {
jcenter()
google()
}
}
Now we need to set up the consuming applications module build.gradle, it’s simple. We pretty much just need to apply the plug-in, and depend on the library module that we create that has all the FireBase code in it.
MyClientApp’s module level build.gradle:
buildscript {
repositories {
google()
mavenLocal()
}
}
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
defaultConfig {
applicationId "com.your.application.that.can.use.firebase"
minSdkVersion 16
targetSdkVersion 27
versionCode 1
versionName '1.0'
}
//other typical set up
}
ext {
currentFirebaseVersion = "11.8.0"
}
dependencies {
implementation('com.your.library:YourLibrary:1.0#aar') {
transitive = true
// Use the consuming application's FireBase module, so exclude it
// from the dependency. (not totally necessary if you use compileOnly
// when declaring the dependency in the library project).
exclude group: 'com.google.firebase'
// Exclude the "plain java" json module to fix build warnings.
exclude group: 'org.json', module: 'json'
}
implementation("com.google.firebase:firebase-messaging:$currentFirebaseVersion") {
// Exclude the "plain java" json module to fix build warnings.
exclude group: 'org.json', module: 'json'
}
}
// Needs to be at the bottom of file.
apply plugin: 'com.google.gms.google-services'
Some things to note:
Must apply google-services plugin at the bottom (only in the client module build.gradle).
Depend on the library module that has the FireBase code in it, but exclude it’s version of the FireBase module, in favor of your own dependency version.
App depends on it's own FireBase version.
classpath 'com.google.gms:google-services:3.1.1’ only goes in the client app’s top level build.gradle.
Of course you will need to register the client app and put the google-services.json in your client app’s project.
Define the necessary Firebase Services in your app’s manifest (or use manifest merger and merge them in from your library project)
Add the google_play_services_version meta-data tag to your client app’s Manifest.
The library can/should use compileOnly when declaring the FireBase dependency.
Now you’ll be able to use FireBase code in your app that you defined in your library that uses FireBase. Or you could let your library module do all the FireBase work!
Of course this is typically used for internal libraries, as frameworks like Firebase weren’t designed to be implemented in library modules, but sometimes you need to, so this is a simple non-hacky/sane solution to the issue. It can be used on projects that are distributed through maven -- my library uses this, and it’s never caused any issues.
Update:
You should use compileOnly when declaring the library module's Firebase dependency. By doing so the dependency will not be added to the build output. But you will be allowed to use the dependency in your library. If the consuming app wants to use firebase they’ll need to depend on it manually (using implementation). This will help cut down on unneeded dependencies/bloat in applications and the “right” way to declare a dependency like this. Note: You may need to perform runtime checks to make sure the library is available before using it’s code in your module.
Yes you can actually do this, on your library build.gradle put this inside the defaultConfig field
buildConfigField("String", "FIREBASE_APP_KEY", "\"${firebaseAppKey}\"")
Then inside your project's gradle.properties
firebaseAppKey = <yourFirebaseAppSecret>;
For each project/app you must define this variable on your gradle.properties.
You'll have to create a firebase app for each project, but your library can now have the Firebase SDK.
When you want to access this environment variable value use BuildConfig.FIREBASE_APP_KEY
(e.g. instantiate firebase).
I know this is an old question with an accepted answer but all the answers have a big disadvantage - they require the user of your library to do work besides adding your library to their application. There is a way to do it without troubling the user of your library at all if your library is being downloaded from a Maven repository.
Note: this method is a hack and is not supported by Firebase. When asked Firebase Support, I got the following reply:
Firebase SDKs are not intended for library projects. The features available on Firebase were integrated in an application level and not
on a per module or per library basis so, the use case for having this
integrated on a library project is not possible or not supported.
Nevertheless, I've found a way to do it and maybe someone will find it useful so here it is:
This is an example of using Realtime Database but it should work for all the Firebase SDKs.
In your project's main build.gradle add mavenCentral repository:
allprojects {
repositories {
...
mavenCentral()
}
}
In your library project's build.gradle, add Google Play Services (as a dependency, not as a plugin):
compile 'com.google.android.gms:play-services-gcm:11.0.4'
Add the relevant Firebase SDKs (with the same version as Google Play Services):
compile 'com.google.firebase:firebase-core:11.0.4'
compile 'com.google.firebase:firebase-database:11.0.4'
Register your SDK as a project on Firebase, download it's google-services.json and open it with any text editor.
In your library's strings.xml add the following lines and fill these lines with data from google-services.json
<string name="gcm_defaultSenderId">project_number</string>
<string name="google_api_key">current_key</string>
<string name="google_app_id">mobilesdk_app_id</string>
<string name="google_crash_reporting_api_key">current_key</string>
<string name="google_storage_bucket">storage_bucket</string>
<string name="firebase_database_url">firebase_url</string>
<string name="default_web_client_id">client_id</string>
<string name="project_id">project_id</string>
This is it. You can use Firebase Realtime Database in your libaray, then build it and publish it to Maven (publishing to Maven is essential, otherwise the user of your library will have to add the dependencies manually). When activated from inside an application, your database will be used.
Note that this method may cause exceptions and unexpected behavior if the user of your library will use Google Play Services or Firebase so use at your own risk!
One option is to have the user of your library create a Firebase project and then pass in the resulting google-services.json file into their application then your library can depend on that.
Firebase Multiple Project
Please refer to the link it has all the information