Android connected tests common code move to library module - android

I have 2 project modules: A, B and a library module. Both projects using a library. I also have some connected tests in both projects (UI Automator). That tests have common utility code that I'd like to move to the library. How can I do it?
What I've tried. First way:
Copy common code to library project to src/androidTest/java/xxx
folder
Add to library build.gradle UI automator dependencies under
androidTestCompile
Add to project build.gradle following:
dependecies {
...
androidTestCompile project(path: ':library', configuration: "debug")
...
}
That cause build issue in project because as I understand src/androidTest folder is not used during building debug configuration
Second way:
First 2 steps are same
Add to library build.gradle
task connectedTestsJars(type: Jar, dependsOn: "assembleXXXAndroidTest") {
classifier = 'connectedTests'
includes = ['com/**']
from "$buildDir/intermediates/classes/androidTest/XXX"
}
configurations {
connectedTestArtifact
}
artifacts {
connectedTestArtifact connectedTestsJars
}
Add to project build.gradle
dependencies {
...
androidTestCompile project(path: ':library', configuration: "connectedTestArtifact")
...
}
That way all compiles fine. It crashes during connected test runtime because of missing resources from library (it has a lot of common code and resources from both projects)
As I understand that happens because I am using only sources from the library, but I need to use aar file instead (aar with adding src/androidTest contents?).
What will be task type in that case? Or what actions I should make in my custom task to get aar file as result? Other way?
I understand that I can move connected tests common code to another (second) library module and use, but I'd like to avoid it to save compilation time.
Is there any way to keep current module structure and move connected tests common code to library module?

I did find a solution. Add to project's build.gradle:
android {
sourceSets {
androidTest {
java.srcDirs = ['../<LIBRARY_MODULE_NAME>/src/androidTest/java', 'src/androidTest/java']
}
}
...
}
I am sure there is a better solution since the common code will be compilated in both projects. Who knows it?

Related

Use buildSrc module versions in app module

I'm following this tutorial on how to manage Gradle dependencies with Kotlin in my Android app and now I would like to use the versions defined in my Versions object in my app module (the scenario is that I have an open source screen and I want to show the library versions). How can I do this?
I have tried adding the buildSrc directory to settings.gradle:
include ':app', ':buildSrc'
and then in my build.gradle file, adding it to the dependencies block:
dependencies {
implementation project(':buildSrc')
}
However, when I try to compile and run, the following error is thrown:
Don't know how to compute maven coordinate for artifact 'Gradle API' with component identifier of type 'class org.gradle.internal.component.local.model.OpaqueComponentIdentifier'.
and there is no much information in the web about this error.
Try to remove the buildSrc module from your settings & build.gradle. Its automatically build and accessible for all other modules in this project.

Difference between three dependencies

in one example, I saw three dependencies block in build.gradle.
example:
root folder: build.gradle
1.
buildscript{
dependencies{
}
}
2.Under android block
android{
dependencies{
}
}
I see one more dependencies block on root folder
buildscript{
}
dependencies{
}
android{
}
First two are been explained in Android developer site.
1st: is applicable for complete project
2nd: per module.
I am not understanding what 3rd dependency block means.
It's a bit confusing because Android Studio by default shows both build.gradle files right next to each other (when using the Android view).
If you switch to the Project view you can see the actual structure and where the different build.gradle files are located.
The build.gradle (Project: MyApplication) file is in the root folder of the project and its configuration settings apply to every module in the project. A module is an isolated piece of the bigger project. In a multi-module project, these modules have their own jobs but work together to form the whole project. Most Android projects only have one module, the app module.
The build.gradle (Module: app) file here is in the app folder. Its build settings apply only to the app module. If there were another module, then the it would have its own build.gradle file, too. As an example, I made a library project with three modules: a library module, a demo app module, and another app module that I plan to use for testing. Each of them have their own build.gradle files that I can tweak.
In a basic project, almost everything you need to edit will be in the app module's build.gradle file. You can remember it like this:
You're making an app, so go to the build.gradle (Module: app) file.
Further reading
Configure Your Build (Android documentation--very readable and useful)
Introduction to multi-project builds (Gradle documentation)
First two are been explained in Android developer site. 1st: is applicable for complete project 2nd: per module.
It is not exact.
The buildscript block can be specified in the root level but also in the module build.gradle file.
These dependencies block only controls the dependencies for the buildscript process itself, not for the application code.
2.Under android block
android{
dependencies{
}
}
It is not correct.
The correct syntax is:
android {
...
}
...
dependencies {
...
}
Don't put these dependencies in the top-level file.

`rootProject` in a Gradle module that's imported to another project

In my current setup I have two top-level Gradle projects:
A library project VideoPresenter with modules
videopresenter-common
videopresenter-exoplayer
videopresenter-visualon
where both videopresenter-exoplayer and videopresenter-visualon depend on videopresenter-common.
All three of the modules depend on OkHttp so I defined a version variable in my top-level build.gradle:
ext {
okhttp = 'com.squareup.okhttp3:okhttp:3.0.0-RC1'
}
which I use in the three other build.gradles:
dependencies {
compile rootProject.ext.okhttp
}
So far, this is completely analogous to the way, for example, RxBinding is set up. And it seems to work as long as I compile the modules from within this project.
However, I also have an application project that uses one or more of these modules. Let's say the settings.gradle of that project includes the following:
include ':videopresenter-common'
include ':videopresenter-exoplayer'
project(':videopresenter-common').projectDir = new File('../VideoPresenterAndroid/videopresenter-common')
project(':videopresenter-exoplayer').projectDir = new File('../VideoPresenterAndroid/videopresenter-exoplayer')
Now, when I try to compile the application project Gradle complains because it
Cannot get property 'okhttp' on extra properties extension as it does
not exist
presumably because rootProject now points to the top-level build.gradle of my application project.
If I add the property there the project compiles. However, I don't want to have to "inject" the correct version number from the main project into the library project. Is there a way to centrally declare the property in the library project so that it also applies when the module is imported into another project?
If the goal is to get the value from the library then you could just get the library project's rootProject then reference the ext like before. Being specific about what project we are looking for should provide the expected result.
dependencies {
compile project(':videopresenter-common').rootProject.ext.okhttp
}
As long as the project is in the settings.gradle you should be able to reference it's extension.

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?

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