Multiple Build Flavors with and without Ads (new Google Developer Policy) - android

I have published an App with 2 Build Flavors: a "normal" version including ads and an ad-free-version.
In the Google Play Developer Console you now have to mark your App if it uses Ads. This is ok for the normal version but the ad-free-version uses the same dependencies as the pro version (especially google play services). So I get a warning when I set this version to ad-free because ad-libs were found.
Is it possible to change dependencies depending on gradle build flavor?
build.gradle:
android {
(...)
productFlavors {
lite {
signingConfig signingConfigs.Release
versionCode 14
versionName '1.1.5'
buildConfigField "boolean", "IS_PRO", "false"
}
pro {
applicationId 'com.example.exampleadfree'
signingConfig signingConfigs.Release
targetSdkVersion 21
versionCode 14
versionName '1.1.5'
buildConfigField "boolean", "IS_PRO", "true"
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:support-v4:21.0.3'
compile 'com.android.support:appcompat-v7:21.0.3'
compile 'com.android.support:cardview-v7:21.0.2'
compile 'com.google.android.gms:play-services:6.1.+'
compile project(':libraries:SharedItems')
compile 'com.android.support:recyclerview-v7:21.0.2'
}

You can change
compile 'com.google.android.gms:play-services:6.1.+'
to
liteCompile 'com.google.android.gms:play-services:6.1.+'
and that will include the play services lib with your lite version only.
But you are not done, because now the code in your app that creates the AdView and related classes from the play services library will not compile when you create the pro version.
My solution in a similar situation (with the billing library) was to move all the code that refers to the excluded library and related classes to a source file which is also only built with the lite flavor, and then provide a dummy implementation for the pro version that does not refer to the library.
For example, create two flavor-specific src directories with the same-named java class in each:
src/lite/java/com/example/myapp/util/AdUtil.java
src/pro/java/com/example/myapp/util/AdUtil.java
In the lite version of AdUtil, you can make calls to google play services and get an AdView to return:
View getAdView(...)
{
View adView = new AdView(...);
adView.setAdSize(...);
adView.setAdUnitId(...);
...
return adView;
}
And in the pro version of that class, you can just put a dummy implementation that does not refer to the play services lib:
View getAdView(...)
{
return null;
}
Then in your main app code, when you call AdUtil.getAdView(), you will get a View in the lite version which you can place on the screen. In the pro version you will get a null so you skip adding the view (but you are likely already checking if you are pro or lite before trying to create the adview in the first place).

When a project declares Product Flavors, these extends the main configuration.
From here. So Product Flavors effectively adds new configurations for every flavor your declare. In gradle it is possible to add dependencies that are specific to a configuration. For example,
dependencies {
<configname> <dependency>
}
If you want to list all the configurations that your project has added:
configurations.findAll().each{println "$it.name"}
In the case if your project you'll see configs that are named the same as your product flavors. So as #cwbowron commented, to add a compile-time dependency for flavor lite:
dependencies {
liteCompile <dependency>
}

From the Google Play Support Chat I was addressed to say "No" in Google Play Console, despite the detection. So there shouldn't be problem in including the Google libs.
On the other hand, Doug's answer is elegant.
Regards,

Related

Android Studio: No build variant found error

i am new to android development, i started developing from scratch on a project i bought online, following the documentation, i encountered a error saying No variants found for 'app'. Check build files to ensure at least one variant exists.
Here is the build.gradle code
apply plugin: 'com.android.application'
android {
compileSdkVersion 29
buildToolsVersion "29.0.1"
defaultConfig {
applicationId "com.app-10.app"
minSdkVersion 23
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.vectordrawable:vectordrawable:1.0.1'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
// Third Party Libraries
//Glide library for image fetching from the web
implementation 'com.github.bumptech.glide:glide:4.9.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'
//Material library for styling blocks
implementation 'com.google.android.material:material:1.0.0'
// Google Gson
implementation 'com.google.code.gson:gson:2.8.5'
// Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.6.1'
implementation 'com.squareup.retrofit2:converter-gson:2.6.1'
// Android-SpinKit
implementation 'com.github.ybq:Android-SpinKit:1.4.0'
implementation files('libs/YouTubeAndroidPlayerApi.jar')
// gotev/android-upload-service
implementation "net.gotev:uploadservice:3.5.2"
//A fast circular ImageView perfect for profile images
implementation 'de.hdodenhof:circleimageview:3.0.1'
implementation 'org.apache.commons:commons-io:1.3.2'
}
I have just solved the same issue like this:
Tools -> SDK Manager
Verify that the SDK platform package for Android 10.0 (the one with API level 29, like you defined in your gradle file) is checked.
If not, check it and apply changes. Accept the licence terms, install the package and then File -> Sync Project with Gradle Files (or open the project again)
In my case, it is because I add flavourDimensions and not adding it to any productFlavors
example from my case I have in my build.gradle in app level:
flavorDimensions "stage", "mode"
and my productFlavors:
productFlavors {
dev {
dimension "stage"
//noinspection DevModeObsolete
minSdkVersion 21
versionNameSuffix "-dev"
applicationIdSuffix '.dev'
resConfigs "en", "xxhdpi"
}
prod {
dimension "stage"
minSdkVersion 21
versionNameSuffix "-prod"
applicationIdSuffix '.prod'
}
}
As you can see here, I don't use flavorDimensions "mode" in any of my productFlavors's dimension. So, when I try to sync my gradle. It gives me that error.
So my solution here is to remove "mode" from flavorDimensions
go to the SDK manager (Ctrl+Shift+A then write SDK manager), install the android version of current project, in this case I installed all the available options starting from 5.0
I replaced from:
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
to my Android Studio v3.0.1 in my case:
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
but at the end i resolve it by
you need to detect and set your proper sdk
my sdk is 30.0.2 after i install 29.0.2 this error gone
Might help someone, in my case, I just needed to update Gradle.
A warning popped up on Android Studio, so I updated it, and then worked properly 🤷🏻‍♀️
For me the issue was that I hadn't opened the project at its root folder, I'd opened the "app" folder. Both folders had the gradle icon so it was an easy mistake to make after not having done any Android development for a while.
You may get the "No variants found" error in a project with multiple modules, when build types do not match between modules.
In my case, this happened when trying to add a macrobenchmark to an existing Android project.
Following the instructions in this document, I added a new module macrobenchmark to the project.
At some point, I misinterpreted the instructions: I added a new build type benchmark to the build.gradle of module app, but did not add the same build type to the build.gradle of module macrobenchmark.
From then on, any attempt to sync the project with the gradle files would fail with the following error message:
No variants found for 'macrobenchmark'. Check build files to ensure at least one variant exists.
The solution was simple (but not trivial): bring the build types back in sync. In my case, add the missing build type benchmark to the build.gradle of module macrobenchmark.
Try with
npm i cordova-android#10.1.1

Transitive dependencies for library build flavours on Android using api

I have a library that is built via Jitpack containing the following build flavors
productFlavors {
play {
dimension "default"
versionName versionString + "-play"
}
nonplay {
dimension "default"
versionName versionString + "-nonplay"
}
}
In the libraries dependencies section, I include a different dependency based on flavour like so
playApi "com.google.android.gms:play-services-location:$playServicesVersion"
nonplayApi "com.mapzen.android:lost:$lostVersion"
When I include this library in a new apps build.gradle, with, for example, nonplay
implementation ("com.xxx:someproject:1.0.0:nonplay#aar") {
transitive = true
}
I expect to see "com.mapzen.android:lost:$lostVersion" transitively included in my apps dependences list.
However I only see dependencies transitively included that do not use a flavour specific include i.e. api instead of nonplayApi. To avoid runtime crashes, I need to also add the nonplayApi dependencies in my app module.
How do I get my flavour specific nonplayApi or playApi dependencies to include transitively in my app module?

How to adapt Android App to use Retrofit without multiDex

I have an Android project that would benefit from using Retrofit. It's still in very early stages and there are less than a dozen function and class definitions. As soon as I add Retrofit to Gradle, I have a DexIndexOverflowException.
It seems way too early to add multiDex to the project, especially since it seems to be triggered by the addition of one dependency. Surely, I must be doing something wrong since there basic examples don't appear to require multiDex. What should I be doing differently?
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
defaultConfig {
applicationId "com.mydomain.myapp"
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0"
//multiDexEnabled true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:24.0.0-beta1'
compile 'com.android.support:support-v4:24.0.0-beta1'
compile 'com.google.android.gms:play-services:9.0.0'
compile 'com.squareup.retrofit2:retrofit:2.1.0'
//compile 'com.squareup.retrofit2:converter-gson:2.1.0'
//compile 'com.android.support:multidex:1.0.0'
}
The solution:
Remove the Google Play Services API dependency and only include the specific Google Play Services API dependencies as needed. I removed:
compile 'com.google.android.gms:play-services:9.0.0'
The reason:
The DEX file hold class definitions and adjunct data for your app including its dependencies. There need to be multiple DEX files if there are > 64K methods, including Android framework methods and library methods.
A brand new app starts out with a lot of methods.
I don't know how many methods are included in the Android framework, but it's a lot and I'm sure it's thousands to tens of thousands.
I don't know how many methods are included in Google Play Services, but rumor has it to be over 28k.
Between the Android framework and Google Play Services, there's probably not room for more than a few thousand more methods.
Retrofit is an abstraction layer built on top of OkHttp. OkHttp covers a lot of things including SPDY, HTTP/2, encryption, connection pooling, etc. and has dependencies on lots of Java frameworks. Any framework that covers something so extensively is going to have many methods. In my situation, it has enough to push past the 64K barrier. It's probably a reasonable amount.
Compile only necessary methods from Google Play Services This answer to a similar problem revealed that you can import only the APIs needed from Google Play Services very easily in the Gradle configuration. See Google's documentation for more information.
Okay, I had the same problem. If you want to use Retrofit with multiDex, and you want to keep Google Play Service in your project to use its APIs, follow the steps below:
1- Keep multiDexEnabled true on your Gradle
2- Add this dependency in your Gradle
compile 'com.android.support:multidex:1.0.1'
3- Create this class:
import android.app.Application;
import android.content.Context;
import android.support.multidex.MultiDex;
public class MultiDexApplication extends Application {
#Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}
4- On your AndroidManifest.xml add:
<application
android:name=".MultiDexApplication"
...
</application>
And now, try to recompile your project. I'm using version 8.3.0 of Google Play Service, and version 2.1.0 of Retrofit and Gson in my Gradle.

How to setup gradle in Android Studio to provide two flavors with different minimum SDK versions?

Problem: I want two product flavors, a FREE version with ads and a PRO version without ads.
Ads require Google Play with a min SDK of 9 so I set that for FREE but I want my pro version to have a min SDK of 8.
The build of the FREE version works but the build of PRO does not.
I am using (stable) Android Studio 1.1.0.
I setup a new project with a blank activity (Hello World example).
I then modified the build.gradle file (below) to include the two flavors and FREE-specific compile dependency and then modified the file structure to move the activity's java and layout xml files into the flavor structures. Thus, the project has the following file structure:
app\src\
free\
java\com\sample\adexample\MainActivity.java - This is Hello World.
res\layout\activity_main.xml - This is the Hello World layout.
res\values\strings.xml - Unique Hello World string for free version.
res\AndroidManifest.xml - This is a copy of the manifest in main.
main\
java\com\sample\adexample\ - empty
res\layout\ - empty
res\AndroidManifest.xml - This is the Hello World manifest.
pro\
java\com\sample\adexample\MainActivity.java - This is Hello World.
res\layout\activity_main.xml - This is the Hello World layout.
res\values\strings.xml - Unique Hello World string for free version.
res\AndroidManifest.xml - This is a copy of the manifest in main.
Here is my build.gradle file:
apply plugin: 'com.android.application'
android {
compileSdkVersion 21
buildToolsVersion "21.1.1"
defaultConfig {
applicationId "com.sample.adexample"
minSdkVersion 8
targetSdkVersion 21
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
productFlavors {
pro {
applicationId "com.sample.adexample.pro"
minSdkVersion 8
versionName "1.0-Pro"
}
free {
applicationId "com.sample.adexample.free"
minSdkVersion 9
versionName "1.0-Free"
dependencies {
compile 'com.google.android.gms:play-services:6.+'
}
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:21.0.3'
}
Building the freeDebug flavor works fine.
But I get the following error when building proDebug:
:app:processProDebugManifest
C:\Users\Jeff\AndroidStudioProjects\AdExample\app\src\main\AndroidManifest.xml:0:0 Error:
uses-sdk:minSdkVersion 8 cannot be smaller than version 9 declared in library C:\Users\Jeff\AndroidStudioProjects\AdExample\app\build\intermediates\exploded-aar\com.google.android.gms\play-services\6.5.87\AndroidManifest.xml
Suggestion: use tools:overrideLibrary="com.google.android.gms" to force usage
Is there a way to accomplish the requirements?
Thanks for your time.
Remove the dependencies closure from free. Move that compile 'com.google.android.gms:play-services:6.+' into your existing dependencies closure and make it be freeCompile rather than compile.
A prefix on the compile statement is how you make dependencies be tied to build variants rather than be used all the time the way compile is. So, a debugCompile would declare a dependency for only the debug build type, and freeCompile would declare a dependency for only the free product flavor.
AFAIK, this should work for multiple flavor dimensions, so if you had a dependency that was only relevant for the bird flavor (on one dimension) and the free flavor (on another dimension), you could use freeBirdCompile 'com.skynyrd.lynyrd:raised-lighter:1.0.0' to pull that in.

How do I match a Google Play Services revision with an install version?

Android SDK Manager notified me this morning that there was a new Google Play Services release to download: revision 18. So how do I find the corresponding long version number to put in my build.gradle file? All my test devices are running version 5.0.84, so I tried updating
compile 'com.google.android.gms:play-services:4.4.52'
to
compile 'com.google.android.gms:play-services:5.0.84'
But that resulted in an error:
Gradle 'MyApp' project refresh failed: Could not find com.google.android.gms:play-services:5.0.84. Required by: {my app} Gradle settings
I'm running Android Studio 0.5.2 and building for API19 (I haven't upgraded to Android L/API20 yet): maybe that's the issue? But in general, how do you match a revision number shown in SDK Manager (e.g. 18) with a version code for build.gradle (e.g. 5.0.84)?
Here's my full build.gradle in case it helps:
apply plugin: 'android'
android {
compileSdkVersion 19
buildToolsVersion "19.1.0"
defaultConfig {
minSdkVersion 14
targetSdkVersion 19
versionCode 1
versionName "1.0"
}
buildTypes {
release {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
// Avoid "Duplicate files copied in APK" errors when using Jackson
packagingOptions {
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
}
}
dependencies {
// Was "compile 'com.android.support:support-v4:+'" but this caused build errors when L SDK released
compile 'com.android.support:support-v4:19.1.0'
compile fileTree(dir: 'libs', include: ['*.jar'])
// Support for Google Cloud Messaging
// Was "compile 'com.android.support:appcompat-v7:+'" but this caused build errors when L SDK released
compile 'com.android.support:appcompat-v7:19.1.0'
compile 'com.google.android.gms:play-services:5.0.84'
// Jackson
compile 'com.fasterxml.jackson.core:jackson-core:2.3.3'
compile 'com.fasterxml.jackson.core:jackson-annotations:2.3.3'
compile 'com.fasterxml.jackson.core:jackson-databind:2.3.3'
}
OK, I haven't quite managed to find a mapping of one to the other, but I've managed the next best thing which is to see a list of Play Services long version numbers installed on my development machine.
For Windows, it's in [android-sdk]\extras\google\m2repository\com\google\android\gms\play-services
(where [android-sdk] is the path to your Android SDK folder).
On a Mac, it's inside the Android.app package: browse to sdk/extras/google/m2repository/com/google/android/gms/play-services
The latest version on my machine was 5.0.77 (not 5.0.84), and putting that in my build.gradle worked fine.
Here's the kind of thing you should see at that location:
What I did in my project was download google play service and open the project structure > dependencies tab and click on the plus button and choose google play service. I dont have to care about the version anymore

Categories

Resources