I have an issue with adding a cpp folder and CMakelist.txt file to a specific flavor in android studio.
I was working on three separate apps with a unique database structure, so I tried to make these three apps as one application using build flavors and other related settings.
For the first two apps, it did so well, but for the last one, I faced an issue that I had no idea how to add cpp folder and CMakelist.txt file to that specific flavor using Gradle. As you may have guessed, the last application is NDK based and uses a CMakelist.txt file and has an activity that works with JNI.
android {
...
defaultConfig {
applicationId "com.example"
...
externalNativeBuild {
cmake {
cppFlags ""
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
flavorDimensions 'program'
productFlavors {
first {
dimension = 'program'
applicationIdSuffix = '.first'
}
second {
dimension = 'program'
applicationIdSuffix = '.second'
}
third {
dimension = 'program'
applicationIdSuffix = '.third'
externalNativeBuild {
cmake {
relativeProjectPath "src/third/cpp/CMakeLists.txt"
version "3.10.2"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
ndk { abiFilters "arm64-v8a" }
}
debug {
ndk { abiFilters "arm64-v8a" }
}
}
}
}
I am using a relativeProjectPath method in gradle, and expect that CMakelist.txt links with my cpp folders but nothing happens.
I have not tried it that way. What worked for me in my previous projects is this.
android {
...
flavorDimensions "program"
productFlavors {
...
third {
dimension "program"
externalNativeBuild.cmake {
arguments "-DFLAVOR=THIRD_PROGRAM"
}
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
...
}
Then in your CMakeList.txt, do this conditional test
if(${FLAVOR} STREQUAL "THIRD_PROGRAM")
// build your cpp codes for flavor THIRD
else()
// nothing to build?
endif()
Note that my CMakeList.txt is in app/ directory.
Related
I have this gradle:
android {
...
buildTypes {
debug {
externalNativeBuild {
cmake {
cppFlags "-DGENDEV"
}
}
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
...
}
This if condition works fine in my CMakeList file:
if("${CMAKE_CXX_FLAGS}" MATCHES "GENDEV$")
// true
endif()
I recently added flavors in my build like so:
flavorDimensions "version"
productFlavors {
free {
dimension "version"
externalNativeBuild.cmake {
cppFlags "-DFLAVOR_FREE"
}
}
full {
dimension "version"
externalNativeBuild.cmake {
cppFlags "-DFLAVOR_FULL"
}
}
}
Now, I have these checks in my CMakeList file:
if("${CMAKE_CXX_FLAGS}" MATCHES "FLAVOR_FULL$")
// full version
else()
// free version
endif()
if("${CMAKE_CXX_FLAGS}" MATCHES "GENDEV$")
// true
endif()
The first check is always false, thus every build is a FREE version! What am I doing wrong?
Your code is alright, but the Gradle plugin was too old to handle it correctly.
For me, same code worked with
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.2'
}
}
This plugin requires Gradle 5.5.
Note that an easier approach to CMake integration could be to specify arguments:
flavorDimensions "version"
productFlavors {
free {
dimension "version"
externalNativeBuild.cmake {
arguments "-DFLAVOR=FREE"
}
}
full {
dimension "version"
externalNativeBuild.cmake {
arguments "-DFLAVOR=FULL"
}
}
}
This way, your CMakeLists.txt will be more readable:
if(${FLAVOR} STREQUAL "FULL")
// full version
else()
// free version
endif()
Or, you can choose to use arguments "-DFLAVOR_FULL" and if(FLAVOR_FULL)
I want to also point out that MATCHES is matching a regex expression. Thus, changing the following:
if("${CMAKE_CXX_FLAGS}" MATCHES "FLAVOR_FULL$")
to
if("${CMAKE_CXX_FLAGS}" MATCHES "FLAVOR_FULL") // without the $
helped solved the problem. Basically, the original condition means to match the "FLAVOR_FULL" text if it is at the end of the string such as "-DGENDEV -DFLAVOR_FULL". This won't match if the string is "-DFLAVOR_FULL -DGENDEV".
I am creating an android project with different product flavours. My project structure is like this
Flavor1
Flavor2
Main
where Flavor1 contains a Constants.java file, Flavor2 also contains a Constants.java file but it is not in main. My main package contains another class Controller that uses variables defined in Constants. When I try to run my project it throws an error 'Cannot resolve symbol Constants'.
When I press alt+enter it imports the file from selected flavor and the error is gone but when I switch to other flavor it doesn't identify the import because it's from flavor1.
Here is code from my build.gradle file than defines product flavors and sourcesets.
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
debuggable true
applicationIdSuffix ".debug"
}
}
productFlavors {
Flavor1{
applicationId = "app.com.Flavor1
}
Flavor2{
applicationId = "app.com.Flavor2
}
}
sourceSets {
main{
java {
srcDirs('src/Flavor1/java/src', 'src/Flavor2/java/src','src/main/java/src')
}
res {
srcDirs('src/Flavor1/res/src', 'src/Flavor2/res/src','src/main/res/src')
}
}
Flavor1{
java {
srcDirs('src/Flavor1/java/src', 'src/main/java/src')
}
res {
srcDirs('src/Flavor1/res/src', 'src/main/res/src')
}
}
Flavor2{
java {
srcDirs('src/Flavor2/java/src', 'src/main/java/src')
}
res {
srcDirs('src/Flavor2/res/src', 'src/main/res/src')
}
}
}
I want every flavor to have its own Constants File. How this can be achieved? How can I use Constants file of every flavor in main so that it imports or uses file of selected Build Variant?
Any help will be appreciated.
I am trying to generate a static library using CMAKE and Android Studio(2.3.2). Below is what my CMakeLists.txt looks like. I am unable to generate .a file, however when I change the library to SHARED, CMakeTestModule.so file gets generated when I do "Build->Rebuild Project". Is it required for me to add/set any flag for building STATIC libraries.
cmake_minimum_required(VERSION 3.4.1)
project (CMakeTestProject)
include_directories(
src/main/cpp/
)
add_library(
CMakeTestModule
STATIC
src/main/cpp/CMakeTestModule.cpp
)
add_executable(
CMakeTestModule_test
src/main/cpp/CMakeTestModule_test.cpp
)
target_link_libraries(CMakeTestModule_test CMakeTestModule)
This is what my build.gradle looks like:
apply plugin: 'com.android.library'
android {
compileSdkVersion 16
buildToolsVersion "25.0.0"
defaultConfig {
minSdkVersion 8
targetSdkVersion 8
externalNativeBuild {
cmake {
abiFilters 'armeabi'
}
}
}
externalNativeBuild {
cmake {
path 'CMakeLists.txt'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
}
I fixed this issue by specifying the target in the build.gradle. Something like below. Since apk only uses .so files, we need to mention the targets for static libraries and executables.
apply plugin: 'com.android.library'
android {
compileSdkVersion 16
buildToolsVersion "25.0.0"
defaultConfig {
minSdkVersion 8
targetSdkVersion 8
externalNativeBuild {
cmake {
abiFilters 'armeabi'
}
targets "CMakeTestModule_test", "CMakeTestModule"
}
}
externalNativeBuild {
cmake {
path 'CMakeLists.txt'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
}
here's a piece of my build.gradle file:
android {
//...
defaultConfig {
//...
externalNativeBuild {
ndkBuild {
targets "MyGame"
arguments "NDK_MODULE_PATH=$cocospath:$cocospath/cocos:$cocospath/external:$cocospath/cocos/prebuilt-mk:$cocospath/extensions"
arguments "-j" + Runtime.runtime.availableProcessors()
buildTypes {
debug {
abiFilters "armeabi", "armeabi-v7a", "arm64-v8a"
}
release {
abiFilters "armeabi"
}
}
}
}
}
//.........
I'm trying to use three abi filters (armeabi, armeabi-v7a and arm64-v8a) while building app in debug mode and use only one (armeabi) while building release apk. But it doesn't work. Either debug and release version are using all three abiFilters.
What's wrong with my gradle file?
edit:
It turns out when I had all three abi filters and successfully build app I wanted to leave just armeabi and... still all three were added. I had to manually delete contents of app/build directory.
You put your aabiFIlters in a wrong block. This is how it will work:
android {
//...
defaultConfig {
//...
externalNativeBuild {
ndkBuild {
targets "MyGame"
arguments …
}
}
}
buildTypes {
release {
ndk {
abiFilters "armeabi-v7a"
}
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
ndk {
abiFilters "x86", "armeabi-v7a"
}
}
}
}
I want to add an if or something similar to my gradle build script, that decides wether to sign my App with the Debug-Key or Release Key accodring to what buildType I'm using. I can't do that in the buildTypes section, because if have different release keys for my product flavours. I tried it with something like buildType.name, but gradle does not know this property.
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard.txt'
}
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard.txt'
}
}
signingConfigs {
app1 {
....
}
app2 {
....
}
}
productFlavors {
app1 {
applicationId "com.test.app1"
}
app2 {
applicationId "com.test.app2"
if (buildType.name == 'release'){
signingConfig signingConfigs.app2
}
}
}
Edit: Ok I managed to solve it via gradle.properties: I add a property and set it true or false in buildtypes, and an if in the productFlavour add the signConfig if true.