I am building android library project, which has a dependency on another internal library project.
I am wondering if there is a way to package a single AAR library, which already contains internal library inside it. I would like to share only 1 AAR library package to my application developers.
This is how my build.gradle files look currently, but currently they produce separate AAR files and both needs to be included in Application's build.gradle. As application is being built by another company, we need to share the final AAR file with them and not the complete library projects.
----- internalLib -------->>>>>>>>>>
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.7.+'
}
}
apply plugin: 'android-library'
repositories {
mavenCentral()
}
android {
compileSdkVersion 18
buildToolsVersion '18.1.1'
}
dependencies {
compile 'com.android.support:support-v4:18.0.0'
}
----- externalLib --------
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.7.+'
}
}
apply plugin: 'android-library'
repositories {
mavenCentral()
}
android {
compileSdkVersion 18
buildToolsVersion '18.1.1'
}
dependencies {
compile 'com.android.support:support-v4:18.0.0'
compile project(':internalLib')
}
There is no mechanism to combine library. It's a bit complicated as you probably want to control which dependencies get merged (for instance you probably don't want to include support-v4 in there). Also you'd need to merge the resources and Android manifest.
At this time there's no way to easily hack something, unless you are sure the resources have no conflicts between the two res folders (for instance you could have strings_a.xml in one lib and strings_b.xml in the other lib). This way you can just "merge" the two res folders by copying them both into the same location (as opposed to do a merge at the android res level).
For the Manifest it'd be more complicated, but doable with some custom code.
Providing a built-in mechanism for this is very low on our priority so don't expect it anytime soon.
For the sake you have to upload each library as separately on maven and use its implementation in parent library modules till the main library module. Only then when you publish your main library on maven will include your all child dependencies.
As far as we have only one option add aar as api dependency inside the module.
For that we have to generate aar file and publish it to Maven and make it accessible by another module and consume it in app.
https://developer.android.com/studio/projects/android-library
As mentioned above android developer document.
The library module with source code is copied to your project, so you can actually edit the library code. If you want to maintain a single version of the library code, then this is probably not what you want and you should instead add the compiled AAR file as described above.
If there anything else we can do, please let us know by jot down in the command section.
It is not supported
It is not recommended to include one library into another because it leads to a serious issues with managing versions and complexity of creating and supporting such solution.
You should stick to native approaches like dependency manager or rearchitect your codebase
[iOS Umbrella framework]
Related
I want to add an enum called modules with the path of the sub module and some compilation types.
I used to have this in the buildSrc before gradle 6 and it was accessible in the settings.gradle
But from gradle 6.0, settings.gradle is compiled before buildSrc project. I have moved my enum to the settings.gradle, now it is not accessible to other project level gradle scripts.
The behaviour change is outlined in the below release notes.
https://docs.gradle.org/current/userguide/upgrading_version_5.html#changes_to_plugins_and_build_scripts
They suggest to add the enums / classes used in the settings.gradle to the build script closure, but I am not really sure how to do that.
https://docs.gradle.org/current/userguide/upgrading_version_5.html#plugins_and_classes_loaded_in_settings_scripts_are_visible_to_project_scripts_and_buildsrc
I've recently hit a similar issue, my company have custom code for authenticating with our Nexus which we were keeping in buildSrc. I can't turn this into a plugin since I'd need to store that in our Nexus and then would be in a catch-22 situation as I'd need to authenticate to get the authentication plugin!
I can see 2 potential workarounds for this:
Publicly published jar.
Build your custom classes as a separate jar, or a Gradle plugin if this fits the use case. Publish the jar to a maven repository that you can access from settings.gradle buildscript (for me this is difficult as it's sensitive company specific code).
This might look something like the following in your settings.gradle:
include "project-name"
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.companyname:gradle-utils:0.0.1'
}
}
Commit the binary
This isn't a desirable option but you can manage the source code for your custom buildSrc classes in another repository, then every time you make a change to them (hopefully infrequently) - you can build the new version and commit the built jar into the repositories that need to use it (perhaps under buildSrc). If your custom code has dependencies that aren't naturally on the classpath when gradle runs, you'd need to package these into the jar that you commit as well.
Your settings.gradle might then look like:
include "project-name"
buildscript {
dependencies {
classpath files("buildSrc/gradle-utils.jar")
}
}
I want to build .AAR with dependencies inside. I was looking for a lot but nothing works. Topics are so old. I realized that resultant .AAR should have classes.jar inside and there are directories with .class files. But I don't know how to automatize this process in gradle.
Android tooling doesn't support it. There's an issue open requesting Google to implement it (feel free to star it to show your support and to help Google to prioritize it).
In the meantime, there are two plugins to try to fix or workaround this lack of support, with limited support of different functionalities:
https://github.com/adwiv/android-fat-aar Old, no longer supported.
https://github.com/Mobbeel/fataar-gradle-plugin Still active, but lagging behind AGP versions (currently working on supporting 3.2 and 3.3... while we're already at 3.4 stable)
So, as you can see the future doesn't look bright.
See also this article for more information.
We manage to do this using this Mobbeel fat AAR Gradle plugin:
https://github.com/Mobbeel/fataar-gradle-plugin
buildscript {
repositories {
//...
maven {
url 'https://plugins.gradle.org/m2/'
}
}
}
//...
dependencies {
classpath 'gradle.plugin.com.mobbeel.plugin:mobbeel-fataar:1.2.0'
}
Mark dependencies with api instead of implementation
apply plugin: 'com.mobbeel.plugin'
dependencies {
api 'org.greenrobot:eventbus:3.0.0'
//...
}
fatAARConfig {
includeAllInnerDependencies false
}
This article was helpful: http://wittchen.io/2018/10/02/creating-fat-aar/
I have some code I'd like to use across multiple different projects. Let's say it's some e-commerce code that handles things like payments and shopping carts.
It seems inefficient and dangerous to copy-paste everything across different projects. And if I add one feature or fix one bug in the core e-commerce module, I'd like that change to be reflected in other projects using it too.
I would also like to re-use some of the Activities, Fragments, Adapters too.
What is a good approach to this?
When we have a library project that needs to be shared to every project on a local computer, we can make use of Maven.
A. Here the step in your library that we will you for the project:
Make a library project from Android Studio.
Add Gradle Android Maven plugin to root build.gradle
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
}
}
Add apply plugin for step 1 in your library build.gradle. (NOT root build.gradle):
apply plugin: 'com.android.library'
apply plugin: 'com.github.dcendents.android-maven'
Add the following after the apply plugin, this line to determine your library when adding to project:
group = 'com.yourpackage.yourlibrary'
version = '1.0'
Add the following code in your settings.gradle:
rootProject.name = 'yourlibrary'
Then publish it to your local maven with:
./gradlew install
Or you can use gradle option in Android Studio.
Your library will be installed in $HOME/.m2/repository. Remember that to use the library you need to add like this:
Groupid:artifactid:versionid
Artifactid will be package name of your library.
B. Here the step in your Project which using the library:
Add the following code in your root build.gradle:
mavenLocal() // for local maven.
This for getting the local library maven that we have installed in step A
Then in your app project.gradle, add compile for the library:
compile 'com.yourpackage.yourlibrary:yourlibrary:1.0'
Read more:
Gradle: How to publish a Android library to local repository
https://github.com/dcendents/android-maven-gradle-plugin
https://inthecheesefactory.com/blog/how-to-upload-library-to-jcenter-maven-central-as-dependency/en
From my Knowledge 1. As others said try creating your own Module or Library and use it where ever you need 2.Use Version Control Tools Like Git(If your code changes it will be refleted in your git account)
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
I'm wondering what is the best / intended way of defining build script repositories and dependencies for Android library projects.
Out in the wild (like Github) most of the repos define the following in there build.gradle
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.0.0'
} }
But if I create a library project in Android Studio this buildscript block does not get created, as it is already in the root build.gradle file, and therefore not necessary (I assume).
So what is the proper way, only defining it once in the root build.gradle or for each library project (which also means updating the version number for each library in case of new plugin versions). Or does it depend whether I want to release the library independently from my main application?
If you're developing a library, there isn't really a top-level build.gradle: that top level applies to all modules in a multimodule project, but a library is best implemented as a standalone single module.
Probably the best practice would be to have a single build.gradle file for your library module, and include a buildscript block in it with the repository and Android plugin Gradle version. That way it stands alone better, and it's not implicitly dependent on being in a project that has a top-level build.gradle file.
There's a huge caveat which kind of renders a lot of this moot, however -- if you include this module, with its own buildscript block, in a project that has a top-level build.gradle with a competing buildscript block, the top-level build file will win and it will ignore the block in your module.
This probably isn't much of a problem, but if your module relied on a specific version of the Android Gradle plugin, for example, and it was in a project that used a different version of the plugin, then your module would lose and it could run into problems. Another way of saying it is that it can only use one version of a plugin for all of the modules in a single build, and I believe the first one to specify it sets it for everyone.
In practice, this is only likely to be an issue if you rely on some feature specific to a later-than-1.0 version of the Android Gradle plugin, and it's included in a project that uses 1.0.
There are some subtleties here that I'll mention but won't answer (and I apologize for answering your question with more questions) -- if anyone else knows for sure, please answer yourself, or edit my answer, or mention it in the comments:
What if your buildscript block adds new plugins to the classpath? Do they get added or are they ignored?
What if your buildscript block adds new repositories to the search path? Will they get picked up?