Gradle composite builds with custom repositories in Android Studio - android

Our company requires we have all our dependencies downloaded from our internal repository (Artifactory). Our Android project has the main Android modules, plus composite builds.
I was able to replicate the issue creating a simple project from Android Studio, and adding a composite build (or buildSrc) into it.
More or less like this (I didn't include the other files above to keep it simple):
project
├─ app (<-- application module)
├─ plugins (<-- composite build )
│ ├─ settings.gradle.kts (<-- settings for composite build)
├─ settings.gradle.kts (<-- settings for main project)
Both settings.gradle.kts (main + composite build projects) have something like this (again, leaving irrelevant elements out of it):
pluginManagement {
repositories{
maven(url="https://artifactory.mycompany.org")
}
}
dependencyResolutionManagement {
repositories{
maven(url="https://artifactory.mycompany.org")
}
}
This works perfectly while running from terminal (e.g. ./gradlew build), but the sync operation via Android Studio seems to always trigger dependencies download from *.gradle.org. After the sync, all the other project dependencies for build operations seem to work on Android Studio. If I create a project without composite builds (or buildSrc) it seems the issue doesn't happen.
This has been creating many issues, as you can imagine, but it doesn't seem that many people have been reporting the exact same experience. Apart from the issue of downloading dependencies from a different repository, it is also downloading these dependencies multiple times during the day.
I've also checked environment variables, Java SDK, etc to match between Android Studio and terminal, and Android Studio is also configured to use gradle from "gradle-wrapper.properties".
Has anyone faced similar issue, and has any clues on what else I could be missing? Or could that be an issue on the Android Studio gradle plugin?

Related

Minimum Necessary files for an android build

Trying to find the bare minimum source and build files needed to build an android project in Android Studio. I want to publish to github and avoid uploading generated build files or binaries.
I do have a Android.gitignore from but I still see some more files getting pushed into the repo which may not be necessary. I understand the few obvious ones but about others, do I need them and if so kindly explain the usage.
So the question, do I need the following and if so then a short description of why?
root
build.gradle
gradle.properties
gradlew
gradlew.bat
settings.gradle
/app
app/build.gradle
app/proguard-rules.pro
/gradle (tested, android can re-download/generate following it if not present)
gradle/wrapper/gradle-wrapper.jar
gradle/wrapper/gradle-wrapper.properties
This question can have two different answers based on the meaning of the word needed.
First (the real one)
Assuming your project has currently those files, if your question is:
Should I commit these files on my Git repo?
The answer is yes, all of them, and I'm explaining why:
root
build.gradle -> defines the configuration for all the Gradle modules in your project (e.g. use the same remote repositories to download some Gradle plugins)
gradle.properties -> defines some optional flags used when building the app (e.g. enabling the incremental KAPT, enabling the AndroidX jetifier)
gradlew -> invokes the Gradle wrapper (which can be found under gradle/wrapper/gradle-wrapper.jar) to avoid to have Gradle installed when building your project on Darwin/Linux
gradlew.bat -> the same of gradlew but for Windows
settings.gradle -> defines the list of modules which are part of your project
app/
app/build.gradle -> defines the configuration only for your app module (e.g. its build types, its flavors, its version code and version name)
app/proguard-rules.pro -> defines the obfuscation rules when your app enables the minification
gradle/
gradle/wrapper/gradle-wrapper.jar -> provides the same version of the Gradle wrapper jar for all the users. This is very important because it forces the users to use the same version of the Gradle wrapper to compile your app
gradle/wrapper/gradle-wrapper.properties -> same as above, it defines which version of the Gradle wrapper you need
Second (the useless one)
Now, I'll give you the answer to the question:
Are these files strictly needed to compile an Android project?
To successfully compile an Android project with Gradle you just need the root build.gradle if you have Gradle installed on your machine or build.gradle + the wrapper files if you have not Gradle installed on your machine.
Theoretically you can:
put your application code in the root project and that avoids you one build.gradle and settings.gradle
disable the obfuscation and that avoids you proguard-rules.pro
remove gradle.properties and set the properties via command line
Obviously this solution won't happen on a real project scenario.

Assemble gradle flavour compiles dependencies from other flavors

We are trying to develop 2 gradle flavors to speed up our development process:
the local flavor that compiles our libraries as modules
the remote flavor that uses the latest SNAPSHOTS of our libraries
I have declared two flavors in gradle:
productFlavors {
local {}
remote {}
}
For now, let's assume that both our local and remote libraries are available as local modules (for debugging purpose). I have created a sample project here. Since each library has sub libraries that are also supposed to be local or remote, I have added:
dependencies {
localCompile project(path: ':mylibrary', configuration: "localDebug")
remoteCompile project(path: ':mylibrary2', configuration: "remoteRelease")
}
Now it becomes tricky. If I call gradle assembleLocalDebug, I get this line:
:mylibrary2:compileRemoteReleaseJavaWithJavac UP-TO-DATE
In the case of the sample app, it compiles. But in our case, we have a project where the newest features cannot be found in the SNAPSHOTS (since they are not published yet). This shouldn't happen since we are building in local. Is there any way to prevent gradle from compiling the remote flavor?
What you want to do might be solved in the latest versions of Gradle.
With Gradle 3.1, you can now use the so-called "composite builds".
As an example, say you have a library L, deployed on a remote repository, and a project P depending on L. Imagining that both L (say, "libL/") and P ("projectP") are in the same directory on your system, you can build the "local" version by running the following command from projectP:
$ ./gradlew --include-build ../libL build
Moreover, composite builds are coming in Android Studio!

How to reuse the submodule in Gradle?

I have two following Android Studio project, structure like this:
projectA/
├----build.gradle
├----settings.gradle
├----bluewhale/
├----krill/
projectA settings.gradle file:include 'bluewhale', 'krill'
projectB/
├----build.gradle
├----settings.gradle
├----hello/
├----krill/
projectB settings.gradle file:include 'hello', 'krill'
You can see "projectA" and "projectB" contain the same module "krill". Actually, it's a library project.
My question is: how to reuse the submodule "krill" in Gradle? I don't want to include the same copy of "krill" in every project
Looking forward to your reply! Thanks!
If you have a sub-module that is used in multiple projects, you should think about extracting it to a separate project. Then you can create a dependency out of it and include it in both projects in dependencies section.
If you only use your local machine for development, without any custom repository, the best way would probably be to use the mavenLocal() repository. You can use the maven publish plugin to publish your jar into the local maven repository. It should be as simple as adding this to the new krill:
apply plugin: 'maven'
apply plugin: 'maven-publish'
publishing {
publications {
maven(MavenPublication) {
from components.java
artifact sourceJar {
classifier "sources"
}
}
}
}
repositories {
mavenLocal()
}
You might want to set the group and artifact ID. See the documentation for more info.
You can also keep krill in one of the projects, let's say ProjectA, if it has some relation to it. Then you set up the maven publishing in the krill sub-module. You can also publish to maven local by running gradle :krill:publishToMavenLocal and then use it as dependency in ProjectB.
Another option is to save the submodule outside the projectA and projectB trees and add it using something like this:
include("krill")
project(":krill") {
projectDir = new File("$settingsDir/../krill")
}
But I can't recommend this because it's hacky and your IDE might have a problem with it too.
Last thing that might be possible is to create symlinks from a directory where your krill project is located to both ProjectA and ProjectB. But that is a really bad idea e.g. when you are using a version control.
Finally I found an article here: an-alternative-multiproject-setup-for-android-studio. It works for me perfectly!
It shows us another Way different from Google’s Gradle Plugin user guide recommends
Sample code below: (Add this script to your project settings.gradle file)
include ':krill'
project(':krill').projectDir = new File('../otherProject/krill')
Project structure below:
RootFolder/
├----projectA/
│ ├----build.gradle
│ ├----settings.gradle
│ └----bluewhale/
│
├----projectB/
│ ├----build.gradle
│ ├----settings.gradle
│ └----hello/
│
└----otherProject/
├----krill/
│ └----build.gradle
│
└----otherModule/
└----build.gradle
For more details, visit gradle official document: Multi Project Builds

Dependency issues in reference project

I have an issue that dependencies of a project that is referenced as a dependency module in my android app seem not to be included into the .apk file of my android application.
Project Setup
Android App (Android studio & gradle)
Java desktop application (IntelliJ/maven/gradle project)
Java model (classes & features used by both android & desktop app)
The "Java model" is added as a dependency to both Android App and Java Desktop application.
When I run the desktop application, the dependencies of the JavaModel are resolved via maven, incuded into the application and everything runs smoothly.
From an Android Studio point of view, I have imported the JavaModel as a module into the android project and gradle is used to resolve the dependencies. I have set up the following gradle files:
Android App "settings.gradle"
include ':app'
include ':JavaModel'
project(':JavaModel').projectDir=new File('../../JavaModel')
Android App "build.gradle"
dependencies {
compile project(':JavaModel')
// and more...
}
Java Model "build.gradle"
dependencies {
compile(
'org.apache.httpcomponents:httpclient:4.4.1'
// and more ...
)
}
Everything compiles just fine without any errors and a .apk can be created and runs on my test device. However, as soon as I access features within the app that are provided by the "Java model" (in this example, I am using the HttpClient class from the org.apache.httpcomponents:httpclient:4.4.1 dependency), I get the following exception:
java.lang.ClassNotFoundException: Didn't find class
"org.apache.http.impl.client.HttpClients"
Plese note that this is just an example case and the issue also occurs with all other dependencies that are only referenced in the "JavaModel", but not in the Android app itself.
It seems to me like the dependencies of the "JavaModel" work just fine at compile time, since everything executes just fine, but are then not included into the .apk file and therefore cause this exeption.
The question is how can I (correctly) make sure that even dependencies of a dependency project are included into the .apk file?
Apache http client conflicts with android one, if you want to use recent one, you need to use android port https://hc.apache.org/httpcomponents-client-4.3.x/android-port.html
Regarding "JavaModel". If dependencies of JavaModel are compile dependencies it all must work fine (assuming dependency does not have fancy code like classloaders)

Android Maven and Refresh Problem

i've a strange problem with maven and android
I've 3 maven project and 2 normal java maven project divided in this manner :
normal project :
model project ... packaged as jar ... contains java Pojo Bean and Interface.
Dao Project ... packaged as jar ... contains Db Logic - Depend on model Project
Android Application Maven project
ContentProvider ... packaged as apk ... contains ContentProviders only. Depends on Dao Project
Editors ... packaged as apk ... contains only Editor, Depends on Dao project
MainApp ... packaged as apk ... contains MyApp, Depends on DAO ...
The Problem is that if i modify DAO Project , Then do a maven clean and maven install of all apk project, then run as Android Application within Eclipse, i don't see updated app on my Emulator.
Nicely if i shut down my ubuntu workstation and restart it i can see The updated app on my Emulator.
Do you know a solution for this issue ?
thanks and regards
Occasionally, I will have to remove the app from the emulator to get the new version to deploy properly from within Eclipse. I use the following maven command from within the project directory to remove the app. This command assumes you are using the Android Maven Plugin with your Android app.
mvn android:undeploy
Conversely, you can also deploy the app with the following command.
mvn android:deploy

Categories

Resources