Gradle reference to external archive directly - android

How can we refer an archive file ( aar for android or jar in general) from the build.gradle.
eg : compile files('https://--artifactoryonline.com-url--Debug.aar')
Background/Root Cause :
Android Library project has multiple flavors to be supported.
productFlavors {
flavor1 {
// Add any falvor1 flavor specific details here
}
flavor2 {
// Add any flavor2 specific details here
}
}
While the flavors are working fine and aar is generated and uploaded to the articfactory, reference from the maven is not getting resolved as POM files are not generated for library flavors. which in turn leads to maven-metadata.xml not being updated.
This seems to be an issue - Reference :How to upload multiple android archives (one for each flavor)
So to circumvent the situation wanted to get the archive files as they are generated correctly.
Any help would be greatly appreciated!

Related

Duplicate files copied in APK Android - Can it be merged?

In my android project I have included two libraries as JARs into libs folder. And I add them to the build Gradle as below.
dependencies {
compile files('libs/siddhi-core-4.0.0-M13-SNAPSHOT.jar')
compile files('libs/siddhi-execution-math-4.0.2-SNAPSHOT.jar')
}
Those two jar files the have a file with the same name ("org.wso2.siddhi.annotation.Extension") but with different content. And both files are important for the project.
Since it has same name gradle won't build saying
Duplicate files copied in APK
How can I merge those two files into one single file with the same name?
Those two files are text files with a list of Class names. In two files they have two different lists. So I want to merge them into one list in a text file with same name.
Finally I found the answer. In the app build gradle you can specify to merge the conflicting files.
packagingOptions {
merge 'META-INF/annotations/org.wso2.siddhi.annotation.Extension'
}
for details look here https://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.PackagingOptions.html
You can exclude the file from jar by unzip them first and copy the jar without those files,
After that compile that unZip copy file instead of the actual file, like this
task unzipJar(type: Copy) {
from zipTree('libs/siddhi-core-4.0.0-M13-SNAPSHOT.jar')
into ("$buildDir/libs/siddhi-core-4.0.0-M13-SNAPSHOT")
include "**/*.class"
exclude "org.wso2.siddhi.annotation.Extension"
}
dependencies {
compile files('libs/siddhi-execution-math-4.0.2-SNAPSHOT.jar')
compile files("$buildDir/libs/siddhi-core-4.0.0-M13-SNAPSHOT") {
builtBy "unzipJar"
}
}
Please check this, even I didn't get the chance to use it but it should work.
You can not as both files having same name resolution.(org.wso2.siddhi.annotation.Extension).
So it will not going to work .
Lets say some how you have included both the jars than how you are going to use one of them
ie. How runtime will uniquely identify the class as both class have same namespace as well as name.
try this one
dependencies {
compile files('libs/siddhi-execution-math-4.0.2-SNAPSHOT.jar')
compile files("$buildDir/libs/siddhi-core-4.0.0-M13-SNAPSHOT") {
builtBy "unzipJar"
}
}

Avoid packaging jar dependencies into aar

I'm developing an android library for work and we're using some jars that are not available in maven repositories. However, we are not legally allowed to package these jars into our library, the consumer must get those jars themselves in addition to our library.
My problem is that I can't seem to require the consumer of our library to provide these jars (I'm using a test app that includes the aar). I tried the solutions for this similar question to no avail.
I have tried setting them to provided instead of compile in my gradle file:
// Neither of these seem to fix the problem
compile files('libs/externalDep.jar')
provided files('libs/externalDep.jar')
I also tried excluding them in packaging options:
packagingOptions { exclude 'libs/externalDep.jar }`
I can exclude them by adding this to the android tag in my build.gradle:
android.libraryVariants.all { variant ->
variant.outputs.each { output ->
def packageLib = output.getPackageLibrary()
packageLib.exclude('libs/externalDep.jar')
}
They're not added to the aar but building the test app gives me:
com.android.build.api.transformTransformException:
com.android.builder.packaging.DuplicateFileException:
Duplicate files copied in APK VERSION.txt
File1: path/to/jar/in/test/app/project/externalDep.jar
File2: path/to/build/intermediates/exploded-aar/.../jars/classes.jar
To clarify, I'm not concerned at all with maven repo dependencies, those are working fine. I just want whoever uses the library to have to get and add those jars we're using too.
Surely there's a less convoluted way to specify this?
The jar file must be moved up one level, from mymodule/libs/ to mymodule/ as per this answer.
Then in the build.gradle file, change:
compile file('libs/externalDep.jar')
to
provided file('externalDep.jar')
That's it.
It won't be copied into the aar and clients using the aar must provide the jar file themselves.
App projects using the aar can specify compile file('lib/externalDep') as normal.

Gradle: interchangeably use AAR or project dependency

I have an AAR library that I want to distribute to partners along with a sample project that uses it. I want to also use the same sample project for manual testing while developing the AAR library. Thus, I would like to be able to use the library project as a dependency when developing, and the AAR file as a dependency when distributing.
I tried to define two flavors in the sample application:
productFlavors {
aar {}
project {}
}
...and then define dependencies like this:
dependencies {
//other dependencies
projectCompile project(':myLibrary')
aarCompile 'com.example.mylibrary:myLibrary-release#aar'
}
The aar flavor builds if I comment out the dependency for the project flavor, but if I leave both uncommented, Gradle sync fails if the myLibrary directory is not present - despite the fact that the project build flavor is not part of the current build variant.
What is the correct way to do this? Or do I have to choose between creating a whole separate project for distribution or always referencing the AAR even when debugging/testing?

Gradle multi-project conditional dependencry

How would one create an Android Studio (Gradle) multi-project configuration such that projB depends on project(':projA') if projA is defined, but uses a file in libs/ otherwise?
Since it may be asked, in this case projA is an SDK; projB is a test application designed to demonstrate the SDK. If the SDK team gets a bug report, it often includes reproduction steps using projB.
When projB team does work, they do so on RC builds of projA, whereas the SDK team uses projB, with a dependency on project(':projA') so that a debug session can be run.
projB has no specific definition of its dependency on projA; that team takes the projA output from the build server and drops it in the libs/ folder, and has a wildcard dependency.
EDIT
I finally went with this code in the dependencies closure, and it works like a charm:
def sdkRef
project.getRootProject().allprojects.each { proj ->
if (proj.name.equals("Sdk")) {
sdkRef = proj;
return true;
}
}
if (sdkRef) {
println "SDK present in project; using project reference as dependency"
compile sdkRef
} else {
println "SDK is not present in project; using libs/"
}
I wonder if that's something you can do with flavors and build variants.
Through code you might try in your build file :
dependencies {
if (project.getRootProject().findProject(":projectA")) {
compile project(":projectA")
} else {
compile files("libs/projectA.jar")
}
}
One thing you have to consider is that your settings.gradle defines what modules are included in your project. So your two teams might end up with different files anyway for the project.
You can achieve that with productFlavors.
You just have to define:
2 product flavors in projB/build.gradle
a specific dependency for each flavor
android {
productFlavors {
demo{}
sdkdev{}
}
...
}
dependencies{
demoCompile files("libs/projectA.jar")
sdkdevCompile project(":projectA")
...
}
The build will produce 2 apks.
In Android studio, someone from the demo team can run the demo flavor by selecting the "demoDebug" (or "demoRelease") variant (in Build Variant tab) and someone from sdk team will select the "sdkdevDebug" variant.
The gradle.settings must contains references for projA and projB, but a user from demo team will never have to compile projA because the demo flavor have no dependencies on it.

How to Exclude Duplicate C Shared Libraries (.so) in a Multi-Project Android Build?

I get a "duplicate files" conflict when building a parent project with two library modules, which make use of the same libc++_shared.so shared library.
(NOTE: Please do not consider this a "duplicate question". I have read several related posts, which have helped me get this far. However, no posts have provided an answer that works in my case involving NDK artifacts.)
The build was working correctly when I only had 1 such library module. The addition of the second library module is now creating the conflict.
Consider the following project structure: 1 parent project, 2 "child" projects - but each project is located at the same directory level (i.e. Not nested hierarchically)
ProjectA/ (Parent)
LibraryModuleA1/
build/exploded-aar/com.package.name/
LibraryModuleB1/<version>/jni/armeabi-v7a/libc++_shared.so
LibraryModuleC1/<version>/jni/armeabi-v7a/libc++_shared.so
build.gradle (bgA1)
Test_APK_Module A1T/
build.gradle (bgA1T)
build.gradle (bgPA)
ProjectB/
LibraryModuleB1/ (Uses NDK)
build/lib/armeabi-v7a/libc++_shared.so
build.gradle (bgB1)
build.gradle (bgPB)
ProjectC/
LibraryModuleC1/ (Uses NDK)
build/lib/armeabi-v7a/libc++_shared.so
build.gradle (bgC1)
build.gradle (bgPC)
Library Module A1 depends on both Library Modules B1 & C1.
A1 -> B1
A1 -> C1
Projects B and C both have NDK-based code and build/test correctly. Both depend on the libc++_shared.so shared library.
However, when building Project A, I get the following error during the :LibraryModuleA1:packageDebugTest task:
Error: duplicate files during packaging of APK /ProjectA/LibraryModuleA1/build/apk/LibraryModuleA1-debug-test-unaligned.apk
Path in archive: lib/armeabi-v7a/libc++_shared.so
Origin 1: /ProjectA/LibraryModuleA1/build/exploded-aar/com.package.name/LibraryModuleB1/<version>/jni/armeabi-v7a/libc++_shared.so
Origin 2: /ProjectA/LibraryModuleA1/build/exploded-aar/com.package.name/LibraryModuleC1/<version>/jni/armeabi-v7a/libc++_shared.so
You can ignore those files in your build.gradle:
android {
packagingOptions {
exclude 'lib/armeabi-v7a/libc++_shared.so'
}
}
* What went wrong:
Execution failed for task ':LibraryModuleA1:packageDebugTest'.
> Duplicate files copied in APK lib/armeabi-v7a/libc++_shared.so
File 1: /ProjectA/LibraryModuleA1/build/exploded-aar/com.package.name/LibraryModuleC1/<version>/jni/armeabi-v7a/libc++_shared.so
File 2: /ProjectA/LibraryModuleA1/build/exploded-aar/com.package.name/LibraryModuleC1/<version>/jni/armeabi-v7a/libc++_shared.so
:LibraryModuleA1:packageDebugTest FAILED
What I've Tried So Far
I attempted to add the suggested closure to my build.gradle file, but which build.gradle file do I add it to? I have added the closure to bgA1, bgB1, and bgC1 (one at a time), with no success.
The suggested closure says to use exclude 'lib/armeabi-v7a/libc++_shared.so'. Each "child" library module builds the libc++_shared.so file under the build/lib path. However, I noticed that the parent library module copies the libc++_shared.so file under jni/armeabi-v7a/libc++_shared.so inside the build/exploded-aar directory structure. (See above) Should the closure instead read exclude 'jni/armeabi-v7a/libc++_shared.so (i.e. jni vs. lib)?
Since I am using Gradle plugin 0.9.1, I tried using pickFirst in place of exclude, but that wasn't successful either.
Can someone help determine how I should configure the `packagingOptions' closure for my given case?
Thank you for your help!
I ran into the same problem and had no luck with exclude or pickFirst. So I used a somewhat ugly workaround. The idea is to create a 'native-libs' folder in the build directory of the main project, copy all required *.so files from ndk library projects there and then tell the build system to package those libs in the apk.
In my main project (the app project), I explicitely define the list of modules that contain ndk codes on which I depend
// Ndk stuff. We have to explicitely manage our NDK dependencies
ext.jniProjects = [project(':ndklib1'), project(':ndklib2'), project(':ndklib3')]
apply from: '../depend_ndk.gradle'
And then, 'depend_ndk.gradle' is a gradle external script that contains
// Build helper for projects that depends on a native library with a NDK part
// Define the list of ndk library you depend on in project main file :
// ext.jniProjects = [project(':ndklib1')]
// apply from : 'depend_ndk.gradle'
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.12.+'
}
}
import com.android.build.gradle.tasks.PackageApplication
// As a workaround, we create a new 'native-libs' folder in the current project and
// copy all the .so we depend on into it
def ndkLibsDir = new File(buildDir, 'native-libs')
ndkLibsDir.mkdir()
task copyDependingNativeLibs(type: Copy) {
// Doc for copy http://www.gradle.org/docs/current/dsl/org.gradle.api.tasks.Copy.html
println 'jniProjects ' + jniProjects
jniProjects.each {
from(new File(it.buildDir, 'native-libs')) {
include '**/*.so'
}
}
into ndkLibsDir
}
tasks.withType(PackageApplication) { pkgTask ->
pkgTask.jniFolders = new HashSet<File>()
pkgTask.jniFolders.add(ndkLibsDir)
pkgTask.dependsOn copyDependingNativeLibs
}

Categories

Resources