I have an application with three different flavours and two build types. The main module defines some common interfaces and each flavour implements them. The flavours correspond to stores : google, amazon and samsung. The app proposes some in-app purchases, which is specific to each flavour.
I implemented a few debug classes to ease the integration tests of the google the flavour. The debug classes implement the IInAppBillingService and an alternative to the purchase dialog. Now the problem is that some debug classes have dependencies on a flavour. I can't switch to another flavour without having compilation errors.
I would like to keep these test classes, as they are used in integration tests. Also, they should be kept away from the release build type, to avoid any debug/testing code appearing in the released version.
My question is : how to define classes with dependencies on a flavour, but that are not used during the building of the release version ?
As you probably know, you can put code and assets specific to a flavor in its own folder under src. For example you can have folders such as google, amazon, and samsung for each flavor. You can also create debug and release folders for classes and assets specific to each build type. This is useful if you have code only used for development but that should not go into the final release version.
You can take this a step further and create folders for any combination of build type and flavor, for example, googleDebug or amazonRelease.
For automated testing, create a test folder for unit tests which run locally on you development machine or an androidTest folder for instrumented tests run on a device or emulator. These can also be combined with build types and flavors, for example androidTestDebug, androidTestSamsung, or androidTestSamsungDebug.
All classes for testing should go under
Instead of having the classes that handles the billing logic in the flavour folder directly, I used another module specific to a flavour.
In the google billing module, I keep all the classes involved in the in-app purchases. Each module specific to a flavour is imported for the corresponding flavour. This way, I avoid mixing code specific to different flavours.
For example, in the build.gradle file I have :
googleCompile project(path: ':inappbilling_google')
In the inappbilling_google module, I have all the classes involved in in-app purchase through Google in-app billing. There is a debug folder to keep all the classes that should not appear during the release build process.
I was quite happy with this solution, as I keep clearly separate the code of the different flavours and build types... until I discovered that Gradle had some limitations. Indeed, the code present in the debug folder of modules is not included during the compilation. This is a known issue (limitation) of Gradle and the Android Gradle plugin.
However, the Google team and Gradle team have worked on this and have announced a solution to this, with the version 2.5 of the Android Gradle plugin.
In a near future, it will be possible to separate our code using the Android Gradle plugin only. Good news !
Related
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.
I am attempting to add Firebase Analytics and Crash Reporting to my app. I added the app in the Firebase Console. I made the updates to gradle and added the firebase core and crash reporting libs as dependencies.
My app is broken into multiple subprojects. Each has a slightly different package name:
app/org.mythtv.android.app
tv/org.mythtv.android.tv
presentation/org.mythtv.android.presentation
domain/org.mythtv.android.domain
data/org.mythtv.android.data
app and tv are two high-level subprojects that separate the app from the android tv version, presentation is common components for the 2 previous interface layers, domain encapsulates the interaction with common logic when dealing with data, and data is where the interaction with the backend occurs.
They all share a common package: org.mythtv.android
The application id is org.mythtv.android.
I created an app in the Firebase Console based on org.mythtv.android and added the google-services.json to the root of app and tv. I then wanted to track the crash reports in the other layers as well. Gradle fails to build at this point as it can't find packages org.mythtv.android.presentation and org.mythtv.android.data. These are both Android Library subprojects. data is just a java subproject.
Does the Firebase console need to have a separate app per package and each needs its own separate google-services.json? Doesn't this kind of defeat the purpose?
It sounds like you already got to the root of the problem, which is that you're only supposed to copy the google-service.json apply the google services plugin to application projects, not library projects. The plugin wants to make some changes that are only relevant for apps.
To help others with the same problem, the error message looks like this:
* What went wrong:
Execution failed for task ':mylibrary:processReleaseGoogleServices'.
> No matching client found for package name 'com.google.mylibrary'
Where "mylibrary" is the name of your own library project.
To be honest, I think the plugin should detect if it's being applied to a library project and fail instead with a better message, so I'll see if we can get that remedied.
As an aside, you may want to consider merging your two app projects into a single app project with two different flavors, one for app and the other for tv. They can then share everything by default, but have separate configurations to target different API levels and even have different sets of resources, assets, manifest items, and even independent code, if you're careful. This should simplify the structure of your project. You can read build variants here:
http://tools.android.com/tech-docs/new-build-system/user-guide
Firebase Analytics reports based on the application package name. The package name is not related to the packages you use for your Java classes. The two are independent. The application package name is used by Android to identify your app (for update for example) and can not be changed once you release your app. If you are using gradle you can find it in your app/build.gradle as applicationId value or in your AndroidManifest.xml package attribute.
I am using various services in my android app for which I need userIDs and keys. Now I can store all of the keys in my string.xml file. However, since I have two different environments (production and debug) in server, i need to figure out a way of maintaining two different sets of keys based on environment.
Is there a standard way of maintaining keys for android app ?
You are looking for gradle feature called build variants. This will let you have i.e. different string.xml for release build and different for debug ones. See docs:
https://developer.android.com/tools/building/configuring-gradle.html
Build variants are specific builds that you can produce from Gradle,
based around shared core source code. While a standard app may have a
debug and release build type, you can expand on this by adding flavor
dimensions.
Read official guideline about Configuring Gradle Builds
Using Gradle Build Variants
Is it possible to have an Application subclass that's used only for tests when building with gradle? I've done something like this in the past before the gradle build system, but I can't find a way to do so now. The problem seems to be that it's impossible to customize the AndroidManifest.xml used for the instrumentation test APK.
You can create build variants which would at let you have a different version of the Application class and let you override the manifest. You could then test only that specific variant. http://tulipemoutarde.be/2013/10/06/gradle-build-variants-for-your-android-project.html
http://tools.android.com/tech-docs/new-build-system/user-guide
"For instance, if the flavors are used to generate a ads-based app and a paid app, one of the flavors could have a dependency on an Ads SDK, while the other does not.
dependencies {
flavor1Compile "..."
}
In this particular case, the file src/flavor1/AndroidManifest.xml would probably need to include the internet permission."
I worked with iPhone Xcode Traget to create multiple iPhone apps with single code base. My question, is it possible to create multiple targets for Android project. If yes, is it possible with Eclipse?
Edit:
Xcode Target: A single Projects can contain one or more targets, each of which produces one product (App). This has always only one Project in which we can select the specific target and run desired app
iPhone have only one Project for many products (App1, App2, App3 etc), Now can I have same as this, one Android Project and multiple products (App1, App2, App3 etc)
Thanks in advance
A bit late, but for those who still looking for solution:
Gradle Build System uses a Build Variant and combination of product flavors to generate different apps with shared/common code base and resources.
As per Android Developer Reference Site:
The build system uses product flavors to create different product versions of your app. Each product version of your app can have different features or device requirements. The build system also uses build types to apply different build and packaging settings to each product version. Each product flavor and build type combination forms a build variant. The build system generates a different APK for each build variant of your app.
Now one can have two or more product flavors e.g (paid flavor, free/demo flavor) etc for one single project with same code base.
For more information See Build Variants & Product Flavors Doc
After a wide research I realized Android Library Project will provide solution for my requirement
An Android library project is a development project that holds
shared Android source code and resources. Other Android application
projects can reference the library project and, at build time, include
its compiled sources in their .apk files. Multiple application
projects can reference the same library project and any single
application project can reference multiple library projects.
Note: You need SDK Tools r14 or newer to use the new library project
feature that generates each library project into its own JAR file. You
can download the tools and platforms using the Android SDK and AVD
Manager, as described in Adding SDK Components.
• If you have source code and resources that are common to multiple
Android projects, you can move them to a library project so that it is
easier to maintain across applications and versions. Here are some
common scenarios in which you could make use of library projects:
• If you are developing multiple related applications that use some of
the same components, you move the redundant components out of their
respective application projects and create a single, reuseable set of
the same components in a library project. If you are creating an
application that exists in both free and paid versions. You move the
part of the application that is common to both versions into a library
project. The two dependent projects, with their different package
names, will reference the library project and provide only the
difference between the two application versions.
There is only one build target in android in a single project. Backword compatibility is controlled at install time using minSdkVersion, targetSdkVersion and maxSdkVersion in the manifest file
http://developer.android.com/guide/topics/manifest/uses-sdk-element.html
Also android market make sure that if your app has native code and is built for ARM architecture it is not visible on a x86 device
You can control what version someone has installed and starting one activity or another depending on that. You can use something like this:
private static boolean version= android.os.Build.VERSION.SDK_INT>=android.os.Build.VERSION_CODES.HONEYCOMB;
And then do something like:
public void onCreate(Bundle savedInstanceState){
Intent startActivity =null;
if(version)
startActivityIntent = new Intent( this, newVersionActivity.class );
else
startActivityIntent = new Intent( this, oldVersionActivity.class );
finish();}
This example is from a video of the Google I/O (min 5~): http://www.google.com/events/io/2011/sessions/android-protips-advanced-topics-for-expert-android-app-developers.html.
So you are supposed to specify the minSdkVersion and the maxSdkVersion and then control what which activity to start.