Same native code rebuilt for every build variant [duplicate] - android

I have a project with C++ code (JNI) and lots of build variants and combinations. These are used to implement different brandings / flavors of the app (i.e. colors, styles, icons, ...).
For example there could be build variants for n customers :
customerNDebug
customerNDebugproguard
customerNRelease.
Anyway, the C/C++ layer is the same for each product flavor.
Normally CMake in Android Studio compiles C code for every build variant. This makes sense if you have build variants like "debug" and "release" where the resulting code actually differs. However, for the build variants I have, the compiled output is always the same.
At the moment the compilation of C/C++ code is done using an external tool in our project and I want to compile using CMake in Android Studio only for proper IDE support of C/C++ code. So for me a single build would suffice.
Is it possible to tell Android Studio to build C/C++ code only once, no matter the build variants and flavors?

By default, Android Studio IDE together with CMake and Gradle will generate a series of native build tasks named with externalNative<BuildVariant>Build according to your build types and flavours. If you want to twist this behaviour, some workaround is as below:
Create an Android Studio module project which only builds your native code, e.g. shared-native.
Let the rest of your modules dependent on this project.
For this solution, you need to consider below points:
Put your .so files into a proper location that other projects can see and link with.
You can only include debug and release build types for this shared-native module project to avoid too many times of re-build. Or you can simply to let your other projects depends on the release type so that it will be built only ONCE.

Related

NDK on Android Studio keeps rebuilding all the time, takes forever

I have a big Android Studio project that has a separate module which contains native code.
The native build is defined with CMake and includes a bunch of source files of C++ code.
I noticed that since a very recent update (might be Android Studio 3.5), NDK rebuilds everything ALL THE TIME.
It can happen with a small change in Java code, switching flavor in an unrelated module in the project, incrementing version code, etc.
This is a major problem, since it can waste 10 minutes at a time for no reason.
I could not find a reasonable way to profile NDK builds in Android Studio and check what's causing the rebuild or what's taking so long.
Unfortunately the project's build files are too big to attach here. Any pointers for things to look after?
For the C/C++ code that you build with cmake, make sure you point cmake to a directory where it can keep its object files and binary outputs.
Let's say you have a dependency on Game in your top level CMakeLists.txt like so:
# dependency: Game
set ( game_src_DIR ../Game )
add_subdirectory( ${game_src_DIR} ${CMAKE_CURRENT_BINARY_DIR}/game )
Then the second parameter to add_subdirectory specified the place where AndroidStudio will keep the object files.
The debug and release object files will live in different subdirs, as will each dependency, so switching debug/release will not clash.
This appears to have been a regression in behavior from Android Studio 3.4 and has been fixed in Android Studio 4.1 Canary 4. Release notes are here.
Often, it helps to split the AS project such that the C++ part, possibly with its Java wrappers become a separate (library) module. This module will hopefully be more stable, not sensitive to increments of app version code.
Such module should not define many flavors, but have careful matching to the flavors of other modules. Sometimes, it makes sense even to disable "debug" variants for such library. There was an effort of the NDK team to better handle debug vs. release build switching, but this is still tricky.
But if after these improvements, insignificant changes to the project still cause massive rebuild, I would suggest to consider ccache.

Android Studio CMake build once for all build variants

I have a project with C++ code (JNI) and lots of build variants and combinations. These are used to implement different brandings / flavors of the app (i.e. colors, styles, icons, ...).
For example there could be build variants for n customers :
customerNDebug
customerNDebugproguard
customerNRelease.
Anyway, the C/C++ layer is the same for each product flavor.
Normally CMake in Android Studio compiles C code for every build variant. This makes sense if you have build variants like "debug" and "release" where the resulting code actually differs. However, for the build variants I have, the compiled output is always the same.
At the moment the compilation of C/C++ code is done using an external tool in our project and I want to compile using CMake in Android Studio only for proper IDE support of C/C++ code. So for me a single build would suffice.
Is it possible to tell Android Studio to build C/C++ code only once, no matter the build variants and flavors?
By default, Android Studio IDE together with CMake and Gradle will generate a series of native build tasks named with externalNative<BuildVariant>Build according to your build types and flavours. If you want to twist this behaviour, some workaround is as below:
Create an Android Studio module project which only builds your native code, e.g. shared-native.
Let the rest of your modules dependent on this project.
For this solution, you need to consider below points:
Put your .so files into a proper location that other projects can see and link with.
You can only include debug and release build types for this shared-native module project to avoid too many times of re-build. Or you can simply to let your other projects depends on the release type so that it will be built only ONCE.

Modifying code to suit different configurations in Android Studio

I have different configurations for my Android project (e.g. google, amazon). Gradle allows generating BuildConfig parameters, that can be checked at runtime, but this isn't what I am really after. I want to have a particular code (method, class, etc) to be present or absent (not just bypassed) in the project, depending on configuration.
This is how I implement that in Eclipse. I have a folder in an Eclipse project (named e.g. platform-specific), not included in BuildPath as well as several Ant scripts (make-google, make-amazon), that copy relevant files from platform-specific folder to src folder and delete irrelevant files from src folder.
Since Eclipse provides an Ant window to view all scripts, I can run a particular script and reconfigure the project to suit chosen configuration.
Is there a way to do that in Android Studio? I know that Gradle allows running and even importing an Ant script, but it isn't a convenient as with 'true' Ant, and I can't find a way to choose a script to run. Maybe Gradle provides its own way to do that?
For two flavours it will work, but if I have say 3 flavours, module 1 appears in flavours 1 and 2, module 2 in flavours 1 and 3, will it mean replicating those modules in each folder? So, every time I modify a code a such a module, I need to replicate the modification in another folder.
Not if you organize your code.
You appear to be using "modules" generically. Android Studio has a specific definition of that term (what Gradle refers to as sub-projects). And you can leverage those to help your cause.
Suppose that you create google, amazon, and yandex product flavors. Then:
Any code that is common to all three goes in src/main/.
Any code that is unique to a single flavor goes in that flavor's source set (e.g., src/yandex/).
Any code that is shared by two flavors goes into a library module that is added to the appropriate flavors using flavor-specific dependencies (e.g., yandexCompile and amazonCompile).
In all cases, there is one copy of your code. Whether it can go in the application module (e.g., app/) or goes into a library module depends on which flavors need that code. For a scenario like this, dependency injection will help you manage what code then gets wired together for each flavor.

How to use buildTypes, productFlavors, and sourceSet to batch build apks for different android channels

I'm new to unity3d , and I have to use it to batch build different apks for multiple android channels. I have to change project's package name, app name, icon, and meta-data values defined in AndroidManifest.xml, which is really boring me. What's worse is that I have to depend on different sdks that makes the project so heavy.
I know that android studio now is using gradle which can use buildTypes, productFlavors and sourceSet, manifestPlaceHolder, applicationId and some other configures to build different apks for multiple android channel.
I also find some plugins in github like https://github.com/zasadnyy/unity-gradle-plugin, but it can't use buildTypes or productFlavors features.
I wonder if it is possible to use gradle to achieve my goal? Any suggestions?
Not exactly what you're searching for, but you can also script the Unity build process to achieve the same thing.
You can do custom build with a combination of build pipeline and executing scripts from the command line.
Unfortunately, Unity's gradle support is substandard (as of Unity 2017 and possibly beyond). I would recommend using the Build Player Pipeline in combination with your own Post Process Build code to selectively enable or disable features and configure the output. You can configure the specific build using Custom Scripting Directives that can be modified in the Build Settings -> Player Settings panel when building the application.

ProGuard in AndroidStudio: How to get obfuscated library .aar files out of a multi-module project release build?

I have the following situation:
I have a project in Android Studio 1.4, which has 3 modules. The main module is the one for the app, the other 2 are library modules/subprojects. So when I build the whole project (using gradle), I get the app as .apk with all dependencies (the 2 library modules), and everything works as intended. I can also enable the minify option for ProGuard in the build.gradle file of the app module, which shrinks the app.
The 2 library modules additionally produce .aar files that I can use in other app projects (when running a release build for the whole project). Now I want to distribute the libraries, and I want to have them obfuscated (not shrinked) via ProGuard.
I want to have them automatically obfuscated during the release build of my app (preserving public APIs of course) without breaking the build process of my app because of missing classes etc. I tried to get this working using 'consumerProguardFiles' entries within the build.gradle files of the libraries, but with no success.
So how can I achieve that?

Categories

Resources