Android: I have some files shared by other projects, and like them packaged under assets/.
/android/app/src/main/assets/a.xml
/projects/shared/b.xml
how to put both a.xml and b.xml under assets/ in apk?
You can add arbitrary directories to the locations that Gradle (and the Android Plugin for Gradle) looks for assets.
For example, when testing migrations in Room, we use this to get our Room-generated historical schemas added to our instrumentation test's assets:
sourceSets {
androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
}
Here, we are saying that we want to add a new directory to the set of directories that populate the assets for the androidTest source set.
Similarly, you could do something like:
sourceSets {
main.assets.srcDirs += ...
}
where you would have to figure out the appropriate ... to point Gradle to wherever your other files are.
Note that the sourceSets closure goes inside the android closure of your module's build.gradle file.
Related
After upgrade to Android Studio Chipmunk, my test failed because I can't access file inside shared folder that defined in build.gradle like this.
sourceSets {
androidTest.java.srcDirs += "src/sharedTest/java"
test.java.srcDirs += "src/sharedTest/java" }
It show warning pop up with message "Duplicate content root detected". Path [sharedTest] of module [unitTest] was removed from modules [androidTest]. Anyone can resolve this?
According to https://issuetracker.google.com/issues/232007221 ("Duplicate content roots detected" with Android Gradle plugin 7.2.0) Google no longer supports this construct in Android Studio Chipmunk 2021.2.1.
https://issuetracker.google.com/issues/232007221#comment17 says "Source sets can no longer contain shared roots as this is impossible to represent in the IDE."
To follow the on-going discussions, subscribe to
https://issuetracker.google.com/232007221 and
https://issuetracker.google.com/232420188
https://issuetracker.google.com/issues/232420188#comment19
The current recommendation is to use a separate com.android.library Gradle project to store any shared code required across test and androidTest.
According to (#kreker thx for the hint): https://issuetracker.google.com/issues/232420188#comment19
The current recommendation is to use a separate com.android.library Gradle project to store any shared code required across test and androidTest.
But often (at least for me) it is enough just to create a separate java project, move the shared test code into this new project and create two additional testImplementation and androidTestImplementation project dependencies to the new shared project.
Step-by-step (maybe it helps) I did it as follows: 1. next to the app folder create a new folder called sharedTest (or something similar). 2. create the sub-directories sharedTest/src/main. 3. Move (or rather git mv in order not to loose the version history) the shared test code: git mv app/src/sharedTest/java sharedTest/src/main/ (and do not forget to check-in). 3. in sharedTest create a new (minimal) sharedTest/build.gradle.kts file:
plugins {
java
}
dependencies {
}
java {
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
}
4.Edit the settings.gradle.kts file and add the new shared project: include(":sharedTest"). 5. Edit the app/build.gradle.kts file: remove the conflicting shared source-set section android{...} and add 2 new dependencies:
dependencies {
//Share Code between androidTest and test
//https://stackoverflow.com/questions/72358843/sharedtest-got-warning-duplicate-content-root-detected-on-android-studio-chipm
testImplementation(project(path = ":sharedTest"))
androidTestImplementation(project(path = ":sharedTest"))
}
I am trying to swap some resources in the res/raw folder and the jniLibs/armeabi folder based on whether its a release buildType or a debug buildType. I currently have two product flavors as well.
The build.gradle file:
apply plugin: 'com.android.application'
android {
dexOptions {
preDexLibraries = false
}
compileSdkVersion 21
buildToolsVersion "22.0.1"
defaultConfig {
applicationId "com.example.test"
minSdkVersion 17
targetSdkVersion 22
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
}
productFlavors{
phone{
applicationId "com.example.testPhone"
}
tablet{
applicationId "com.example.testTablet"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
sourceSets{
release{
res.srcDirs = ['androidRelease/res/raw']
}
}
}
dependencies {
compile project(':facebook')
}
Is using sourceSet the right way to do so? If it is, what folder should be created so that it swaps the appropriate resources based on the buildType only and irrespective of the productFlavors?
EDIT: Is it even possible to swap jniLibs and raw folder resources?
Folder Structure:
src/main/jniLibs/armeabi
phoneRelease/jniLibs/armeabi
tabletRelease/jniLibs/armeabi
Is the folder structure correct.?
EDIT 2:
Based on Xavier's answer should the gradle look like this:
android {
sourcesets {
phone {
jniLibs.srcDirs = ['phoneRelease/jniLibs/']
res.srcDirs = ['androidRelease/res/raw']
}
tablet {
jniLibs.srcDirs = ['tabletRelease/jniLibs/']
res.srcDirs = ['androidRelease/res/raw']
}
}
}
I keep reading lot of conflicting answers, some of them mention that you just need separate folders based on build variant and some mention about having to use sourceSet?
Thanks!
some of them mention that you just need separate folders based on build variant and some mention about having to use sourceSet?
Gradle/Gradle for Android has an expected structure for a sourceset:
Android resources in res/
Java source tree in java/
Pre-compiled JNI libraries in jniLibs/
Assets in assets/
Etc.
Where the sourceSets closure comes into play is if, for a given sourceset, you want a different structure:
Android resources in foo/
Java source tree in bar/
Pre-compiled JNI libraries in ickyNativeStuff/
Assets in assetsBecauseThatSeemsLikeADecentName/
Etc.
Each build type, product flavor, and build variant can have a separate sourceset (as can androidTest for instrumentation testing), to go along with main. They are named the same as the build type/product flavor/build variant. These will be in the stock structure, unless you use sourceSets to change things.
So, to roll all the way back to:
I am trying to swap some resources in the res/raw folder and the jniLibs/armeabi folder based on whether its a release buildType or a debug buildType
In the case of resources, other sourcesets overlay main. So, if you have src/main/res/... and src/main/debug/... and src/main/release/..., and you are doing a debug build, whatever is in src/main/release/... is ignored (as we aren't doing release) and whatever is in src/main/res/... and src/main/debug/... will be used. If there is the same resource in both (src/main/res/raw/boom.ogg and src/debug/res/raw/boom.ogg), the debug one trumps the main one.
I have not experimented with varying jniLibs/ by build variant. My guess is that it will behave more like Java code, where you cannot have conflicts between what is in a build variant's sourceset and what is in main, but that's just a guess. So, you can have the debug version of your compiled JNI code in src/debug/jniLibs/ and the release version of your compiled JNI code in src/release/jniLibs/. Only have in src/main/jniLibs/ any libraries that are not varying. That being said, as I mentioned, I haven't tried this, and so there may be hiccups here.
So, I would expect you to not have a sourcesets closure in build.gradle, and to just use the stock sourcesets structure, for your various bits:
src/
main/
...
debug/
jniLibs/
res/
raw/
release
jniLibs/
res/
raw/
Anything that's normally under src/main/ can be put in a different folder:
src/<element>/AndroidManifest.xml
src/<element>/java
src/<element>/res
src/<element>/assets
src/<element>/resources
src/<element>/jni
src/<element>/jniLibs
src/<element>/aidl
src/<element>/rs
Where element is the name of a build type or a product flavor. If your variant includes such a element (build type or flavor), then that source set is also used in addition to src/main
Note that the location is really not relevant if you have configured it.
What matters is that there is a android.sourcesets.main element that contains the sources common to all variants, and each variant has a set of sourcesets.
For instance if you have a flavor phoneRelease it's really using the following sourcesets:
android.sourcesets.main
android.sourcesets.phone
android.sourcesets.release
android.sourcesets.phoneRelease
If you have another variant tabletRelease, it'll use the following:
android.sourcesets.main
android.sourcesets.tablet
android.sourcesets.release
android.sourcesets.phoneRelease
So the phone/tablet sourceset is different and is where you'd put the variant specific sources, unless you want to be even more specific and use the phoneRelease/tabletRelease sourcesets (though those are less used generally.) By default these would be src/phone/... and src/tablet/... (or src/phoneRelease/...) but you can change that however you want and as long as it's connected to the android.sourcesets.* objects it'll be fine.
for example, doing:
android {
sourcesets {
phone {
jniLibs.srcDirs = ['phoneRelease/jniLibs/']
}
tablet {
jniLibs.srcDirs = ['tabletRelease/jniLibs/']
}
}
}
is fine. But do be aware that you only changed the jniLibs folder and not the other source elements (java, res, etc...)
If you kept the default location for the main sourcesets, I'd just keep everything under src/
You can see more info about sourcesets and how multiple sourcesets are combined here: http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Sourcesets-and-Dependencies
To use flavors to vary source sets,
productFlavors{
phone{
}
tablet{
}
}
Now structure your code like,
src
main
phone
tablet
The code in main is common between both flavors, but the code in phone or tablet is only included when the respective flavor is built. That's it, you don't need to do anything else.
The structure under phone and tablet is the same as under main (res, java, etc). You can also have a custom AndroidManifest.xml under the flavor directory. Gradle attempts to merge the flavor's AndroidManifest.xml with the one in main. In some cases you have to provide rules for how to merge.
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!
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
}
We have a project structure of the form
srcsrc_flavor1src_flavor2resres_flavor1res_flavor2
The core logic and resources are placed in src and res folder resp. The flavoured folders only contains few files which separate the two flavors.
Im trying to define this project structure withing the build.gradle file but havnt found any success. Also Im trying to use the prductFlavor tags to create simultaneous builds of the two flavors but no success. Doing all this within the Android Studio latest build
Assuming you have define your flavors like this:
productFlavors {
flavor1 {
...
}
flavor2 {
...
}
}
You can modify the sourceSets of each flavor
android.sourceSets.flavor1 {
java.srcDirs = ['src_flavor1']
resources.srcDir = ['res_flavor1']
}
android.sourceSets.flavor2 {
java.srcDirs = ['src_flavor2']
resources.srcDir = ['res_flavor2']
}
I hope this help... (don't hesitate to add more details about your problems since it will help us to help you)
Last remark: according my experience, Android-Studio is not very stable yet and not full-featured yet regarding gradle<-->IDE sync. So I strongly suggest you to always test your gradle scripts from the command line.